Class: RubyCurses::TextArea

Inherits:
Widget show all
Includes:
ListEditable, ListScrollable
Defined in:
lib/rbcurse/core/widgets/rtextarea.rb

Overview

a multiline text editing widget TODO - giving data to user - adding newlines, and withog adding.

- respect newlines for incoming data
we need a set_text method, passing nil or blank clears
current way is not really good. remove_all sucks.
 TODO don't set maxlen if nil. compute it as a local in methods. Else splitpane will not
 work correctly.

Instance Attribute Summary collapse

Attributes included from ListScrollable

#find_offset, #find_offset1, #search_found_ix, #show_caret

Attributes inherited from Widget

#_object_created, #col_offset, #cols_panned, #config, #curpos, #focussed, #form, #id, #key_label, #parent_component, #row_offset, #rows_panned, #state

Instance Method Summary collapse

Methods included from ListEditable

#add_to_kill_ring, #append_next_kill, #append_row, #delete_at, #delete_curr_char, #delete_eol, #delete_forward, #delete_line, #delete_prev_char, #delete_word, #join_next_line, #kill_ring_save, #remove_all, #undo_handler, #yank, #yank_pop

Methods included from ListScrollable

#_convert_index_to_printable_row, #_convert_index_to_visible_row, #_find_next, #_find_prev, #ask_search, #backward_word, #bounds_check, #find_more, #find_next, #find_prev, #focussed_index, #forward_char, #forward_word, #goto_bottom, #goto_last_position, #goto_top, #highlight_focussed_row, #install_keys, #is_visible?, #next_match, #next_row, #previous_row, #sanitize, #scroll_backward, #scroll_forward, #scroll_left, #scroll_right, #selected_item, #set_focus_on, #set_form_row, #set_selection_for_char, #show_caret_func, #truncate

Methods inherited from Widget

#action_manager, #changed, #click, #color_pair, #command, #destroy, #enter, #event_list, #focus, #get_preferred_size, #getvalue_for_paint, #height, #height=, #hide, #leave, #modified?, #move, #on_enter, #on_leave, #override_graphic, #process_key, #remove, #repaint_all, #repaint_required, #set_buffer_modified, #set_buffering, #set_form, #set_form_row, #setformrowcol, #setrowcol, #show, #text_variable, #unbind_key, #width, #width=

Methods included from Io

#__create_footer_window, #clear_this, #get_file, #print_this, #rb_getchar, #rb_gets, #rbgetstr, #warn

Methods included from Utils

#OLDdefine_key, #_process_key, #bind_key, #bind_keys, #clean_string!, #define_key, #define_prefix_command, #display_app_help, #get_attrib, #get_color, #keycode_tos, #last_line, #one_line_window, #parse_formatted_text, #print_key_bindings, #repeatm, #run_command, #shell_out, #shell_output, #suspend, #view

Methods included from ConfigSetup

#cget, #config_setup, #configure, #variable_set

Methods included from EventHandler

#bind, #fire_handler, #fire_property_change

Constructor Details

#initialize(form = nil, config = {}, &block) ⇒ TextArea

Returns a new instance of TextArea.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 53

def initialize form = nil, config={}, &block
  @focusable = true
  @editable = true
  @row = 0
  @col = 0
  @curpos = 0
  @list = []
  @suppress_borders = false
  @row_offset = @col_offset = 1 # for cursor display on first entry, so not positioned on border
  @_events ||= [] 
  @_events.push :CHANGE
  super
  @orig_col = @col
  # this does result in a blank line if we insert after creating. That's required at 
  # present if we wish to only insert
  if @list.empty?
  #  @list << "\r"   # removed this on 2009-02-15 17:25 lets see how it goes
  end
  @content_rows = @list.length
  @win = @graphic # 2009-12-26 14:54 BUFFERED  replace form.window with graphic
  # 2010-01-10 19:35 compute locally if not set
  install_keys
  init_vars
  bordertitle_init
  init_actions
end

Instance Attribute Details

#overwrite_modeObject

dsl_accessor :suppress_borders # added 2010-02-12 12:21 values true or false



51
52
53
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 51

def overwrite_mode
  @overwrite_mode
end

#toprowObject (readonly)

Returns the value of attribute toprow.



46
47
48
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 46

def toprow
  @toprow
end

Instance Method Details

#<<(data) ⇒ Object

wraps line sent in if longer than _maxlen Typically a line is sent in. We wrap and put a hard return at end.



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 139

def << data
  # if width if nil, either set it, or add this to a container that sets it before calling this method
  _maxlen = @maxlen || @width - @internal_width
  if data.length > _maxlen
    #$log.debug "wrapped append for #{data}"
    data = wrap_text data
    #$log.debug "after wrap text for :#{data}"
    data = data.split("\n")
    # 2009-01-01 22:24 the \n was needed so we would put a space at time of writing.
    # we need a soft return so a space can be added when pushing down.
    # commented off 2008-12-28 21:59 
    #data.each {|line| @list << line+"\n"}
    data.each {|line| @list << line}
     @list[-1] << "\r" #XXXX
  else
    #$log.debug "normal append for #{data}"
    data << "\r" if data[-1,1] != "\r" #XXXX
    @list << data
  end
  set_modified  # added 2009-03-07 18:29 
  goto_end if @auto_scroll 
  self
end

#addcol(num) ⇒ Object

