class RubyCurses::TextPad

Public Class Methods

new(form=nil, config={}) click to toggle source

You may pass height, width, row and col for creating a window otherwise a fullscreen window will be created. If you pass a window from caller then that window will be used. Some keys are trapped, jkhl space, pgup, pgdown, end, home, t b This is currently very minimal and was created to get me started to integrating pads into other classes such as textview.

Calls superclass method
# File bin/mancurses, line 45
def initialize form=nil, config={}, &block

  @editable = false
  @focusable = true
  @config = config
  @prow = @pcol = 0
  @startrow = 0
  @startcol = 0
  @list = []
  super

  # FIXME 0 as height craps out. need to make it LINES

  #@height = @height.ifzero(FFI::NCurses.LINES)
  #@width = @width.ifzero(FFI::NCurses.COLS)
  @rows = @height
  @cols = @width
  @startrow = @row
  @startcol = @col
  #@suppress_border = config[:suppress_border]
  @row_offset = @col_offset = 1
  unless @suppress_border
    @startrow += 1
    @startcol += 1
    @rows -=3  # 3 is since print_border_only reduces one from width, to check whether this is correct
    @cols -=3
  end
  @row_offset = @col_offset = 0 if @suppress_borders
  @top = @row
  @left = @col
  @lastrow = @row + 1
  @lastcol = @col + 1
  init_vars
end

Public Instance Methods

bottom_of_window() click to toggle source
# File bin/mancurses, line 345
def bottom_of_window
  @current_index = @prow + @scrollatrows
  $multiplier ||= 0
  if $multiplier > 0
    @current_index -= $multiplier
    $multiplier = 0
  end
end
destroy() click to toggle source

Now since we use get_pad from window, upon the window being destroyed, it will call this. Else it will destroy pad

# File bin/mancurses, line 538
def destroy
  FFI::NCurses.delwin(@pad) if @pad # when do i do this ? FIXME
  @pad = nil
end
down(num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)) click to toggle source

move down a line mimicking vim's j key @param [int] multiplier entered prior to invoking key

# File bin/mancurses, line 360
def down num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
  @oldindex = @current_index if num > 10
  @current_index += num
  unless is_visible? @current_index
    if @current_index > @scrollatrows
      @prow += 1
    end
  end
  $multiplier = 0
end
ensure_visible(row = @current_index) click to toggle source

Ensure current row is visible, if not make it first row TODO - need to check if its at end and then reduce scroll at rows, @param current_index (default if not given)

# File bin/mancurses, line 658
def ensure_visible row = @current_index
  unless is_visible? row
      @prow = @current_index
  end
end
filename(filename) click to toggle source

supply a filename as source for textpad Reads up file into @content

# File bin/mancurses, line 146
def filename(filename)
  @file = filename
  @filetype = File.extname filename
  @content = File.open(filename,"r").readlines
  if @filetype == ""
    if @content.first.index("ruby")
      @filetype = ".rb"
    end
  end
  @_populate_needed = true
end
find_more() click to toggle source

Find next matching row for string accepted in ask_search

# File bin/mancurses, line 624
def find_more
  return unless @last_regex
  ix = next_match @last_regex
  return unless ix
  @oldindex = @current_index
  @current_index = ix[0]
  @curpos = ix[1]
  ensure_visible
end
formatted_text(text, fmt) click to toggle source
# File bin/mancurses, line 208
def formatted_text text, fmt
  require 'rbcurse/core/include/chunk'
  @formatted_text = text
  @color_parser = fmt
  @repaint_required = true
  # don't know if start is always required. so putting in caller
  #goto_start
  #remove_all
end
forward_word() click to toggle source
# File bin/mancurses, line 663
def forward_word
  $multiplier = 1 if !$multiplier || $multiplier == 0
  line = @current_index
  buff = @content[line].to_s
  return unless buff
  pos = @curpos || 0 # list does not have curpos
  $multiplier.times {
    found = buff.index(/[[:punct:][:space:]]\w/, pos)
    if !found
      # if not found, we've lost a counter
      if line+1 < @content.length
        line += 1
      else
        return
      end
      pos = 0
    else
      pos = found + 1
    end
    $log.debug " forward_word: pos #{pos} line #{line} buff: #{buff}"
  }
  $multiplier = 0
  @current_index = line
  @curpos = pos
  ensure_visible
  #@buffer = @list[@current_index].to_s
  #set_form_row
  #set_form_col pos
  @repaint_required = true
