# File lib/rbreadline.rb, line 2676
  def update_line(old, ostart, new, current_line, omax, nmax, inv_botlin)
    # If we're at the right edge of a terminal that supports xn, we're
    #   ready to wrap around, so do so.  This fixes problems with knowing
    #   the exact cursor position and cut-and-paste with certain terminal
    #   emulators.  In this calculation, TEMP is the physical screen
    #   position of the cursor.
    if @encoding == 'X'
      old.force_encoding('ASCII-8BIT')
      new.force_encoding('ASCII-8BIT')
    end

    if !@rl_byte_oriented
      temp = @_rl_last_c_pos
    else
      temp = @_rl_last_c_pos - w_offset(@_rl_last_v_pos, @visible_wrap_offset)
    end
    if (temp == @_rl_screenwidth && @_rl_term_autowrap && !@_rl_horizontal_scroll_mode &&
        @_rl_last_v_pos == current_line - 1)

      if (!@rl_byte_oriented)
        # This fixes only double-column characters, but if the wrapped
        #   character comsumes more than three columns, spaces will be
        #   inserted in the string buffer.
        if (@_rl_wrapped_line[current_line] > 0)
          _rl_clear_to_eol(@_rl_wrapped_line[current_line])
        end

        if new[0,1] != 0.chr
          case @encoding
          when 'E'
            wc = new.scan(/./me)[0]
            ret = wc.length
            tempwidth = wc.length
          when 'S'
            wc = new.scan(/./ms)[0]
            ret = wc.length
            tempwidth = wc.length
          when 'U'
            wc = new.scan(/./mu)[0]
            ret = wc.length
            tempwidth = wc.unpack('U').first >= 0x1000 ? 2 : 1
          when 'X'
            wc = new[0..-1].force_encoding(@encoding_name)[0]
            ret = wc.bytesize
            tempwidth = wc.ord >= 0x1000 ? 2 : 1
          else
            ret = 1
            tempwidth = 1
          end
        else
          tempwidth = 0
        end

        if (tempwidth > 0)
          bytes = ret
          @rl_outstream.write(new[0,bytes])
          @_rl_last_c_pos = tempwidth
          @_rl_last_v_pos+=1

          if old[ostart,1] != 0.chr
            case @encoding
            when 'E'
              wc = old[ostart..-1].scan(/./me)[0]
              ret = wc.length
            when 'S'
              wc = old[ostart..-1].scan(/./ms)[0]
              ret = wc.length
            when 'U'
              wc = old[ostart..-1].scan(/./mu)[0]
              ret = wc.length
            when 'X'
              wc = old[ostart..-1].force_encoding(@encoding_name)[0]
              ret = wc.bytesize
            end
          else
            ret = 0
          end
          if (ret != 0 && bytes != 0)
            if ret != bytes
              len = old[ostart..-1].index(0.chr,ret)
              old[ostart+bytes,len-ret] = old[ostart+ret,len-ret]
            end
            old[ostart,bytes] = new[0,bytes]
          end
        else
          @rl_outstream.write(' ')
          @_rl_last_c_pos = 1
          @_rl_last_v_pos+=1
          if (old[ostart,1] != 0.chr && new[0,1] != 0.chr)
            old[ostart,1] = new[0,1]
          end
        end

      else
        if (new[0,1] != 0.chr)
          @rl_outstream.write(new[0,1])
        else
          @rl_outstream.write(' ')
        end
        @_rl_last_c_pos = 1
        @_rl_last_v_pos+=1
        if (old[ostart,1] != 0.chr && new[0,1] != 0.chr)
          old[ostart,1] = new[0,1]
        end
      end
    end

    # Find first difference.
    if (!@rl_byte_oriented)
      # See if the old line is a subset of the new line, so that the
      # only change is adding characters.
      temp = (omax < nmax) ? omax : nmax
      if old[ostart,temp]==new[0,temp]
        ofd = temp
        nfd = temp
      else
        if (omax == nmax && new[0,omax]==old[ostart,omax])
          ofd = omax
          nfd = nmax
        else
          new_offset = 0
          old_offset = ostart
          ofd = 0
          nfd = 0
          while(ofd < omax && old[ostart+ofd,1] != 0.chr &&
                _rl_compare_chars(old, old_offset, new, new_offset))

            old_offset = _rl_find_next_mbchar(old, old_offset, 1, MB_FIND_ANY)
            new_offset = _rl_find_next_mbchar(new, new_offset, 1, MB_FIND_ANY)
            ofd = old_offset - ostart
            nfd = new_offset
          end
        end
      end
    else
      ofd = 0
      nfd = 0
      while(ofd < omax && old[ostart+ofd,1] != 0.chr && old[ostart+ofd,1] == new[nfd,1])
        ofd += 1
        nfd += 1
      end
    end


    # Move to the end of the screen line.  ND and OD are used to keep track
    #   of the distance between ne and new and oe and old, respectively, to
    #   move a subtraction out of each loop.
    oe = old.index(0.chr,ostart+ofd) - ostart
    if oe.nil? || oe>omax
      oe = omax
    end

    ne = new.index(0.chr,nfd)
    if ne.nil? || ne>omax
      ne = nmax
    end

    # If no difference, continue to next line.
    if (ofd == oe && nfd == ne)
      return
    end


    wsatend = true       # flag for trailing whitespace

    if (!@rl_byte_oriented)

      ols = _rl_find_prev_mbchar(old, ostart+oe, MB_FIND_ANY) - ostart
      nls = _rl_find_prev_mbchar(new, ne, MB_FIND_ANY)
      while ((ols > ofd) && (nls > nfd))

        if (!_rl_compare_chars(old, ostart+ols, new, nls))
          break
        end
        if (old[ostart+ols,1] == " ")
          wsatend = false
        end

        ols = _rl_find_prev_mbchar(old, ols+ostart, MB_FIND_ANY) - ostart
        nls = _rl_find_prev_mbchar(new, nls, MB_FIND_ANY)
      end
    else
      ols = oe - 1         # find last same
      nls = ne - 1
      while ((ols > ofd) && (nls > nfd) && old[ostart+ols,1] == new[nls,1])
        if (old[ostart+ols,1] != " ")
          wsatend = false
        end
        ols-=1
        nls-=1
      end
    end

    if (wsatend)
      ols = oe
      nls = ne
    elsif (!_rl_compare_chars(old, ostart+ols, new, nls))
      if (old[ostart+ols,1] != 0.chr)         # don't step past the NUL
        if !@rl_byte_oriented
          ols = _rl_find_next_mbchar(old, ostart+ols, 1, MB_FIND_ANY) - ostart
        else
          ols+=1
        end
      end
      if (new[nls,1] != 0.chr )
        if !@rl_byte_oriented
          nls = _rl_find_next_mbchar(new, nls, 1, MB_FIND_ANY)
        else
          nls+=1
        end
      end
    end

    # count of invisible characters in the current invisible line.
    current_invis_chars = w_offset(current_line, @wrap_offset)
    if (@_rl_last_v_pos != current_line)
      _rl_move_vert(current_line)
      if (@rl_byte_oriented && current_line == 0 && @visible_wrap_offset!=0)
        @_rl_last_c_pos += @visible_wrap_offset
      end
    end

    # If this is the first line and there are invisible characters in the
    #   prompt string, and the prompt string has not changed, and the current
    #   cursor position is before the last invisible character in the prompt,
    #   and the index of the character to move to is past the end of the prompt
    #   string, then redraw the entire prompt string.  We can only do this
    #   reliably if the terminal supports a `cr' capability.

    #  This is not an efficiency hack -- there is a problem with redrawing
    #  portions of the prompt string if they contain terminal escape
    #  sequences (like drawing the `unbold' sequence without a corresponding
    #  `bold') that manifests itself on certain terminals.

    lendiff = @local_prompt_len

    if (current_line == 0 && !@_rl_horizontal_scroll_mode &&
        @_rl_term_cr && lendiff > @prompt_visible_length && @_rl_last_c_pos > 0 &&
        ofd >= lendiff && @_rl_last_c_pos < prompt_ending_index())
      @rl_outstream.write(@_rl_term_cr)
      _rl_output_some_chars(@local_prompt,0,lendiff)
      if !@rl_byte_oriented
        # We take wrap_offset into account here so we can pass correct
        #   information to _rl_move_cursor_relative.
        @_rl_last_c_pos = _rl_col_width(@local_prompt, 0, lendiff) - @wrap_offset
        @cpos_adjusted = true
      else
        @_rl_last_c_pos = lendiff
      end
    end

    o_cpos = @_rl_last_c_pos

    # When this function returns, _rl_last_c_pos is correct, and an absolute
    #   cursor postion in multibyte mode, but a buffer index when not in a
    #   multibyte locale.
    _rl_move_cursor_relative(ofd, old, ostart)

    # We need to indicate that the cursor position is correct in the presence
    # of invisible characters in the prompt string.  Let's see if setting this
    # when we make sure we're at the end of the drawn prompt string works.
    if (current_line == 0 && !@rl_byte_oriented &&
        (@_rl_last_c_pos > 0 || o_cpos > 0) &&
        @_rl_last_c_pos == @prompt_physical_chars)
      @cpos_adjusted = true
    end

    # if (len (new) > len (old))
    #   lendiff == difference in buffer
    #   col_lendiff == difference on screen
    #   When not using multibyte characters, these are equal
    lendiff = (nls - nfd) - (ols - ofd)
    if !@rl_byte_oriented
      col_lendiff = _rl_col_width(new, nfd, nls) - _rl_col_width(old, ostart+ofd, ostart+ols)
    else
      col_lendiff = lendiff
    end

    # If we are changing the number of invisible characters in a line, and
    #   the spot of first difference is before the end of the invisible chars,
    #   lendiff needs to be adjusted.
    if (current_line == 0 && !@_rl_horizontal_scroll_mode &&
        current_invis_chars != @visible_wrap_offset)
      if !@rl_byte_oriented
        lendiff += @visible_wrap_offset - current_invis_chars
        col_lendiff += @visible_wrap_offset - current_invis_chars
      else
        lendiff += @visible_wrap_offset - current_invis_chars
        col_lendiff = lendiff
      end
    end

    # Insert (diff (len (old), len (new)) ch.
    temp = ne - nfd
    if !@rl_byte_oriented
      col_temp = _rl_col_width(new,nfd,ne)
    else
      col_temp = temp
    end
    if (col_lendiff > 0) # XXX - was lendiff

      # Non-zero if we're increasing the number of lines.
      gl = current_line >= @_rl_vis_botlin && inv_botlin > @_rl_vis_botlin

      # If col_lendiff is > 0, implying that the new string takes up more
      # screen real estate than the old, but lendiff is < 0, meaning that it
      # takes fewer bytes, we need to just output the characters starting from
      # the first difference.  These will overwrite what is on the display, so
      # there's no reason to do a smart update.  This can really only happen in
      # a multibyte environment.
      if lendiff < 0
        _rl_output_some_chars(new, nfd, temp)
        @_rl_last_c_pos += _rl_col_width(new, nfd, nfd+temp)

        # If nfd begins before any invisible characters in the prompt, adjust
        # _rl_last_c_pos to account for wrap_offset and set cpos_adjusted to
        # let the caller know.
        if current_line == 0 && @wrap_offset && nfd <= @prompt_last_invisible
          @_rl_last_c_pos -= @wrap_offset
          @cpos_adjusted = true
        end
        return
      # Sometimes it is cheaper to print the characters rather than
      # use the terminal's capabilities.  If we're growing the number
      # of lines, make sure we actually cause the new line to wrap
      # around on auto-wrapping terminals.
      elsif (@_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || @_rl_term_IC) && (!@_rl_term_autowrap || !gl))

        # If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and
        #   _rl_horizontal_scroll_mode == 1, inserting the characters with
        #   _rl_term_IC or _rl_term_ic will screw up the screen because of the
        #   invisible characters.  We need to just draw them.
        if (old[ostart+ols,1] != 0.chr && (!@_rl_horizontal_scroll_mode || @_rl_last_c_pos > 0 ||
                                           lendiff <= @prompt_visible_length || current_invis_chars==0))

          insert_some_chars(new[nfd..-1], lendiff, col_lendiff)
          @_rl_last_c_pos += col_lendiff
        elsif ((@rl_byte_oriented) && old[ostart+ols,1] == 0.chr && lendiff > 0)
          # At the end of a line the characters do not have to
          # be "inserted".  They can just be placed on the screen.
          # However, this screws up the rest of this block, which
          # assumes you've done the insert because you can.
          _rl_output_some_chars(new,nfd, lendiff)
          @_rl_last_c_pos += col_lendiff
        else
          _rl_output_some_chars(new,nfd, temp)
          @_rl_last_c_pos += col_temp
          # If nfd begins before any invisible characters in the prompt, adjust
          # _rl_last_c_pos to account for wrap_offset and set cpos_adjusted to
          # let the caller know.
          if current_line == 0 && @wrap_offset && nfd <= @prompt_last_invisible
            @_rl_last_c_pos -= @wrap_offset
            @cpos_adjusted = true
          end
          return
        end
        # Copy (new) chars to screen from first diff to last match.
        temp = nls - nfd
        if ((temp - lendiff) > 0)
          _rl_output_some_chars(new,(nfd + lendiff),temp - lendiff)
          # XXX -- this bears closer inspection.  Fixes a redisplay bug
          # reported against bash-3.0-alpha by Andreas Schwab involving
          # multibyte characters and prompt strings with invisible
          # characters, but was previously disabled.
          @_rl_last_c_pos += _rl_col_width(new,nfd+lendiff, nfd+lendiff+temp-col_lendiff)
        end
      else
        # cannot insert chars, write to EOL
        _rl_output_some_chars(new,nfd, temp)
        @_rl_last_c_pos += col_temp
        # If we're in a multibyte locale and were before the last invisible
        #   char in the current line (which implies we just output some invisible
        #   characters) we need to adjust _rl_last_c_pos, since it represents
        #   a physical character position.
      end
    else           # Delete characters from line.
      # If possible and inexpensive to use terminal deletion, then do so.
      if (@_rl_term_dc && (2 * col_temp) >= -col_lendiff)

        # If all we're doing is erasing the invisible characters in the
        #   prompt string, don't bother.  It screws up the assumptions
        #   about what's on the screen.
        if (@_rl_horizontal_scroll_mode && @_rl_last_c_pos == 0 &&
            -lendiff == @visible_wrap_offset)
          col_lendiff = 0
        end

        if (col_lendiff!=0)
          delete_chars(-col_lendiff) # delete (diff) characters
        end

        # Copy (new) chars to screen from first diff to last match
        temp = nls - nfd
        if (temp > 0)
          # If nfd begins at the prompt, or before the invisible characters in
          # the prompt, we need to adjust _rl_last_c_pos in a multibyte locale
          # to account for the wrap offset and set cpos_adjusted accordingly.
          _rl_output_some_chars(new,nfd, temp)
          if !@rl_byte_oriented
            @_rl_last_c_pos += _rl_col_width(new,nfd,nfd+temp)
            if current_line == 0 && @wrap_offset && nfd <= @prompt_last_invisible
              @_rl_last_c_pos -= @wrap_offset
              @cpos_adjusted = true
            end
          else
            @_rl_last_c_pos += temp
          end
        end

        # Otherwise, print over the existing material.
      else
        if (temp > 0)
          # If nfd begins at the prompt, or before the invisible characters in
          # the prompt, we need to adjust _rl_last_c_pos in a multibyte locale
          # to account for the wrap offset and set cpos_adjusted accordingly.
          _rl_output_some_chars(new,nfd, temp)
          @_rl_last_c_pos += col_temp      # XXX
          if !@rl_byte_oriented
            if current_line == 0 && @wrap_offset && nfd <= @prompt_last_invisible
              @_rl_last_c_pos -= @wrap_offset
              @cpos_adjusted = true
            end
          end
        end

        lendiff = (oe) - (ne)
        if !@rl_byte_oriented
          col_lendiff = _rl_col_width(old, ostart, ostart+oe) - _rl_col_width(new, 0, ne)
        else
          col_lendiff = lendiff
        end

        if (col_lendiff!=0)
          if (@_rl_term_autowrap && current_line < inv_botlin)
            space_to_eol(col_lendiff)
          else
            _rl_clear_to_eol(col_lendiff)
          end
        end
      end
    end
  end