FIXME : these 2 only require the footer to be repainted not everything We should be able to manage that. We need a repaint_footer_required. Setting repaint_required really slows performance when one presses the right arrow key since a repaint is happenign repeatedly for each key.



473
474
475
476
477
478
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 473

def addcol num
#     @repaint_required = true # added 2010-01-15 23:59, so that footer is updated, sucks!
  @repaint_footer_required = true # 2010-01-23 22:41 
  my_win = @form || @parent_component.form # 2010-02-12 12:51 
  my_win.addcol num
end

#addrowcol(row, col) ⇒ Object



479
480
481
482
483
484
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 479

def addrowcol row,col
  #@repaint_required = true # added 2010-01-15 23:59 
  @repaint_footer_required = true # 2010-01-23 22:41 
  my_win = @form || @parent_component.form # 2010-02-12 12:51 
  my_win.addrowcol row, col
end

#ask_search_forwardObject



896
897
898
899
900
901
902
903
904
905
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 896

def ask_search_forward
    regex =  get_string("Enter regex to search", 20, @last_regex||"")
    ix = _find_next regex, @current_index
    if ix.nil?
      alert("No matching data for: #{regex}")
    else
      set_focus_on(ix)
      set_form_col @find_offset
    end
end

#at_eol?Boolean

added 2009-10-04 22:13 returns whether cursor is at end of line

Returns:

  • (Boolean)


457
458
459
460
461
462
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 457

def at_eol?
  if @curpos+1== @list[@current_index].length  
    return  true
  end
  return false
end

#at_last_line?Boolean

added 2009-10-04 22:13 returns whether at last line (required so that forward does not go to start)

Returns:

  • (Boolean)


465
466
467
468
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 465

def at_last_line?
  return true if @list.length == @current_index + 1
  return false
end

#buffer_lenObject



429
430
431
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 429

def buffer_len
  @list[@current_index].nil? ? 0 : @list[@current_index].chomp().length  
end

#current_lineObject



789
790
791
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 789

def current_line
  @list[@current_index]
end

#cursor_backwardObject

2009-10-04 23:01 taken care that you can’t go back at start of textarea it was going onto border



487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 487

def cursor_backward
    #$log.debug "back char cp ll and ci #{@list.length}, #{@current_index}"
    #$log.debug "back char cb #{@curpos}, #{@buffer.length}. wi: #{@width}"
    return if @curpos == 0 and @current_index == 0 # added 2009-10-04 23:02 
    repeatm { 
      if @curpos > 0
        @curpos -= 1
        addcol -1
      else # trying this out 2008-12-26 20:18 
        ret = up
        cursor_eol if ret != -1
      end
    }
end

#cursor_bolObject



807
808
809
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 807

def cursor_bol
  set_form_col 0
end

#cursor_bounds_checkObject



425
426
427
428
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 425

def cursor_bounds_check
  max = buffer_len()
  @curpos = max if @curpos > max # check 2008-12-27 00:02 
end

#cursor_eolObject



802
803
804
805
806
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 802

def cursor_eol
   _maxlen = @maxlen || @width - @internal_width
  $log.error "ERROR !!! bufferlen gt _maxlen #{@buffer.length}, #{_maxlen}" if @buffer.length > _maxlen
  set_form_col current_line().chomp().length() #-1 needs to be one ahead 2011-10-10 TRYING OUT XXX
end

#cursor_forward(num = 1) ⇒ Object

FIXME : if cursor at end of last line then forward takes cursor to start of last line (same line), should stop there.



439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 439

def cursor_forward num=1
  #$log.debug "next char cp #{@curpos}, #{@buffer.length}. wi: #{@width}"
  #$log.debug "next char cp ll and ci #{@list.length}, #{@current_index}"
  #if @curpos < @width and @curpos < maxlen-1 # else it will do out of box
  return if at_eol? and at_last_line?
  repeatm { 
  if @curpos < buffer_len()
    @curpos += 1
    addcol 1
  else # trying this out 2008-12-26 20:18 
    @curpos = 0
    down 1 # if not then multipler will trigger there too
  end
  cursor_bounds_check
  }
end

#do_current_row {|| ... } ⇒ Object

:yields current row

Yields:

  • ()


432
433
434
435
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 432

def do_current_row # :yields current row
  yield @list[@current_index]
  @buffer = @list[@current_index]
end

#do_relative_row(num) {|| ... } ⇒ Object

Yields:

  • ()


792
793
794
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 792

def do_relative_row num
  yield @list[@current_index+num] 
end

#edit_externalObject



918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 918