end
goto_end() click to toggle source

goto last line of file

# File bin/mancurses, line 320
def goto_end
  @oldindex = @current_index
  $multiplier ||= 0
  if $multiplier > 0
    goto_line $multiplier
    return
  end
  @current_index = @content_rows-1
  @prow = @current_index - @scrollatrows
  $multiplier = 0
end
goto_last_position() click to toggle source
# File bin/mancurses, line 422
def goto_last_position
  return unless @oldindex
  tmp = @current_index
  @current_index = @oldindex
  @oldindex = tmp
  bounds_check
end
goto_line(line) click to toggle source
# File bin/mancurses, line 331
def goto_line line
  ## we may need to calculate page, zfm style and place at right position for ensure visible
  @current_index = line
  ensure_visible line
  $multiplier = 0
end
goto_start() click to toggle source

goto first line of file

# File bin/mancurses, line 306
def goto_start
  @oldindex = @current_index
  $multiplier ||= 0
  if $multiplier > 0
    goto_line $multiplier
    return
  end
  @current_index = 0
  @curpos = @pcol = @prow = 0
  @prow = 0
  $multiplier = 0
end
handle_key(ch) click to toggle source

NOTE : if advancing pcol one has to clear the pad or something or else there'll be older content on the right side.

# File bin/mancurses, line 456
def handle_key ch
  return :UNHANDLED unless @content
  map_keys unless @mapped_keys

  @maxrow = @content_rows - @rows
  @maxcol = @content_cols - @cols 

  # need to understand the above line, can go below zero.
  # all this seems to work fine in padreader.rb in util.
  # somehow maxcol going to -33
  @oldrow = @prow
  @oldcol = @pcol
  $log.debug "XXX: PAD got #{ch} prow = #{@prow}"
  begin
    case ch
    when key(?l)
      # TODO take multipler
      #@pcol += 1
      if @curpos < @cols
        @curpos += 1
      end
    when key(?$)
      #@pcol = @maxcol - 1
      @curpos = [@content[@current_index].size, @cols].min
    when key(?h)
      # TODO take multipler
      if @curpos > 0
        @curpos -= 1
      end
    when key(?0)
      @curpos = 0
  when ?0.getbyte(0)..?9.getbyte(0)
    if ch == ?0.getbyte(0) && $multiplier == 0
      # copy of C-a - start of line
      @repaint_required = true if @pcol > 0 # tried other things but did not work
      @pcol = 0
      return 0
    end
    # storing digits entered so we can multiply motion actions
    $multiplier *= 10 ; $multiplier += (ch-48)
    return 0
    when ?\C-c.getbyte(0)
      $multiplier = 0
      return 0
    else
      # check for bindings, these cannot override above keys since placed at end
      begin
        ret = process_key ch, self
        $multiplier = 0
        ## If i press C-x > i get an alert from rwidgets which blacks the screen
        # if i put a padrefresh here it becomes okay but only for one pad,
        # i still need to do it for all pads.
      rescue => err
        $log.error " TEXTPAD ERROR INS #{err} "
        $log.debug(err.backtrace.join("\n"))
        textdialog ["Error in TextPad: #{err} ", *err.backtrace], :title => "Exception"
      end
      ## NOTE if textpad does not handle the event and it goes to form which pops
      # up a messagebox, then padrefresh does not happen, since control does not
      # come back here, so a black rect is left on screen
      return :UNHANDLED if ret == :UNHANDLED
    end
    bounds_check
  rescue => err
    $log.error " TEXTPAD ERROR 111 #{err} "
    $log.debug( err) if err
    $log.debug(err.backtrace.join("\n")) if err
    textdialog ["Error in TextPad: #{err} ", *err.backtrace], :title => "Exception"
    $error_message.value = ""
  ensure
    padrefresh
    Ncurses::Panel.update_panels
  end
  return 0
