Class: Canis::TextArea

Inherits:
Widget show all
Includes:
ListScrollable, ListEditable
Defined in:
lib/canis/core/widgets/extras/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, #config, #curpos, #focussed, #form, #handler, #id, #key_label, #parent_component, #row_offset, #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, #bgcolor, #color, #color_pair, #command, #destroy, #focus, #focusable, #focusable?, #getvalue_for_paint, #hide, #modified?, #move, #on_enter, #on_leave, #override_graphic, #process_key, #property_set, #remove, #repaint_all, #repaint_required, #set_form, #set_form_row, #setformrowcol, #setrowcol, #show, #unbind_key

Methods included from Io

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

Methods included from Utils

#ORIG_process_key, #ORIGbind_key, #ORIGkeycode_tos, #_process_key, #bind_composite_mapping, #bind_key, #bind_keys, #check_composite_mapping, #create_logger, #define_key, #define_prefix_command, #execute_mapping, #get_attrib, #get_color, #key, #key_tos, #print_key_bindings, #repeatm, #run_command, #shell_out, #shell_output, #suspend, #view, #xxxbind_composite_mapping

Methods included from ConfigSetup

#config_setup, #variable_set

Methods included from EventHandler

#bind, #event?, #event_list, #fire_handler, #fire_property_change, #register_events

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/canis/core/widgets/extras/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/canis/core/widgets/extras/rtextarea.rb', line 51

def overwrite_mode
  @overwrite_mode
end

#toprowObject (readonly)

Returns the value of attribute toprow.



46
47
48
# File 'lib/canis/core/widgets/extras/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/canis/core/widgets/extras/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.



474
475
476
477
478
479
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 474

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



480
481
482
483
484
485
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 480

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



898
899
900
901
902
903
904
905
906
907
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 898

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)


458
459
460
461
462
463
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 458

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)


466
467
468
469
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 466

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

#buffer_lenObject



430
431
432
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 430

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

#current_lineObject



790
791
792
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 790

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



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

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



808
809
810
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 808

def cursor_bol
  set_form_col 0
end

#cursor_bounds_checkObject



426
427
428
429
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 426

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

#cursor_eolObject



803
804
805
806
807
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 803

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.



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

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:

  • ()


433
434
435
436
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 433

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

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

Yields:

  • ()


793
794
795
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 793

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

#edit_externalObject



920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 920

def edit_external
  require 'canis/core/include/appmethods'
  require 'tempfile'
  f = Tempfile.new("canis")
  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/canis/core/widgets/extras/rtextarea.rb', line 225

def get_content
  @list
end

#get_textObject

def to_s this was just annoying in debugs



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

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/canis/core/widgets/extras/rtextarea.rb', line 266

def get_window
  @graphic
end

#getvalueObject



276
277
278
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 276

def getvalue
  @list
end

#handle_key(ch) ⇒ Object

textarea



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
374
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 327

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



954
955
956
957
958
959
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 954

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/canis/core/widgets/extras/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/canis/core/widgets/extras/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



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

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.



686
687
688
689
690
691
692
693
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 686

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



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
577
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 508

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



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

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



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
311
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 280

def map_keys
  return if @keys_mapped
  @key_map = :both # get both vim and emacs keys
  require 'canis/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”



769
770
771
772
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 769

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”



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

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,



787
788
789
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 787

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/canis/core/widgets/extras/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



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
631
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 584

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/canis/core/widgets/extras/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/canis/core/widgets/extras/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



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
896
897
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 839

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?
  raise "graphic is nil in textarea paint()" unless @graphic
  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/canis/core/widgets/extras/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.



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
682
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 650

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



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

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.



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
731
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 696

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



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

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
275
# File 'lib/canis/core/widgets/extras/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
  @graphic = @form.window unless @graphic # print_border not getting it 2014-08-30 - 20:41 
  paint if @repaint_required
  print_foot if @print_footer && !@suppress_borders && (@repaint_footer_required || @repaint_required)
end

#row_countObject



836
837
838
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 836

def row_count
  @list.size
end

#rowcolObject



95
96
97
98
# File 'lib/canis/core/widgets/extras/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



937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 937

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 —- ##



829
830
831
832
833
834
835
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 829

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/canis/core/widgets/extras/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



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

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



796
797
798
799
800
801
802
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 796

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/canis/core/widgets/extras/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/canis/core/widgets/extras/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



915
916
917
918
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 915

def text_redo
  return unless @undo_handler
  @undo_handler.redo
end

#undoObject



908
909
910
911
912
913
914
# File 'lib/canis/core/widgets/extras/rtextarea.rb', line 908

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



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

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



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

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/canis/core/widgets/extras/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/canis/core/widgets/extras/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