def edit_external
  require 'rbcurse/core/include/appmethods'
  require 'tempfile'
  f = Tempfile.new("rbcurse")
  l = self.text
  l.each { |line| f.puts line }
  fp = f.path
  f.flush

  editor = ENV['EDITOR'] || 'vi'
  vimp = %x[which #{editor}].chomp
  ret = shell_out "#{vimp} #{fp}"
  if ret
    lines = File.open(f,'r').readlines
    set_content(lines, :content_type => @old_content_type)
  end
end

#get_contentObject

FOR scrollable ###



225
226
227
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 225

def get_content
  @list
end

#get_textObject

def to_s this was just annoying in debugs



811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 811

def get_text
  l = getvalue
  str = ""
  old = " "
  l.each_with_index do |line, i|
    tmp = line.gsub("\n","")
    tmp.gsub!("\r", "\n")
    if old[-1,1] !~ /\s/ and tmp[0,1] !~ /\s/
      str << " "
    end
    str << tmp
    old = tmp
  end
  str
end

#get_windowObject



266
267
268
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 266

def get_window
  @graphic
end

#getvalueObject



275
276
277
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 275

def getvalue
  @list
end

#handle_key(ch) ⇒ Object

textarea



326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 326

def handle_key ch
  @current_key = ch # I need some funcs to know what key they were mapped to
  @buffer = @list[@current_index]
  if @buffer.nil? and @list.length == 0
    ## 2009-10-04 22:39 
    # what this newline does is , if we use << to append, data is appended
    # to second line
    @list << "\n" # changed space to newline so wrapping puts a line.
    @current_index = 0 ; ## added 2009-10-04 21:47 
    @buffer = @list[@current_index]
  end
  ## 2009-10-04 20:48  i think the next line was resulting in a hang if buffer nil
  # in sqlc on pressing Clear.
  # if buffer is nil and user wants to enter something -- added UNHANDLED
  return :UNHANDLED if @buffer.nil?
  #$log.debug "TA: before: curpos #{@curpos} blen: #{@buffer.length}"
  # on any line if the cursor is ahead of buffer length, ensure its on last position
  # what if the buffer is somehow gt maxlen ??
  if @curpos > @buffer.length
    addcol(@buffer.length-@curpos)+1
    @curpos = @buffer.length
  end
  #$log.debug "TA: after : curpos #{@curpos} blen: #{@buffer.length}, w: #{@width} max #{@maxlen}"
  
  #NOTE C-d being used for del what of scroll !!
  case ch
  when KEY_ENTER, KEY_RETURN, FFI::NCurses::KEY_ENTER # numeric enter
    insert_break
  #when ?\C-u.getbyte(0)
    ## since textareas are editable we use a control key to increase
    ## multiplier. Series is 4 16 64
    #@multiplier = (@multiplier == 0 ? 4 : @multiplier *= 4)
    #return 0
  else
    #$log.debug(" textarea ch #{ch}")
    ret = putc ch
    if ret == :UNHANDLED
      # check for bindings, these cannot override above keys since placed at end
      ret = process_key ch, self
      #$log.debug "TA process_key #{ch} got ret #{ret} in #{@name} "
      return :UNHANDLED if ret == :UNHANDLED
    end
  end
  set_form_row
  set_form_col  # testing 2008-12-26 19:37 
  $multiplier = 0 # reset only if key handled
  return 0
end

#init_actionsObject



952
953
954
955
956
957
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 952

def init_actions
  editor = ENV['EDITOR'] || 'vi'
  am = action_manager()
  am.add_action(Action.new("&Edit in #{editor} ") { edit_external })
  am.add_action(Action.new("&Saveas") { saveas() } )
end

#init_varsObject



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 79

def init_vars
  @repaint_required = true
  @repaint_footer_required = true # 2010-01-23 22:41 
  @toprow = @current_index = @pcol = 0
  @repaint_all=true 
  @row_offset = @col_offset = 0 if @suppress_borders
  @longest_line = 0
  # if borders used, reduce 2 from width else 0
  @internal_width = 2
  @internal_width = 2 if @suppress_borders # WHAT THE !!!! It should be zero
  bind_key(?\M-w, :kill_ring_save)
  bind_key(?\C-y, :yank)
  bind_key(?\M-y, :yank_pop)
  bind_key(?\M-\C-w, :append_next_kill)
  map_keys
end

#insert(off0, data) ⇒ Object

trying to wrap and insert



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 114

def insert off0, data
   _maxlen = @maxlen || @width - @internal_width
  if data.length > _maxlen
    data = wrap_text data
  #  $log.debug "after wrap text done :#{data}"
    data = data.split("\n")
    data[-1] << "\r" #XXXX
  data.each do |row|
    @list.insert off0, row
    off0 += 1
  end
  else
    data << "\r" if data[-1,1] != "\r" #XXXX
    @list.insert off0, data
  end
  # expecting array !! 
  #data.each do |row|
    #@list.insert off0, row
    #off0 += 1
  #end
  #$log.debug " AFTER INSERT: #{@list}"
end

#insert_breakObject

FIXME - fire event not correct, not undo’ing correctly, check row and also slash r append



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 392

def insert_break
  return -1 unless @editable
  # insert a blank row and append rest of this line to cursor
  $log.debug "ENTER PRESSED at  #{@curpos}, on row #{@current_index}"
  @delete_buffer = (delete_eol || "")
  @list[@current_index] << "\r"
  $log.debug "DELETE BUFFER #{@delete_buffer}" 
  @list.insert @current_index+1, @delete_buffer 
  @curpos = 0
  down
  col = @orig_col + @col_offset
  setrowcol @row+1, col
  # FIXME maybe this should be insert line since line inserted, not just data, undo will delete it
  fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :INSERT_LINE, @current_index, @delete_buffer)     #  2008-12-24 18:34 
end

#insert_wrap(lineno, pos, lastchars) ⇒ Object

this attempts to recursively insert into a row, seeing that any stuff exceeding is pushed down further. Yes, it should check for a para end and insert. Currently it could add to next para.



685
686
687
688
689
690
691
692
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 685

def insert_wrap lineno, pos, lastchars
   _maxlen = @maxlen || @width - @internal_width
  @list[lineno].insert pos, lastchars 
  len = @list[lineno].length 
  if len > _maxlen
      push_last_word lineno #- sometime i may push down 10 chars but the last word is less
    end