end
init_vars() click to toggle source
# File bin/mancurses, line 79
def init_vars
  @scrollatrows = @height - 3
  @oldindex = @current_index = 0
  # column cursor
  @curpos = 0
  @repaint_required = true
end
is_visible?(index) click to toggle source
# File bin/mancurses, line 542
def is_visible? index
  j = index - @prow #@toprow
  j >= 0 && j <= @scrollatrows
end
map_keys() click to toggle source

key mappings

# File bin/mancurses, line 281
def map_keys
  @mapped_keys = true
  bind_key([?g,?g], 'goto_start'){ goto_start } # mapping double keys like vim
  bind_key(279, 'goto_start'){ goto_start } 
  bind_keys([?G,277], 'goto end'){ goto_end } 
  bind_keys([?k,KEY_UP], "Up"){ up } 
  bind_keys([?j,KEY_DOWN], "Down"){ down } 
  bind_key(?\C-e, "Scroll Window Down"){ scroll_window_down } 
  bind_key(?\C-y, "Scroll Window Up"){ scroll_window_up } 
  bind_keys([32,338, ?\C-d], "Scroll Forward"){ scroll_forward } 
  bind_keys([?\C-b,339]){ scroll_backward } 
  bind_key([?',?']){ goto_last_position } # vim , goto last row position (not column)
  bind_key(?/, :ask_search)
  bind_key(?n, :find_more)
  bind_key([?\C-x, ?>], :scroll_right)
  bind_key([?\C-x, ?<], :scroll_left)
  bind_key(?\M-l, :scroll_right)
  bind_key(?\M-h, :scroll_left)
  bind_key(?L, :bottom_of_window)
  bind_key(?M, :middle_of_window)
  bind_key(?H, :top_of_window)
  bind_key(?w, :forward_word)
end
middle_of_window() click to toggle source
# File bin/mancurses, line 353
def middle_of_window
  @current_index = @prow + (@scrollatrows/2)
  $multiplier = 0
end
next_match(str) click to toggle source

Find the next row that contains given string @return row and col offset of match, or nil @param String to find

# File bin/mancurses, line 638
def next_match str
  first = nil
  ## content can be string or Chunkline, so we had to write <tt>index</tt> for this.
  ## =~ does not give an error, but it does not work.
  @content.each_with_index do |line, ix|
    col = line.index str
    if col
      first ||= [ ix, col ]
      if ix > @current_index
        return [ix, col]
      end
    end
  end
  return first
end
on_enter() click to toggle source
# File bin/mancurses, line 546
def on_enter
  set_form_row
end
padrefresh() click to toggle source
write pad onto window

private

# File bin/mancurses, line 220
def padrefresh
  FFI::NCurses.prefresh(@pad,@prow,@pcol, @startrow, @startcol, @rows + @startrow, @cols+@startcol);
end
print(string, _width = @content_cols) click to toggle source
2013-03-07 - 19:57 changed width to @content_cols since data not printing

in some cases fully when ansi sequences were present int some line but not in others lines without ansi were printing less by a few chars. This was prolly copied from rwindow, where it is okay since its for a specific width

render(pad, lineno, text) click to toggle source

default method for rendering a line

# File bin/mancurses, line 128
def render pad, lineno, text
  if text.is_a? Chunks::ChunkLine
    FFI::NCurses.wmove @pad, lineno, 0
    a = get_attrib @attrib
  
    show_colored_chunks text, nil, a
    return
  end
  if @renderer
    @renderer.render @pad, lineno, text
  else
    FFI::NCurses.mvwaddstr(@pad,lineno, 0, @content[lineno])
  end
end
renderer(r) click to toggle source

supply a custom renderer that implements +render()+ @see render

# File bin/mancurses, line 122
def renderer r
  @renderer = r
