code: def _output_screen_diff(
      app: Application[Any],
      output: Output,
      screen: Screen,
      current_pos: Point,
      color_depth: ColorDepth,
      previous_screen: Screen | None,
      last_style: str | None,
      is_done: bool,  # XXX: drop is_done
      full_screen: bool,
      attrs_for_style_string: _StyleStringToAttrsCache,
      style_string_has_style: _StyleStringHasStyleCache,
      size: Size,
      previous_width: int,
  ) -> tuple[Point, str | None]:
      """
      Render the diff between this screen and the previous screen.
  
      This takes two `Screen` instances. The one that represents the output like
      it was during the last rendering and one that represents the current
      output raster. Looking at these two `Screen` instances, this function will
      render the difference by calling the appropriate methods of the `Output`
      object that only paint the changes to the terminal.
  
      This is some performance-critical code which is heavily optimized.
      Don't change things without profiling first.
  
      :param current_pos: Current cursor position.
      :param last_style: The style string, used for drawing the last drawn
          character.  (Color/attributes.)
      :param attrs_for_style_string: :class:`._StyleStringToAttrsCache` instance.
      :param width: The width of the terminal.
      :param previous_width: The width of the terminal during the last rendering.
      """
      width, height = size.columns, size.rows
  
      #: Variable for capturing the output.
      write = output.write
      write_raw = output.write_raw
  
      # Create locals for the most used output methods.
      # (Save expensive attribute lookups.)
      _output_set_attributes = output.set_attributes
      _output_reset_attributes = output.reset_attributes
      _output_cursor_forward = output.cursor_forward
      _output_cursor_up = output.cursor_up
      _output_cursor_backward = output.cursor_backward
  
      # Hide cursor before rendering. (Avoid flickering.)
      output.hide_cursor()
  
      def reset_attributes() -> None:
          "Wrapper around Output.reset_attributes."
          nonlocal last_style
          _output_reset_attributes()
          last_style = (
              None  # Forget last char after resetting attributes.
          )
  
      def move_cursor(new: Point) -> Point:
          "Move cursor to this `new` point. Returns the given Point."
          current_x, current_y = current_pos.x, current_pos.y
  
          if new.y > current_y:
              # Use newlines instead of CURSOR_DOWN, because this might add new lines.
              # CURSOR_DOWN will never create new lines at the bottom.
              # Also reset attributes, otherwise the newline could draw a
              # background color.
              reset_attributes()
              write("\r\n" * (new.y - current_y))
              current_x = 0
              _output_cursor_forward(new.x)
              return new
          elif new.y < current_y:
              _output_cursor_up(current_y - new.y)
  
          if current_x >= width - 1:
              write("\r")
              _output_cursor_forward(new.x)
          elif new.x < current_x or current_x >= width - 1:
              _output_cursor_backward(current_x - new.x)
          elif new.x > current_x:
              _output_cursor_forward(new.x - current_x)
  
          return new
  
      def output_char(char: Char) -> None:
          """
          Write the output of this character.
          """
          nonlocal last_style
  
          # If the last printed character has the same style, don't output the
          # style again.
          if last_style == char.style:
              write(char.char)
          else:
              # Look up `Attr` for this style string. Only set attributes if different.
              # (Two style strings can still have the same formatting.)
              # Note that an empty style string can have formatting that needs to
              # be applied, because of style transformations.
              new_attrs = attrs_for_style_string[char.style]
              if (
                  not last_style
                  or new_attrs != attrs_for_style_string[last_style]
              ):
                  _output_set_attributes(new_attrs, color_depth)
  
              write(char.char)
              last_style = char.style
  
      def get_max_column_index(row: dict[int, Char]) -> int:
          """
          Return max used column index, ignoring whitespace (without style) at
          the end of the line. This is important for people that copy/paste
          terminal output.
  
          There are two reasons we are sometimes seeing whitespace at the end:
          - `BufferControl` adds a trailing space to each line, because it's a
            possible cursor position, so that the line wrapping won't change if
            the cursor position moves around.
          - The `Window` adds a style class to the current line for highlighting
            (cursor-line).
          """
          numbers = (
              index
              for index, cell in row.items()
              if cell.char != " " or style_string_has_style[cell.style]
          )
          return max(numbers, default=0)
  
      # Render for the first time: reset styling.
      if not previous_screen:
          reset_attributes()
  
      # Disable autowrap. (When entering a the alternate screen, or anytime when
      # we have a prompt. - In the case of a REPL, like IPython, people can have
      # background threads, and it's hard for debugging if their output is not
      # wrapped.)
      if not previous_screen or not full_screen:
          output.disable_autowrap()
  
      # When the previous screen has a different size, redraw everything anyway.
      # Also when we are done. (We might take up less rows, so clearing is important.)
      if (
          is_done or not previous_screen or previous_width != width
      ):  # XXX: also consider height??
          current_pos = move_cursor(Point(x=0, y=0))
          reset_attributes()
          output.erase_down()
  
          previous_screen = Screen()
  
      # Get height of the screen.
      # (height changes as we loop over data_buffer, so remember the current value.)
      # (Also make sure to clip the height to the size of the output.)
      current_height = min(screen.height, height)
  
      # Loop over the rows.
      row_count = min(
          max(screen.height, previous_screen.height), height
      )
  
      for y in range(row_count):
          new_row = screen.data_buffer[y]
          previous_row = previous_screen.data_buffer[y]
          zero_width_escapes_row = screen.zero_width_escapes[y]
  
          new_max_line_len = min(
              width - 1, get_max_column_index(new_row)
          )
          previous_max_line_len = min(
              width - 1, get_max_column_index(previous_row)
          )
  
          # Loop over the columns.
          c = 0  # Column counter.
          while c <= new_max_line_len:
              new_char = new_row[c]
              old_char = previous_row[c]
              char_width = new_char.width or 1
  
              # When the old and new character at this position are different,
              # draw the output. (Because of the performance, we don't call
              # `Char.__ne__`, but inline the same expression.)
              if (
                  new_char.char != old_char.char
                  or new_char.style != old_char.style
              ):
                  current_pos = move_cursor(Point(x=c, y=y))
  
                  # Send injected escape sequences to output.
                  if c in zero_width_escapes_row:
                      write_raw(zero_width_escapes_row[c])
  
                  output_char(new_char)
                  current_pos = Point(
                      x=current_pos.x + char_width, y=current_pos.y
                  )
  
              c += char_width
  
          # If the new line is shorter, trim it.
          if (
              previous_screen
              and new_max_line_len < previous_max_line_len
          ):
              current_pos = move_cursor(
                  Point(x=new_max_line_len + 1, y=y)
              )
              reset_attributes()
              output.erase_end_of_line()
  
      # Correctly reserve vertical space as required by the layout.
      # When this is a new screen (drawn for the first time), or for some reason
      # higher than the previous one. Move the cursor once to the bottom of the
      # output. That way, we're sure that the terminal scrolls up, even when the
      # lower lines of the canvas just contain whitespace.
  
      # The most obvious reason that we actually want this behavior is the avoid
      # the artifact of the input scrolling when the completion menu is shown.
      # (If the scrolling is actually wanted, the layout can still be build in a
      # way to behave that way by setting a dynamic height.)
      if current_height > previous_screen.height:
          current_pos = move_cursor(Point(x=0, y=current_height - 1))
  
      # Move cursor:
      if is_done:
          current_pos = move_cursor(Point(x=0, y=current_height))
          output.erase_down()
      else:
          current_pos = move_cursor(
              screen.get_cursor_position(app.layout.current_window)
          )
  
      if is_done or not full_screen:
          output.enable_autowrap()
  
      # Always reset the color attributes. This is important because a background
      # thread could print data to stdout and we want that to be displayed in the
      # default colors. (Also, if a background color has been set, many terminals
      # give weird artifacts on resize events.)
      reset_attributes()
  
      if screen.show_cursor or is_done:
          output.show_cursor()
  
      return current_pos, last_style
  
imports: from __future__ import annotations
  from asyncio import FIRST_COMPLETED, Future, ensure_future, sleep, wait
  from collections import deque
  from enum import Enum
  from typing import TYPE_CHECKING, Any, Callable, Dict, Hashable
  from prompt_toolkit.application.current import get_app
  from prompt_toolkit.cursor_shapes import CursorShape
  from prompt_toolkit.data_structures import Point, Size
  from prompt_toolkit.filters import FilterOrBool, to_filter
  from prompt_toolkit.formatted_text import AnyFormattedText, to_formatted_text
  from prompt_toolkit.layout.mouse_handlers import MouseHandlers
  from prompt_toolkit.layout.screen import Char, Screen, WritePosition
  from prompt_toolkit.output import ColorDepth, Output
  from prompt_toolkit.styles import Attrs, BaseStyle, DummyStyleTransformation, StyleTransformation
label_desc: Use image node_id 1 for calling a global function with example usage: _output_screen_diff(app, output, screen, current_pos, color_depth, previous_screen, last_style, is_done, full_screen, attrs_for_style_string, style_string_has_style, size, previous_width) and returns: current_pos,  last_style, new, max, new