end

#join_to_prev_lineObject

private when backspace pressed in position zero if the previous line is filled we may have to bring down the last word and join, rather than go up FIXME : make logic simple. Append entire line to above line. Then go to maxlen if not a space, reverse to find last space. Lop off all after space and replace this line with that balance. UNDO and REDO has to work in this case too. FIXME bare in mind handlers when doing this



507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 507

def join_to_prev_line
  return -1 unless @editable
  return if @current_index == 0
  oldcurpos = @curpos
  oldprow = @current_index
  prev = @list[@current_index-1].chomp
  prevlen = prev.length
  # 2008-12-26 21:37 delete previous line if nothing there. This moves entire buffer up.
  if prevlen == 0
    delete_line @current_index-1
    up
    return
  end
  _maxlen = @maxlen || @width - @internal_width
  space_left = _maxlen - prevlen
  # prev line is full exit
  return if space_left == 0

  # get last space, if none, return
  blank_found = @buffer.rindex(' ', space_left)
  return unless blank_found # no word in the space i can carry up.
  # get string for carrying up
  carry_up = @buffer[0..blank_found]
  result = @list[@current_index-1].chomp! # this has to be undone too.
  @list[@current_index-1] << carry_up
  #$log.debug "carry up: #{carry_up} prevrow:#{@list[@current_index -1]}"
  # remove from curr line
  @list[@current_index].slice!(0..carry_up.length-1)
  $log.debug "carry up: #{carry_up} currrow:#{@list[@current_index]}"
  #@list[@current_index] ||= ""
  up
  addrowcol -1,0
  @curpos = prevlen
  # if result not nil, then we need that to be recorded FIXME
  fire_handler :CHANGE, InputDataEvent.new(oldcurpos,oldcurpos+carry_up.length, self, :DELETE, oldprow, carry_up)
  fire_handler :CHANGE, InputDataEvent.new(prevlen,prevlen+carry_up.length, self, :INSERT, oldprow-1, carry_up)

  ## BUG. carry full words up, or if no space then bring down last word of prev lien and join with first
  #carry_up = words_in_length @buffer, space_left #@buffer[0..space_left] # XXX
  #if carry_up.nil?
    ## carry down last word
    #prev_wd = remove_last_word @current_index-1
    ## 2010-01-14 18:26 check added else crashing if C-h pressed with no data in line
    #if !prev_wd.nil?
       #@buffer.insert 0, prev_wd
       #@curpos = prev_wd.length
       #$log.debug " carry up nil! prev_wd (#{prev_wd}) len:#{prev_wd.length}"
       #fire_handler :CHANGE, InputDataEvent.new(0,prev_wd.length, self, :INSERT, oldprow, prev_wd)     #  2008-12-26 23:07 
    #end
  #else
    #$log.debug " carrying up #{carry_up.length} #{carry_up}, space: #{space_left}"
    #@list[@current_index-1]=prev + carry_up
    #space_left2 = @buffer[(carry_up.length+1)..-1]
    #@list[@current_index]=space_left2 #if !space_left2.nil?
    #@list[@current_index] ||= ""
    #up
    #addrowcol -1,0
    #@curpos = prevlen
    #fire_handler :CHANGE, InputDataEvent.new(oldcurpos,carry_up.length, self, :DELETE, oldprow, carry_up)     #  2008-12-24 18:34 
    #fire_handler :CHANGE, InputDataEvent.new(prevlen,carry_up.length, self, :INSERT, oldprow-1, carry_up)     #  2008-12-24 18:34 
  #end
  ## FIXME -- can;t have a naked for reference here.
  ##@form.col = @orig_col + @col_offset + @curpos
  col1 = @orig_col + @col_offset + @curpos
  setrowcol nil, col1 # 2010-02-12 13:09  RFED16

#     $log.debug "carry up: nil" if carry_up.nil?
#     $log.debug "listrow nil " if @list[@current_index].nil?
#     $log.debug "carry up: #{carry_up} prow:#{@list[@current_index]}"
end

#kill_lineObject

mimicking emacs behavior of C-k. delete entire line if at start, else delete till eol



313
314
315
316
317
318
319
320
321
322
323
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 313

def kill_line
    # i'ved added curpos == 0 since emacs deletes a line if cursor is at 0
    # Earlier behavior was based on alpine which leaves a blank line
    if @editable
      if @buffer.chomp == "" || @curpos == 0
        delete_line
      else
        delete_eol 
      end
    end
end

#map_keysObject



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 279

def map_keys
  return if @keys_mapped
  @key_map = :both # get both vim and emacs keys
  require 'rbcurse/core/include/listbindings'
  bindings
  #
  # There's one issue, if using vim keys, most of them won't
  # work in text area. So you will need emacs keys in text area.

  # moved to listbin
  #bind_key(Ncurses::KEY_LEFT){ cursor_backward }
  #bind_key(Ncurses::KEY_RIGHT){ cursor_forward }
  #bind_key(Ncurses::KEY_UP){ ret = up;  get_window.ungetch(KEY_BTAB) if ret == :NO_PREVIOUS_ROW }
  # the next was irritating if user wanted to add a row ! 2011-10-10 
  ##bind_key(Ncurses::KEY_DOWN){ ret = down ; get_window.ungetch(KEY_TAB) if ret == :NO_NEXT_ROW }
  #bind_key(Ncurses::KEY_DOWN){ ret = down ; }

  bind_key(KEY_BACKSPACE){ delete_prev_char if @editable }
  bind_key(KEY_BSPACE){ delete_prev_char if @editable}
  bind_key(?\M-d, :delete_word)
  bind_key(?\M-f, :forward_word)

  # earlier 330
  bind_key(FFI::NCurses::KEY_DC, 'delete current char'){ delete_curr_char if @editable }
  bind_key(?\C-k, 'kill line'){ kill_line }
  bind_key(?\C-_, 'undo'){ undo }
  bind_key(?\C-r, 'redo') { text_redo }
  #bind_key(27){ set_buffer @original_value }
  #bind_key([?\C-x, ?e], :edit_external)
  #bind_key([?\C-x, ?\C-s], :saveas)
  @keys_mapped = true