end
repaint() click to toggle source
# File bin/mancurses, line 242
def repaint
  ## 2013-03-08 - 21:01 This is the fix to the issue of form callign an event like ? or F1
  # which throws up a messagebox which leaves a black rect. We have no place to put a refresh
  # However, form does call repaint for all objects, so we can do a padref here. Otherwise,
  # it would get rejected. UNfortunately this may happen more often we want, but we never know
  # when something pops up on the screen.
  padrefresh unless @repaint_required
  return unless @repaint_required
  if @formatted_text
    $log.debug "XXX:  INSIDE FORMATTED TEXT "

    l = RubyCurses::Utils.parse_formatted_text(@color_parser,
                                           @formatted_text)

    text(l)
    @formatted_text = nil
  end

  ## moved this line up or else create_p was crashing
  @window ||= @graphic
  populate_pad if @_populate_needed
  #HERE we need to populate once so user can pass a renderer
  unless @suppress_border
    if @repaint_all
      @window.print_border_only @top, @left, @height-1, @width, $datacolor
      print_title
      @window.wrefresh
    end
  end

  padrefresh
  Ncurses::Panel.update_panels
  @repaint_required = false
  @repaint_all = false
end
scroll_backward() click to toggle source

scrolls lines backward a window full at a time, on pressing pageup C-u may not work since it is trapped by form earlier. Need to fix

# File bin/mancurses, line 417
def scroll_backward
  @oldindex = @current_index
  @current_index -= @scrollatrows
  @prow = @current_index - @scrollatrows
end
scroll_forward() click to toggle source

scrolls lines a window full at a time, on pressing ENTER or C-d or pagedown

# File bin/mancurses, line 409
def scroll_forward
  @oldindex = @current_index
  @current_index += @scrollatrows
  @prow = @current_index - @scrollatrows
end
scroll_left() click to toggle source
# File bin/mancurses, line 447
def scroll_left
  @pcol -= 1
end
scroll_right() click to toggle source
# File bin/mancurses, line 429
def scroll_right
  if @content_cols < @cols
    maxpcol = 0
  else
    maxpcol = @content_cols - @cols
  end
  @pcol += 1
  @pcol = maxpcol if @pcol > maxpcol
  # to prevent right from retaining earlier painted values
  # padreader does not do a clear, yet works fine.
  # OK it has an update_panel after padrefresh, that clears it seems.
  #this clears entire window not just the pad
  #FFI::NCurses.wclear(@window.get_window)
  # so border and title is repainted after window clearing
  #
  # Next line was causing all sorts of problems when scrolling  with ansi formatted text
  #@repaint_all = true
end
scroll_window_down(num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)) click to toggle source

scrolls window down mimicking vim C-e @param [int] multiplier entered prior to invoking key

# File bin/mancurses, line 388
def scroll_window_down num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
  @prow += num
    if @prow > @current_index
      @current_index += 1
    end
  #check_prow
  $multiplier = 0
end
scroll_window_up(num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)) click to toggle source

scrolls window up mimicking vim C-y @param [int] multiplier entered prior to invoking key

# File bin/mancurses, line 399
def scroll_window_up num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
  @prow -= num
  unless is_visible? @current_index
    # one more check may be needed here TODO
    @current_index -= num
  end
  $multiplier = 0
end
set_form_col() click to toggle source
# File bin/mancurses, line 552
def set_form_col
end
set_form_row() click to toggle source
# File bin/mancurses, line 549
def set_form_row
  setrowcol @lastrow, @lastcol
end
show_colored_chunks(chunks, defcolor = nil, defattr = nil) click to toggle source
# File bin/mancurses, line 181
def show_colored_chunks(chunks, defcolor = nil, defattr = nil)
  #return unless visible?
  chunks.each do |chunk| #|color, chunk, attrib|
    case chunk
    when Chunks::Chunk
      color = chunk.color
      attrib = chunk.attrib
      text = chunk.text
    when Array
      # for earlier demos that used an array
      color = chunk[0]
      attrib = chunk[2]
      text = chunk[1]
    end

    color ||= defcolor
    attrib ||= defattr || NORMAL

    #cc, bg = ColorMap.get_colors_for_pair color
    #$log.debug "XXX: CHUNK textpad #{text}, cp #{color} ,  attrib #{attrib}. #{cc}, #{bg} "
    FFI::NCurses.wcolor_set(@pad, color,nil) if color
    FFI::NCurses.wattron(@pad, attrib) if attrib
    print(text)
    FFI::NCurses.wattroff(@pad, attrib) if attrib
  end
end
text(lines) click to toggle source

