# File lib/rbreadline.rb, line 3120
  def rl_redisplay()
    return if !@readline_echoing_p

    _rl_wrapped_multicolumn = 0

    @rl_display_prompt ||= ""

    if (@invisible_line.nil? || @vis_lbreaks.nil?)
      init_line_structures(0)
      rl_on_new_line()
    end

    # Draw the line into the buffer.
    @cpos_buffer_position = -1

    line = @invisible_line
    out = inv_botlin = 0

    # Mark the line as modified or not.  We only do this for history
    #   lines.
    modmark = 0
    if (@_rl_mark_modified_lines && current_history() && @rl_undo_list)
      line[out,1] = '*'
      out += 1
      line[out,1] = 0.chr
      modmark = 1
    end

    # If someone thought that the redisplay was handled, but the currently
    #   visible line has a different modification state than the one about
    #   to become visible, then correct the caller's misconception.
    if (@visible_line[0,1] != @invisible_line[0,1])
      @rl_display_fixed = false
    end

    # If the prompt to be displayed is the `primary' readline prompt (the
    #   one passed to readline()), use the values we have already expanded.
    #   If not, use what's already in rl_display_prompt.  WRAP_OFFSET is the
    #   number of non-visible characters in the prompt string.
    if (@rl_display_prompt == @rl_prompt || @local_prompt)

      if (@local_prompt_prefix && @forced_display)
        _rl_output_some_chars(@local_prompt_prefix,0,@local_prompt_prefix.length)
      end
      if (@local_prompt_len > 0)

        temp = @local_prompt_len + out + 2
        if (temp >= @line_size)
          @line_size = (temp + 1024) - (temp % 1024)
          if @visible_line.length >= @line_size
            @visible_line = @visible_line[0,@line_size]
          else
            @visible_line += 0.chr * (@line_size-@visible_line.length)
          end

          if @invisible_line.length >= @line_size
            @invisible_line = @invisible_line[0,@line_size]
          else
            @invisible_line += 0.chr * (@line_size-@invisible_line.length)
          end
          if @encoding=='X'
            @visible_line.force_encoding('ASCII-8BIT')
            @invisible_line.force_encoding('ASCII-8BIT')
          end
          line = @invisible_line
        end
        line[out,@local_prompt_len] = @local_prompt
        out += @local_prompt_len
      end
      line[out,1] = 0.chr
      @wrap_offset = @local_prompt_len - @prompt_visible_length
    else
      prompt_this_line = @rl_display_prompt.rindex("\n")
      if prompt_this_line.nil?
        prompt_this_line = 0
      else
        prompt_this_line+=1

        pmtlen = prompt_this_line # temp var
        if (@forced_display)
          _rl_output_some_chars(@rl_display_prompt,0,pmtlen)
          # Make sure we are at column zero even after a newline,
          #regardless of the state of terminal output processing.
          if (pmtlen < 2 || @rl_display_prompt[prompt_this_line-2,1] != "\r")
            cr()
          end
        end
      end

      @prompt_physical_chars = pmtlen = @rl_display_prompt.length - prompt_this_line
      temp = pmtlen + out + 2
      if (temp >= @line_size)
        @line_size = (temp + 1024) - (temp % 1024)
        if @visible_line.length >= @line_size
          @visible_line = @visible_line[0,@line_size]
        else
          @visible_line += 0.chr * (@line_size-@visible_line.length)
        end

        if @invisible_line.length >= @line_size
          @invisible_line = @invisible_line[0,@line_size]
        else
          @invisible_line += 0.chr * (@line_size-@invisible_line.length)
        end
        if @encoding=='X'
          @visible_line.force_encoding('ASCII-8BIT')
          @invisible_line.force_encoding('ASCII-8BIT')
        end

        line = @invisible_line
      end
      line[out,pmtlen] = @rl_display_prompt[prompt_this_line,pmtlen]
      out += pmtlen
      line[out,1] = 0.chr
      @wrap_offset = @prompt_invis_chars_first_line = 0
    end
    # inv_lbreaks[i] is where line i starts in the buffer.
    @inv_lbreaks[newlines = 0] = 0
    lpos = @prompt_physical_chars + modmark

    @_rl_wrapped_line = Array.new(@visible_line.length,0)
    num = 0

    # prompt_invis_chars_first_line is the number of invisible characters in
    #   the first physical line of the prompt.
    #  wrap_offset - prompt_invis_chars_first_line is the number of invis
    #   chars on the second line.

    # what if lpos is already >= _rl_screenwidth before we start drawing the
    #   contents of the command line?
    while (lpos >= @_rl_screenwidth)
      # fix from Darin Johnson <darin@acuson.com> for prompt string with
      #   invisible characters that is longer than the screen width.  The
      #   prompt_invis_chars_first_line variable could be made into an array
      #   saying how many invisible characters there are per line, but that's
      #   probably too much work for the benefit gained.  How many people have
      #   prompts that exceed two physical lines?
      #   Additional logic fix from Edward Catmur <ed@catmur.co.uk>
      if (!@rl_byte_oriented)
        n0 = num
        temp = @local_prompt_len
        while (num < temp)
          z = _rl_col_width(@local_prompt, n0, num)
          if (z > @_rl_screenwidth)
            num = _rl_find_prev_mbchar(@local_prompt, num, MB_FIND_ANY)
            break
          elsif (z == @_rl_screenwidth)
            break
          end
          num+=1
        end
        temp = num
      else
        temp = ((newlines + 1) * @_rl_screenwidth)
      end

      # Now account for invisible characters in the current line.
      temp += (@local_prompt_prefix.nil? ? ((newlines == 0) ? @prompt_invis_chars_first_line :
                                            ((newlines == 1) ? @wrap_offset : 0)) :
                                            ((newlines == 0) ? @wrap_offset : 0))

      @inv_lbreaks[newlines+=1] = temp
      if !@rl_byte_oriented
        lpos -= _rl_col_width(@local_prompt, n0, num)
      else
        lpos -= @_rl_screenwidth
      end
    end
    @prompt_last_screen_line = newlines

    # Draw the rest of the line (after the prompt) into invisible_line, keeping
    #   track of where the cursor is (cpos_buffer_position), the number of the line containing
    #   the cursor (lb_linenum), the last line number (inv_botlin).
    #   It maintains an array of line breaks for display (inv_lbreaks).
    #   This handles expanding tabs for display and displaying meta characters.
    lb_linenum = 0
    _in = 0
    if !@rl_byte_oriented && @rl_end>0
      case @encoding
      when 'E'
        wc = @rl_line_buffer[0,@rl_end].scan(/./me)[0]
        wc_bytes = wc ? wc.length : 1
      when 'S'
        wc = @rl_line_buffer[0,@rl_end].scan(/./ms)[0]
        wc_bytes = wc ? wc.length : 1
      when 'U'
        wc = @rl_line_buffer[0,@rl_end].scan(/./mu)[0]
        wc_bytes = wc ? wc.length : 1
      when 'X'
        wc = @rl_line_buffer[0,@rl_end].force_encoding(@encoding_name)[0]
        wc_bytes = wc ? wc.bytesize : 1
      end
    else
      wc_bytes = 1
    end

    while(_in < @rl_end)

      c = @rl_line_buffer[_in,1]
      if(c == 0.chr)
        @rl_end = _in
        break
      end
      if (!@rl_byte_oriented)
        case @encoding
        when 'U'
          wc_width = wc && wc.unpack('U').first >= 0x1000 ? 2 : 1
        when 'X'
          wc_width = wc && wc.ord > 0x1000 ? 2 : 1
        else
          wc_width = wc ? wc.length : 1
        end
      end
      if (out + 8 >= @line_size)    # XXX - 8 for \t
        @line_size *= 2
        if @visible_line.length>=@line_size
          @visible_line = @visible_line[0,@line_size]
        else
          @visible_line += 0.chr * (@line_size-@visible_line.length)
        end
        if @invisible_line.length>=@line_size
          @invisible_line = @invisible_line[0,@line_size]
        else
          @invisible_line += 0.chr * (@line_size-@invisible_line.length)
        end
        line = @invisible_line
      end

      if (_in == @rl_point)
        @cpos_buffer_position = out
        lb_linenum = newlines
      end
      if (false && meta_char(c))
        if (!@_rl_output_meta_chars && false)
          line[out,4] = "\\%03o" % c.ord

          if (lpos + 4 >= @_rl_screenwidth)
            temp = @_rl_screenwidth - lpos
            @inv_lbreaks[newlines+=1] = out + temp
            lpos = 4 - temp
          else
            lpos += 4
          end
          out += 4
        else
          line[out,1] = c
          out += 1
          lpos+=1
          if (lpos >= @_rl_screenwidth)
            @inv_lbreaks[newlines+=1] = out
            @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
            lpos = 0
          end
        end

      elsif (c == "\t")

        newout = out + 8 - lpos % 8
        temp = newout - out
        if (lpos + temp >= @_rl_screenwidth)
          temp2 = @_rl_screenwidth - lpos
          @inv_lbreaks[newlines+=1] = out + temp2
          lpos = temp - temp2
          while (out < newout)
            line[out,1] = ' '
            out += 1
          end

        else

          while (out < newout)
            line[out,1] = ' '
            out += 1
          end
          lpos += temp
        end

      elsif (c == "\n" && !@_rl_horizontal_scroll_mode && @_rl_term_up)
        line[out,1] = 0.chr # XXX - sentinel
        out += 1
        @inv_lbreaks[newlines+=1] = out
        lpos = 0
      elsif (ctrl_char(c) || c == RUBOUT)
        line[out,1] = '^'
        out += 1
        lpos+=1
        if (lpos >= @_rl_screenwidth)
          @inv_lbreaks[newlines+=1] = out
          @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
          lpos = 0
        end
        # NOTE: c[0].ord works identically on both 1.8 and 1.9
        line[out,1] = ctrl_char(c) ? (c[0].ord|0x40).chr.upcase : '?'
        out += 1
        lpos+=1
        if (lpos >= @_rl_screenwidth)
          @inv_lbreaks[newlines+=1] = out
          @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
          lpos = 0
        end
      else

        if (!@rl_byte_oriented)
          _rl_wrapped_multicolumn = 0
          if (@_rl_screenwidth < lpos + wc_width)
            for i in lpos ... @_rl_screenwidth
              # The space will be removed in update_line()
              line[out,1] = ' '
              out += 1
              _rl_wrapped_multicolumn+=1
              lpos+=1
              if (lpos >= @_rl_screenwidth)
                @inv_lbreaks[newlines+=1] = out
                @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
                lpos = 0
              end
            end
          end
          if (_in == @rl_point)
            @cpos_buffer_position = out
            lb_linenum = newlines
          end
          line[out,wc_bytes] = @rl_line_buffer[_in,wc_bytes]
          out += wc_bytes
          for i in 0 ... wc_width
            lpos+=1
            if (lpos >= @_rl_screenwidth)
              @inv_lbreaks[newlines+=1] = out
              @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
              lpos = 0
            end
          end
        else
          line[out,1] = c
          out += 1
          lpos+=1
          if (lpos >= @_rl_screenwidth)
            @inv_lbreaks[newlines+=1] = out
            @_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn
            lpos = 0
          end
        end

      end

      if (!@rl_byte_oriented)
        _in += wc_bytes
        case @encoding
        when 'E'
          wc = @rl_line_buffer[_in,@rl_end - _in].scan(/./me)[0]
          wc_bytes = wc ? wc.length : 1
        when 'S'
          wc = @rl_line_buffer[_in,@rl_end - _in].scan(/./ms)[0]
          wc_bytes = wc ? wc.length : 1
        when 'U'
          wc = @rl_line_buffer[_in,@rl_end - _in].scan(/./mu)[0]
          wc_bytes = wc ? wc.length : 1
        when 'X'
          wc = @rl_line_buffer[_in,@rl_end - _in].force_encoding(@encoding_name)[0]
          wc_bytes = wc ? wc.bytesize : 1
        end

      else
        _in+=1
      end
    end

    line[out,1] = 0.chr

    if (@cpos_buffer_position < 0)
      @cpos_buffer_position = out
      lb_linenum = newlines
    end

    inv_botlin = newlines
    @inv_lbreaks[newlines+1] = out
    cursor_linenum = lb_linenum

    # CPOS_BUFFER_POSITION == position in buffer where cursor should be placed.
    #   CURSOR_LINENUM == line number where the cursor should be placed.

    # PWP: now is when things get a bit hairy.  The visible and invisible
    #   line buffers are really multiple lines, which would wrap every
    #   (screenwidth - 1) characters.  Go through each in turn, finding
    #   the changed region and updating it.  The line order is top to bottom.

    # If we can move the cursor up and down, then use multiple lines,
    #   otherwise, let long lines display in a single terminal line, and
    #   horizontally scroll it.

    if (!@_rl_horizontal_scroll_mode && @_rl_term_up)
      if (!@rl_display_fixed || @forced_display)
        @forced_display = false
        # If we have more than a screenful of material to display, then
        #   only display a screenful.  We should display the last screen,
        #   not the first.
        if (out >= @_rl_screenchars)
          if (!@rl_byte_oriented)
            out = _rl_find_prev_mbchar(line, @_rl_screenchars, MB_FIND_ANY)
          else
            out = @_rl_screenchars - 1
          end
        end

        # The first line is at character position 0 in the buffer.  The
        #   second and subsequent lines start at inv_lbreaks[N], offset by
        #   OFFSET (which has already been calculated above).

        # For each line in the buffer, do the updating display.
        linenum = 0
        while linenum <= inv_botlin
          # This can lead us astray if we execute a program that changes
          #the locale from a non-multibyte to a multibyte one.
          o_cpos = @_rl_last_c_pos
          @cpos_adjusted = false
          update_line(@visible_line,vis_pos(linenum), inv_line(linenum), linenum,
                      vis_llen(linenum), inv_llen(linenum), inv_botlin)

          if (linenum == 0 && !@rl_byte_oriented &&
              !@cpos_adjusted &&
              @_rl_last_c_pos != o_cpos &&
              @_rl_last_c_pos > @wrap_offset &&
              o_cpos < @prompt_last_invisible)
            @_rl_last_c_pos -= @wrap_offset
          end

          # If this is the line with the prompt, we might need to
          # compensate for invisible characters in the new line. Do
          # this only if there is not more than one new line (which
          # implies that we completely overwrite the old visible line)
          # and the new line is shorter than the old.  Make sure we are
          # at the end of the new line before clearing.
          if (linenum == 0 &&
              inv_botlin == 0 && @_rl_last_c_pos == out &&
              (@wrap_offset > @visible_wrap_offset) &&
              (@_rl_last_c_pos < @visible_first_line_len))
            if !@rl_byte_oriented
              nleft = @_rl_screenwidth - @_rl_last_c_pos
            else
              nleft = @_rl_screenwidth + @wrap_offset - @_rl_last_c_pos
            end
            if (nleft!=0)
              _rl_clear_to_eol(nleft)
            end
          end

          # Since the new first line is now visible, save its length.
          if (linenum == 0)
            @visible_first_line_len = (inv_botlin > 0) ? @inv_lbreaks[1] : out - @wrap_offset
          end

          linenum += 1
        end

        # We may have deleted some lines.  If so, clear the left over
        #   blank ones at the bottom out.
        if (@_rl_vis_botlin > inv_botlin)
          while(linenum <= @_rl_vis_botlin)
            tt = vis_chars(linenum)
            _rl_move_vert(linenum)
            _rl_move_cursor_relative(0, tt)
            _rl_clear_to_eol((linenum == @_rl_vis_botlin) ? tt.length : @_rl_screenwidth)
            linenum += 1
          end
        end
        @_rl_vis_botlin = inv_botlin

        # CHANGED_SCREEN_LINE is set to 1 if we have moved to a
        #   different screen line during this redisplay.
        changed_screen_line = @_rl_last_v_pos != cursor_linenum
        if (changed_screen_line)
          _rl_move_vert(cursor_linenum)
          # If we moved up to the line with the prompt using _rl_term_up,
          # the physical cursor position on the screen stays the same,
          # but the buffer position needs to be adjusted to account
          # for invisible characters.
          if (@rl_byte_oriented && cursor_linenum == 0 && @wrap_offset!=0)
            @_rl_last_c_pos += @wrap_offset
          end
        end
        # We have to reprint the prompt if it contains invisible
        #   characters, since it's not generally OK to just reprint
        #   the characters from the current cursor position.  But we
        #   only need to reprint it if the cursor is before the last
        #   invisible character in the prompt string.
        nleft = @prompt_visible_length + @wrap_offset
        if (cursor_linenum == 0 && @wrap_offset > 0 && @_rl_last_c_pos > 0 &&
            @_rl_last_c_pos < prompt_ending_index() && @local_prompt)
          if (@_rl_term_cr)
            @rl_outstream.write(@_rl_term_cr)
          end
          _rl_output_some_chars(@local_prompt,0,nleft)
          if !@rl_byte_oriented
            @_rl_last_c_pos = _rl_col_width(@local_prompt, 0, nleft) - @wrap_offset
          else
            @_rl_last_c_pos = nleft
          end
        end

        # Where on that line?  And where does that line start
        #   in the buffer?
        pos = @inv_lbreaks[cursor_linenum]
        # nleft == number of characters in the line buffer between the
        #   start of the line and the desired cursor position.
        nleft = @cpos_buffer_position - pos

        # NLEFT is now a number of characters in a buffer.  When in a
        #   multibyte locale, however, _rl_last_c_pos is an absolute cursor
        #   position that doesn't take invisible characters in the prompt
        #   into account.  We use a fudge factor to compensate.

        # Since _rl_backspace() doesn't know about invisible characters in the
        #   prompt, and there's no good way to tell it, we compensate for
        #   those characters here and call _rl_backspace() directly.

        if (@wrap_offset!=0 && cursor_linenum == 0 && nleft < @_rl_last_c_pos)
          # TX == new physical cursor position in multibyte locale.
          if !@rl_byte_oriented
            tx = _rl_col_width(@visible_line, pos, pos+nleft) - @visible_wrap_offset
          else
            tx = nleft
          end
          if tx >= 0 && @_rl_last_c_pos > tx
            _rl_backspace(@_rl_last_c_pos - tx) # XXX
            @_rl_last_c_pos = tx
          end
        end
        # We need to note that in a multibyte locale we are dealing with
        #   _rl_last_c_pos as an absolute cursor position, but moving to a
        #   point specified by a buffer position (NLEFT) that doesn't take
        #   invisible characters into account.
        if !@rl_byte_oriented
          _rl_move_cursor_relative(nleft, @invisible_line,pos)
        elsif (nleft != @_rl_last_c_pos)
          _rl_move_cursor_relative(nleft, @invisible_line,pos)
        end
      end

    else           # Do horizontal scrolling.

      # Always at top line.
      @_rl_last_v_pos = 0

      # Compute where in the buffer the displayed line should start.  This
      # will be LMARGIN.

      # The number of characters that will be displayed before the cursor.
      ndisp = @cpos_buffer_position - @wrap_offset
      nleft  = @prompt_visible_length + @wrap_offset
      # Where the new cursor position will be on the screen.  This can be
      # longer than SCREENWIDTH; if it is, lmargin will be adjusted.
      phys_c_pos = @cpos_buffer_position - (@last_lmargin!=0 ? @last_lmargin : @wrap_offset)
      t = @_rl_screenwidth / 3

      # If the number of characters had already exceeded the screenwidth,
      #last_lmargin will be > 0.

      # If the number of characters to be displayed is more than the screen
      # width, compute the starting offset so that the cursor is about
      # two-thirds of the way across the screen.
      if (phys_c_pos > @_rl_screenwidth - 2)
        lmargin = @cpos_buffer_position - (2 * t)
        if (lmargin < 0)
          lmargin = 0
        end
        # If the left margin would be in the middle of a prompt with
        #   invisible characters, don't display the prompt at all.
        if (@wrap_offset!=0 && lmargin > 0 && lmargin < nleft)
          lmargin = nleft
        end
      elsif (ndisp < @_rl_screenwidth - 2)      # XXX - was -1
        lmargin = 0
      elsif (phys_c_pos < 1)
        # If we are moving back towards the beginning of the line and
        #   the last margin is no longer correct, compute a new one.
        lmargin = ((@cpos_buffer_position - 1) / t) * t # XXX
        if (@wrap_offset!=0 && lmargin > 0 && lmargin < nleft)
          lmargin = nleft
        end
      else
        lmargin = @last_lmargin
      end

      # If the first character on the screen isn't the first character
      #in the display line, indicate this with a special character.
      if (lmargin > 0)
        line[lmargin,1] = '<'
      end

      # If SCREENWIDTH characters starting at LMARGIN do not encompass
      # the whole line, indicate that with a special character at the
      # right edge of the screen.  If LMARGIN is 0, we need to take the
      # wrap offset into account.
      t = lmargin + m_offset(lmargin, @wrap_offset) + @_rl_screenwidth
      if (t < out)
        line[t - 1,1] = '>'
      end
      if (!@rl_display_fixed || @forced_display || lmargin != @last_lmargin)

        @forced_display = false
        update_line(@visible_line,@last_lmargin,@invisible_line[lmargin..-1],
                    0,
                    @_rl_screenwidth + @visible_wrap_offset,
                    @_rl_screenwidth + (lmargin ? 0 : @wrap_offset),
                    0)
        # If the visible new line is shorter than the old, but the number
        #   of invisible characters is greater, and we are at the end of
        #   the new line, we need to clear to eol.
        t = @_rl_last_c_pos - m_offset(lmargin, @wrap_offset)
        if ((m_offset(lmargin, @wrap_offset) > @visible_wrap_offset) &&
            (@_rl_last_c_pos == out) &&
            t < @visible_first_line_len)

          nleft = @_rl_screenwidth - t
          _rl_clear_to_eol(nleft)
        end
        @visible_first_line_len = out - lmargin - m_offset(lmargin, @wrap_offset)
        if (@visible_first_line_len > @_rl_screenwidth)
          @visible_first_line_len = @_rl_screenwidth
        end
        _rl_move_cursor_relative(@cpos_buffer_position - lmargin, @invisible_line ,lmargin)
        @last_lmargin = lmargin
      end
    end
    @rl_outstream.flush

    # Swap visible and non-visible lines.
    @visible_line,@invisible_line = @invisible_line,@visible_line
    @vis_lbreaks,@inv_lbreaks = @inv_lbreaks,@vis_lbreaks

    @rl_display_fixed = false
    # If we are displaying on a single line, and last_lmargin is > 0, we
    #   are not displaying any invisible characters, so set visible_wrap_offset
    #   to 0.
    if (@_rl_horizontal_scroll_mode && @last_lmargin!=0)
      @visible_wrap_offset = 0
    else
      @visible_wrap_offset = @wrap_offset
    end
  end