end

#move_char_upObject

move up one char from next row to current, used when deleting in a line should not be called if line ends in “r”



768
769
770
771
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 768

def move_char_up
  @list[@current_index] << @list[@current_index+1].slice!(0)
  delete_line(@current_index+1) if next_line().length==0
end

#move_chars_upObject

tries to move up as many as possible should not be called if line ends in “r”



774
775
776
777
778
779
780
781
782
783
784
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 774

def move_chars_up
  oldprow = @current_index
  oldcurpos = @curpos
   _maxlen = @maxlen || @width - @internal_width
  space_left = _maxlen - @buffer.length
  can_move = [space_left, next_line.length].min
  carry_up =  @list[@current_index+1].slice!(0, can_move)
  @list[@current_index] << carry_up
  delete_line(@current_index+1) if next_line().length==0
  fire_handler :CHANGE, InputDataEvent.new(oldcurpos,oldcurpos+can_move, self, :INSERT, oldprow, carry_up)     #  2008-12-24 18:34 
end

#next_lineObject

returns next line, does not move to it,



786
787
788
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 786

def next_line
  @list[@current_index+1]
end

#Oinsert(off0, *data) ⇒ Object

this avoids wrapping. Better to use the <<.



101
102
103
104
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 101

def Oinsert off0, *data
  @list.insert off0, *data
  # fire_handler :CHANGE, self  # 2008-12-09 14:56  NOT SURE
end

#old_join_to_prev_lineObject

private when backspace pressed in position zero if the previous line is filled we may have to bring down the last word and join, rather than go up FIXME : make logic simple. Append entire line to above line. Then go to maxlen if not a space, reverse to find last space. Lop off all after space and replace this line with that balance. UNDO and REDO has to work in this case too. FIXME bare in mind handlers when doing this



583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 583

def old_join_to_prev_line
  return -1 unless @editable
  return if @current_index == 0
  oldcurpos = @curpos
  oldprow = @current_index
  prev = @list[@current_index-1].chomp
  prevlen = prev.length
  # 2008-12-26 21:37 delete previous line if nothing there. This moves entire buffer up.
  if prevlen == 0
    delete_line @current_index-1
    up
    return
  end
  _maxlen = @maxlen || @width - @internal_width
  space_left = _maxlen - prev.length
  # BUG. carry full words up, or if no space then bring down last word of prev lien and join with first
  carry_up = words_in_length @buffer, space_left #@buffer[0..space_left] # XXX
  if carry_up.nil?
    # carry down last word
    prev_wd = remove_last_word @current_index-1
    # 2010-01-14 18:26 check added else crashing if C-h pressed with no data in line
    if !prev_wd.nil?
       @buffer.insert 0, prev_wd
       @curpos = prev_wd.length
       $log.debug " carry up nil! prev_wd (#{prev_wd}) len:#{prev_wd.length}"
       fire_handler :CHANGE, InputDataEvent.new(0,prev_wd.length, self, :INSERT, oldprow, prev_wd)     #  2008-12-26 23:07 
    end
  else
    $log.debug " carrying up #{carry_up.length} #{carry_up}, space: #{space_left}"
    @list[@current_index-1]=prev + carry_up
    space_left2 = @buffer[(carry_up.length+1)..-1]
    @list[@current_index]=space_left2 #if !space_left2.nil?
    @list[@current_index] ||= ""
    up
    addrowcol -1,0
    @curpos = prevlen
    fire_handler :CHANGE, InputDataEvent.new(oldcurpos,carry_up.length, self, :DELETE, oldprow, carry_up)     #  2008-12-24 18:34 
    fire_handler :CHANGE, InputDataEvent.new(prevlen,carry_up.length, self, :INSERT, oldprow-1, carry_up)     #  2008-12-24 18:34 
  end
  # FIXME -- can;t have a naked for reference here.
  #@form.col = @orig_col + @col_offset + @curpos
  col1 = @orig_col + @col_offset + @curpos
  setrowcol nil, col1 # 2010-02-12 13:09  RFED16

#     $log.debug "carry up: nil" if carry_up.nil?
#     $log.debug "listrow nil " if @list[@current_index].nil?
#     $log.debug "carry up: #{carry_up} prow:#{@list[@current_index]}"
end

#OLDprint_bordersObject

private



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 182

def OLDprint_borders
  window = @graphic # 2009-12-26 14:54 BUFFERED
  @color_pair = get_color($datacolor) # 2011-09-28 V1.3.1 
  bordercolor = @border_color || @color_pair
  borderatt = @border_attrib || Ncurses::A_NORMAL
  #color = $datacolor
  #window.print_border @row, @col, @height, @width, color
  window.print_border @row, @col, @height-1, @width, bordercolor, borderatt
  print_title