Supply an array of string to be displayed This will replace existing text

# File bin/mancurses, line 161
def text lines
  raise "text() receiving null content" unless lines
  @content = lines
  @_populate_needed = true
end
top_of_window() click to toggle source
# File bin/mancurses, line 337
def top_of_window
  @current_index = @prow 
  $multiplier ||= 0
  if $multiplier > 0
    @current_index += $multiplier
    $multiplier = 0
  end
end
up(num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)) click to toggle source

move up a line mimicking vim's k key @param [int] multiplier entered prior to invoking key

# File bin/mancurses, line 373
def up num=(($multiplier.nil? or $multiplier == 0) ? 1 : $multiplier)
  @oldindex = @current_index if num > 10
  @current_index -= num
  unless is_visible? @current_index
    if @prow > @current_index
      #$status_message.value = "1 #{@prow} > #{@current_index} "
      @prow -= 1
    else
    end
  end
  $multiplier = 0
end

Private Instance Methods

bounds_check() click to toggle source

check that current_index and prow are within correct ranges sets row (and someday col too) sets repaint_required

# File bin/mancurses, line 561
def bounds_check
  r,c = rowcol
  @current_index = 0 if @current_index < 0
  @current_index = @content_rows-1 if @current_index > @content_rows-1
  #$status_message.value = "visible #{@prow} , #{@current_index} "
  unless is_visible? @current_index
    if @prow > @current_index
      #$status_message.value = "1 #{@prow} > #{@current_index} "
      @prow -= 1
    else
    end
  end
  #end
  check_prow
  #$log.debug "XXX: PAD BOUNDS ci:#{@current_index} , old #{@oldrow},pr #{@prow}, max #{@maxrow} pcol #{@pcol} maxcol #{@maxcol}"
  @crow = @current_index + r - @prow
  @crow = r if @crow < r
  # 2 depends on whetehr suppressborders
  @crow = @row + @height -2 if @crow >= r + @height -2
  setrowcol @crow, @curpos+c
  lastcurpos @crow, @curpos+c
  if @oldrow != @prow || @oldcol != @pcol
    @repaint_required = true
  end
end
check_prow() click to toggle source

check that prow and pcol are within bounds

# File bin/mancurses, line 594
def check_prow
  @prow = 0 if @prow < 0
  if @prow > @maxrow-1
    @prow = @maxrow-1
  end
  if @pcol > @maxcol-1
    @pcol = @maxcol-1
  end
  @pcol = 0 if @pcol < 0
end
content_cols() click to toggle source

length of longest string in array This will give a 'wrong' max length if the array has ansi color escape sequences in it which inc the length but won't be printed. Such lines actually have less length when printed So in such cases, give more space to the pad.

# File bin/mancurses, line 234
def content_cols
  longest = @content.max_by(&:length)
  ## 2013-03-06 - 20:41 crashes here for some reason when man gives error message no man entry
  return 0 unless longest
  longest.length
end
create_pad() click to toggle source
# File bin/mancurses, line 91
def create_pad
  destroy if @pad
  #@pad = FFI::NCurses.newpad(@content_rows, @content_cols)
  @pad = @window.get_pad(@content_rows, @content_cols )
end
key(x) click to toggle source

convenience method to return byte

# File bin/mancurses, line 226
def key x
  x.getbyte(0)
end
lastcurpos(r,c) click to toggle source
# File bin/mancurses, line 586
def lastcurpos r,c
  @lastrow = r
  @lastcol = c
end
populate_pad() click to toggle source

create and populate pad

# File bin/mancurses, line 99
def populate_pad
  @_populate_needed = false
  # how can we make this more sensible ? FIXME
  @renderer ||= DefaultRubyRenderer.new if ".rb" == @filetype
  @content_rows = @content.count
  @content_cols = content_cols()
  @content_rows = @rows if @content_rows < @rows
  @content_cols = @cols if @content_cols < @cols
  $log.debug "XXXX content_cols = #{@content_cols}"

  create_pad

  Ncurses::Panel.update_panels
  @content.each_index { |ix|
    #FFI::NCurses.mvwaddstr(@pad,ix, 0, @content[ix])
    render @pad, ix, @content[ix]
  }

end