=begin
  hline = "+%s+" % [ "-"*(width-((1)*2)) ]
  hline2 = "|%s|" % [ " "*(width-((1)*2)) ]
  window.printstring( row=startrow, col=startcol, hline, color)
  print_title
  (startrow+1).upto(startrow+height-1) do |row|
    window.printstring(row, col=startcol, hline2, color)
  end
  window.printstring(startrow+height, col=startcol, hline, color)
=end
  
end

#OLDprint_titleObject

private



204
205
206
207
208
209
210
211
212
213
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 204

def OLDprint_title
  # truncate title if longer than width
  return unless @title
  @color_pair ||= get_color($datacolor)
  _title = @title
  if @title.length > @width - 2
    _title = @title[0..@width-2]
  end
  @graphic.printstring( @row, @col+(@width-_title.length)/2, _title, @color_pair, @title_attrib) unless @title.nil?
end

#paintObject



838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 838

def paint
  # not sure where to put this, once for all or repeat 2010-02-12 RFED16
  #my_win = @form? @form.window : @target_window
  #$log.warn "neither form not target window given!!! TA paint 751" unless my_win
  raise "Height or width nil h:#{@height} , w: #{@width} " if @height.nil? || @width.nil?
  print_borders if (@suppress_borders == false && @repaint_all) # do this once only, unless everything changes
  rc = row_count
  _maxlen = @maxlen || @width-@internal_width # TODO fix in other branches remove ||= 
  $log.debug " #{@name} textarea repaint width is #{@width}, height is #{@height} , maxlen #{_maxlen}/ #{@maxlen}, #{@graphic.name} "
  tm = get_content
  tr = @toprow
  acolor = get_color $datacolor
  h = scrollatrow()
  r,c = rowcol
  @longest_line = @width # _maxlen scroll uses width not maxlen
  $log.debug " TA:::: #{tr} , #{h}, r #{r} c #{c} "
  0.upto(h) do |hh|
    crow = tr+hh
    if crow < rc
        #focussed = @current_index == crow ? true : false 
        #selected = is_row_selected crow
      content = tm[crow].chomp rescue ""
        content.gsub!(/\t/, '  ') # don't display tab
        content.gsub!(/[^[:print:]]/, '')  # don't display non print characters
        if !content.nil? 
          if content.length > _maxlen # only show _maxlen
            @longest_line = content.length if content.length > @longest_line
            ## added nil check since we are allowing scrolling in listscrollable anyway 2013-03-06 - 00:14 
            content = content[@pcol..@pcol+_maxlen-1] || " "
          else
            ## added nil check since we are allowing scrolling in listscrollable anyway
            content = content[@pcol..-1] || " "
          end
        end
        #renderer = get_default_cell_renderer_for_class content.class.to_s
        #renderer = cell_renderer()
        #renderer.repaint @form.window, r+hh, c+(colix*11), content, focussed, selected
        #renderer.repaint @form.window, r+hh, c, content, focussed, selected
        @graphic.printstring  r+hh, c, "%-*s" % [@width-@internal_width,content], acolor, @attr
        if @search_found_ix == tr+hh
          if !@find_offset.nil?
            @graphic.mvchgat(y=r+hh, x=c+@find_offset, @find_offset1-@find_offset, Ncurses::A_NORMAL, $reversecolor, nil)
          end
        end

    else
      # clear rows
        # TODO the spaces string can be stored once outside loop
      @graphic.printstring r+hh, c, " " * (@width-@internal_width), acolor,@attr
    end
  end
  show_caret_func

  @table_changed = false
  @repaint_required = false
  @repaint_footer_required = true # 2010-01-23 22:41 
  @repaint_all = false # added 2010-01-14 for redrawing everything
end

text_area print footer



215
216
217
218
219
220
221
222
223
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 215

def print_foot
  @footer_attrib ||= Ncurses::A_REVERSE
  footer = "R: #{@current_index+1}, C: #{@curpos}, #{@list.length} lines  "
  #$log.debug " print_foot calling printstring with #{@row} + #{@height} -1, #{@col}+2"
  # changed 2010-01-02 19:31 BUFFERED we were exceeding 1
  #@graphic.printstring( @row + @height, @col+2, footer, $datacolor, @footer_attrib) 
  @graphic.printstring( @row + @height-1, @col+2, footer, @color_pair || $datacolor, @footer_attrib) 
  @repaint_footer_required = false
end

#push_last_word(lineno = @current_index) ⇒ Object

push the last word from given line to next I have modified it to push all words that are exceeding maxlen. This was needed for if i push 10 chars to next line, and the last word is less then the line will exceed. So i must push as many words as exceed length. 2010-09-07 22:31 this must not return nil, or previous will crash. This happens if no space in line.



649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 649

def push_last_word lineno=@current_index
   _maxlen = @maxlen || @width - @internal_width
  #lastspace = @buffer.rindex(" ")
  #lastspace = @list[lineno].rindex(/ \w/)
  line = @list[lineno]
  line = @list[lineno][0.._maxlen+1] if line.length > _maxlen
  lastspace = line.rindex(/ \w/)
  $log.debug " PUSH:2 #{lastspace},#{line},"
  # fix to ensure something returned 2010-09-07 22:40 
  lastspace = _maxlen-1 unless lastspace # added 2010-09-07 22:29  XXXX

  if !lastspace.nil?
    lastchars = @list[lineno][lastspace+1..-1]
    @list[lineno] = @list[lineno][0..lastspace]
    $log.debug "PUSH_LAST:ls:#{lastspace},lw:#{lastchars},lc:#{lastchars[-1]},:#{@list[lineno]}$"
    if lastchars[-1,1] == "\r" or @list[lineno+1].nil?
      # open a new line and keep the 10 at the end.
      append_row lineno, lastchars
    else
      # check for soft tab \n - NO EVEN THIS LOGIC IS WRONG.
      #if lastchars[-1,1] == "\n"
      if lastchars[-1,1] != ' ' and @list[lineno+1][0,1] !=' '
        #@list[lineno+1].insert 0, lastchars + ' '
        insert_wrap lineno+1, 0, lastchars + ' '
      else
        #@list[lineno+1].insert 0, lastchars 
        insert_wrap lineno+1, 0, lastchars 
      end
    end
    return lastchars, lastspace
  end
  return nil
end

#putc(c) ⇒ Object



746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 746

def putc c
  if c >= 32 and c <= 126
    begin
      ret = putch c.chr
    rescue => ex
      # this does not prevent entry, it prevents updating
      # often comes here if error in event block, not our fault
      Ncurses.beep
      $log.debug " ERROR IN PUTCH RTEXTAREA  "
      $log.debug( ex) if ex
      $log.debug(ex.backtrace.join("\n")) if ex
    end
    if ret == 0
    # addcol 1
      set_modified 
      return 0
    end
  end
  return :UNHANDLED
end

#putch(char) ⇒ Object

add one char. careful, i shoved a string in yesterday.



695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 695

def putch char
   _maxlen = @maxlen || @width - @internal_width
  @buffer ||= @list[@current_index]
  return -1 if !@editable #or @buffer.length >= _maxlen
  #if @chars_allowed != nil # remove useless functionality
    #return if char.match(@chars_allowed).nil?
  #end
  raise "putch expects only one char" if char.length != 1
  oldcurpos = @curpos
  #$log.debug "putch : pr:#{@current_index}, cp:#{@curpos}, char:#{char}, lc:#{@buffer[-1]}, buf:(#{@buffer})"
  if @overwrite_mode
    @buffer[@curpos] = char
  else
    @buffer.insert(@curpos, char)
  end
  @curpos += 1 
  #$log.debug "putch INS: cp:#{@curpos}, max:#{_maxlen}, buf:(#{@buffer.length})"
  if @curpos-1 > _maxlen or @buffer.length()-1 > _maxlen
    lastchars, lastspace = push_last_word @current_index
    #$log.debug "last sapce #{lastspace}, lastchars:#{lastchars},lc:#{lastchars[-1]}, #{@list[@current_index]} "
    ## wrap on word XX If last char is 10 then insert line
    @buffer = @list[@current_index]
    if @curpos-1 > _maxlen  or @curpos-1 > @buffer.length()-1
      ret = down 
      # keep the cursor in the same position in the string that was pushed down.
      @curpos = oldcurpos - lastspace  #lastchars.length # 0
    end
  end
  set_form_row
  @buffer = @list[@current_index]
  set_form_col
  @modified = true
  fire_handler :CHANGE, InputDataEvent.new(oldcurpos,@curpos, self, :INSERT, @current_index, char)     #  2008-12-24 18:34 
  @repaint_required = true
  0
end

#remove_last_word(lineno) ⇒ Object

removes and returns last word in given line number, or nil if no whitespace



732
733
734
735
736
737
738
739
740
741
742
743
744
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 732

def remove_last_word lineno
  @list[lineno].chomp!
  line=@list[lineno]
  lastspace = line.rindex(" ")
  if !lastspace.nil?
    lastchars = line[lastspace+1..-1]
    @list[lineno].slice!(lastspace..-1)
    $log.debug " remove_last: lastspace #{lastspace},#{lastchars},#{@list[lineno]}"
    fire_handler :CHANGE, InputDataEvent.new(lastspace,lastchars.length, self, :DELETE, lineno, lastchars)     #  2008-12-26 23:06 
    return lastchars
  end
  return nil
end

#repaintObject

FOR scrollable ###



270
271
272
273
274
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 270

def repaint # textarea
  #return unless @repaint_required # 2010-02-12 19:08  TRYING - won't let footer print if only col move
  paint if @repaint_required
  print_foot if @print_footer && !@suppress_borders && (@repaint_footer_required || @repaint_required)
end

#row_countObject



835
836
837
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 835

def row_count
  @list.size
end

#rowcolObject



95
96
97
98
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 95

def rowcol
#  $log.debug "textarea rowcol : #{@row+@row_offset+@winrow}, #{@col+@col_offset}"
  return @row+@row_offset, @col+@col_offset
end

#saveas(name = nil, config = {}) ⇒ Object



935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 935

def saveas name=nil, config={}
  unless name
    name = rb_gets "File to save as: "
    return if name.nil? || name == ""
  end
  exists = File.exists? name
  if exists # need to prompt
    return unless rb_confirm("Overwrite existing file? ")
  end
  l = getvalue
  File.open(name, "w"){ |f|
    l.each { |line| f.puts line }
    #l.each { |line| f.write line.gsub(/\r/,"\n") }
  }
  rb_puts "#{name} written."
end

#scrollatrowObject

alias :get_text :to_s —- for listscrollable —- ##



828
829
830
831
832
833
834
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 828

def scrollatrow
  if @suppress_borders
    @height - 1 
  else
    @height - 3 
  end
end

#set_content(lines, config = {}) ⇒ Object

sets content of textarea. I don’t know why this was not existing all this while Name to be consistent with textview. Okay, this does not wrap the words, we assume its short enough. FIXME. Avoid using currently till i firm this. NOTE: does not wrap, and does not trigger events Added on 2011-10-10 Added config for compatibility with textview

Parameters:

  • String (String, Array)

    is an existing filename, Array is content to be replaced

Since:

  • 1.4.0



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 237

def set_content lines, config={}
  case lines
  when String
    if File.exists? lines
      lines = File.open(lines,"r").readlines
    else
      raise "set_content String param should be a filename"
    end
  when Array
  else
    raise "Don't know how to handle data in set_content: #{lines.class} "
  end
  @list.replace lines
  @repaint_required = true
end

#set_form_col(col1 = @curpos) ⇒ Object

set cursor on correct column



408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 408

def set_form_col col1=@curpos
  @curpos = col1
  @cols_panned ||= 0
  cursor_bounds_check
  
  ## added win_col on 2009-12-28 20:21 for embedded forms BUFFERED TRYING OUT
  win_col = 0 # 2010-02-07 23:19 new cursor stuff
  #col = win_col + @orig_col + @col_offset + @curpos
  #col = win_col + @orig_col + @col_offset + @curpos + @cols_panned
  # 2010-01-14 13:31 changed orig_col to col for embedded forms, splitpanes.
  col = win_col + @col + @col_offset + @curpos + @cols_panned
  $log.debug "sfc: wc:#{win_col}  col:#{@col}, coff:#{@col_offset}. cp:#{@curpos} colsp:#{@cols_panned} . "
  #@form.setrowcol @form.row, col   # added 2009-12-29 18:50 BUFFERED
  $log.debug " TA calling setformrow col nil, #{col} "
  setrowcol nil, col   # added 2009-12-29 18:50 BUFFERED
  @repaint_footer_required = true
end

#set_modified(tf = true) ⇒ Object



795
796
797
798
799
800
801
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 795

def set_modified tf=true
  @modified = tf
  @repaint_required = tf
  @repaint_footer_required = tf
  # 2010-01-14 22:45 putting a check for form, so not necessary to have form set when appending data
  @form.modified = true if tf and !@form.nil?
end

#text(*val) ⇒ Object

alias :text :set_content set text Added for consistency with other widgets



255
256
257
258
259
260
261
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 255

def text(*val)
  if val.empty?
    return @list
  end
  set_content(*val)
  self
end

#text=(val) ⇒ Object



262
263
264
265
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 262

def text=(val)
  return unless val # added 2010-11-17 20:11, dup will fail on nil
  set_content(val)
end

#text_redoObject



913
914
915
916
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 913

def text_redo
  return unless @undo_handler
  @undo_handler.redo
end

#undoObject



906
907
908
909
910
911
912
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 906

def undo
  if @undo_handler
    @undo_handler.undo
  else
    undo_delete
  end
end

#undo_deleteObject

this is broken, delete_buffer could be a line or a string or array of lines



375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 375

def undo_delete
    # added 2008-11-27 12:43  paste delete buffer into insertion point
    return if @delete_buffer.nil?
    $log.warn "undo_delete is broken! perhaps cannot be used . textarea 347 "
    # FIXME - can be an array
    case @delete_buffer
    when Array
      # we need to unroll array, and it could be lines not just a string
      str = @delete_buffer.first
    else
      str = @delete_buffer
    end
    @buffer.insert @curpos, str 
    set_modified 
    fire_handler :CHANGE, InputDataEvent.new(@curpos,@curpos+@delete_buffer.length, self, :INSERT, @current_index, @delete_buffer)     #  2008-12-24 18:34 
end

#words_in_length(buff, len) ⇒ Object

return as many words as fit into len for carrying up.. actually there is a case of when the next char (len+1) is a white space or word boundary. XXX



634
635
636
637
638
639
640
641
642
643
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 634

def words_in_length buff, len
  return nil if len == 0
  str = buff[0..len]
  ix = str.rindex(/\s/)
  $log.debug " str #{str} len #{len} ix #{ix} , buff #{buff}~"
  return nil if ix.nil?
  ix = ix > 0 ? ix - 1 : ix
  $log.debug " str[]:#{str[0..ix]}~ len #{len} ix #{ix} , buff #{buff}~"
  return str[0..ix]
end

#wrap_para(line = @current_index) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 162

def wrap_para line=@current_index
  line ||= 0
  l=[]
  while true
    if @list[line].nil? or @list[line]=="" or @list[line]==13 #"\r"
      break
    end
    #$log.debug "lastchar #{@list[line][-1]}, appending: #{@list[line]}]"
    t =  @list[line]
    l << t.strip
    @list.delete_at line
    break if t[-1]==13 # "\r"
#    line += 1
  end
  str=l.join(" ")
  #$log.debug " sending insert : #{str}."
  insert line, str
end

#wrap_text(txt, col = @maxlen) ⇒ Object

private



106
107
108
109
110
111
# File 'lib/rbcurse/core/widgets/rtextarea.rb', line 106

def wrap_text(txt, col = @maxlen)
   col ||= @width - @internal_width
  #$log.debug "inside wrap text for :#{txt}"
  txt.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/,
           "\\1\\3\n") 
end