rbcurse-core 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/README.md +69 -0
  2. data/VERSION +1 -0
  3. data/examples/abasiclist.rb +151 -0
  4. data/examples/alpmenu.rb +46 -0
  5. data/examples/app.sample +17 -0
  6. data/examples/atree.rb +100 -0
  7. data/examples/common/file.rb +45 -0
  8. data/examples/data/README.markdown +9 -0
  9. data/examples/data/brew.txt +38 -0
  10. data/examples/data/color.2 +37 -0
  11. data/examples/data/gemlist.txt +60 -0
  12. data/examples/data/lotr.txt +12 -0
  13. data/examples/data/ports.txt +136 -0
  14. data/examples/data/table.txt +37 -0
  15. data/examples/data/tasks.csv +88 -0
  16. data/examples/data/tasks.txt +27 -0
  17. data/examples/data/todo.txt +10 -0
  18. data/examples/data/todocsv.csv +28 -0
  19. data/examples/data/unix1.txt +21 -0
  20. data/examples/data/unix2.txt +11 -0
  21. data/examples/dbdemo.rb +487 -0
  22. data/examples/dirtree.rb +90 -0
  23. data/examples/newtabbedwindow.rb +100 -0
  24. data/examples/newtesttabp.rb +92 -0
  25. data/examples/tabular.rb +132 -0
  26. data/examples/tasks.rb +167 -0
  27. data/examples/term2.rb +83 -0
  28. data/examples/testkeypress.rb +72 -0
  29. data/examples/testlistbox.rb +158 -0
  30. data/examples/testmessagebox.rb +140 -0
  31. data/examples/testree.rb +106 -0
  32. data/examples/testwsshortcuts.rb +66 -0
  33. data/examples/testwsshortcuts2.rb +127 -0
  34. data/lib/rbcurse.rb +8 -0
  35. data/lib/rbcurse/core/docs/index.txt +73 -0
  36. data/lib/rbcurse/core/include/action.rb +40 -0
  37. data/lib/rbcurse/core/include/appmethods.rb +112 -0
  38. data/lib/rbcurse/core/include/bordertitle.rb +41 -0
  39. data/lib/rbcurse/core/include/chunk.rb +182 -0
  40. data/lib/rbcurse/core/include/io.rb +953 -0
  41. data/lib/rbcurse/core/include/listcellrenderer.rb +140 -0
  42. data/lib/rbcurse/core/include/listeditable.rb +317 -0
  43. data/lib/rbcurse/core/include/listscrollable.rb +590 -0
  44. data/lib/rbcurse/core/include/listselectable.rb +264 -0
  45. data/lib/rbcurse/core/include/multibuffer.rb +83 -0
  46. data/lib/rbcurse/core/include/orderedhash.rb +77 -0
  47. data/lib/rbcurse/core/include/ractionevent.rb +67 -0
  48. data/lib/rbcurse/core/include/rchangeevent.rb +27 -0
  49. data/lib/rbcurse/core/include/rhistory.rb +62 -0
  50. data/lib/rbcurse/core/include/rinputdataevent.rb +47 -0
  51. data/lib/rbcurse/core/include/vieditable.rb +170 -0
  52. data/lib/rbcurse/core/system/colormap.rb +163 -0
  53. data/lib/rbcurse/core/system/keyboard.rb +150 -0
  54. data/lib/rbcurse/core/system/keydefs.rb +30 -0
  55. data/lib/rbcurse/core/system/ncurses.rb +218 -0
  56. data/lib/rbcurse/core/system/panel.rb +162 -0
  57. data/lib/rbcurse/core/system/window.rb +901 -0
  58. data/lib/rbcurse/core/util/ansiparser.rb +117 -0
  59. data/lib/rbcurse/core/util/app.rb +1235 -0
  60. data/lib/rbcurse/core/util/basestack.rb +407 -0
  61. data/lib/rbcurse/core/util/bottomline.rb +1850 -0
  62. data/lib/rbcurse/core/util/colorparser.rb +71 -0
  63. data/lib/rbcurse/core/util/focusmanager.rb +31 -0
  64. data/lib/rbcurse/core/util/padreader.rb +189 -0
  65. data/lib/rbcurse/core/util/rcommandwindow.rb +587 -0
  66. data/lib/rbcurse/core/util/rdialogs.rb +619 -0
  67. data/lib/rbcurse/core/util/viewer.rb +149 -0
  68. data/lib/rbcurse/core/util/widgetshortcuts.rb +505 -0
  69. data/lib/rbcurse/core/widgets/applicationheader.rb +102 -0
  70. data/lib/rbcurse/core/widgets/box.rb +58 -0
  71. data/lib/rbcurse/core/widgets/divider.rb +310 -0
  72. data/lib/rbcurse/core/widgets/keylabelprinter.rb +178 -0
  73. data/lib/rbcurse/core/widgets/rcombo.rb +238 -0
  74. data/lib/rbcurse/core/widgets/rcontainer.rb +415 -0
  75. data/lib/rbcurse/core/widgets/rlink.rb +30 -0
  76. data/lib/rbcurse/core/widgets/rlist.rb +723 -0
  77. data/lib/rbcurse/core/widgets/rmenu.rb +939 -0
  78. data/lib/rbcurse/core/widgets/rmenulink.rb +22 -0
  79. data/lib/rbcurse/core/widgets/rmessagebox.rb +373 -0
  80. data/lib/rbcurse/core/widgets/rprogress.rb +118 -0
  81. data/lib/rbcurse/core/widgets/rtabbedpane.rb +615 -0
  82. data/lib/rbcurse/core/widgets/rtabbedwindow.rb +68 -0
  83. data/lib/rbcurse/core/widgets/rtextarea.rb +920 -0
  84. data/lib/rbcurse/core/widgets/rtextview.rb +780 -0
  85. data/lib/rbcurse/core/widgets/rtree.rb +787 -0
  86. data/lib/rbcurse/core/widgets/rwidget.rb +3040 -0
  87. data/lib/rbcurse/core/widgets/scrollbar.rb +143 -0
  88. data/lib/rbcurse/core/widgets/statusline.rb +94 -0
  89. data/lib/rbcurse/core/widgets/tabular.rb +264 -0
  90. data/lib/rbcurse/core/widgets/tabularwidget.rb +1211 -0
  91. data/lib/rbcurse/core/widgets/textpad.rb +516 -0
  92. data/lib/rbcurse/core/widgets/tree/treecellrenderer.rb +150 -0
  93. data/lib/rbcurse/core/widgets/tree/treemodel.rb +428 -0
  94. metadata +156 -0
@@ -0,0 +1,264 @@
1
+ # File created: 2010-10-29 14:09
2
+ # Author : rkumar
3
+ #
4
+ # this is a new, simpler version of listselectable
5
+ # the original gets into models and has complicated operation as well
6
+ # as difficult to remember method names. This attempts to be a simple plugin.
7
+ # Currently being used by rbasiclistbox (rlist) and now tabularwidget.
8
+ # NOTE: pls define @_header_adjustment to 0 if you don't use it or know what it means.
9
+ # TODO: of course we need to fire events so user can do something.
10
+ module RubyCurses
11
+ module NewListSelectable
12
+
13
+ # @group selection related
14
+
15
+ # change selection of current row on pressing space bar
16
+ # If mode is multiple, then other selections are cleared and this is added
17
+ # @example
18
+ # bind_key(32) { toggle_row_selection }
19
+ # current_index is not account for header_adjustment
20
+ # if current row is selected in mulitple we should deselect ?? FIXME
21
+ def toggle_row_selection crow=@current_index-@_header_adjustment
22
+ @last_clicked = crow
23
+ @repaint_required = true
24
+ case @selection_mode
25
+ when :multiple
26
+ @widget_scrolled = true # FIXME we need a better name
27
+ if @selected_indices.include? crow
28
+ @selected_indices.delete crow
29
+ lse = ListSelectionEvent.new(crow, crow, self, :DELETE)
30
+ fire_handler :LIST_SELECTION_EVENT, lse
31
+ else
32
+ @selected_indices << crow
33
+ lse = ListSelectionEvent.new(crow, crow, self, :INSERT)
34
+ fire_handler :LIST_SELECTION_EVENT, lse
35
+ end
36
+ else
37
+ if @selected_index == crow
38
+ @old_selected_index = @selected_index # 2011-10-15 so we can unhighlight
39
+ @selected_index = nil
40
+ lse = ListSelectionEvent.new(crow, crow, self, :DELETE)
41
+ fire_handler :LIST_SELECTION_EVENT, lse
42
+ else
43
+ @old_selected_index = @selected_index # 2011-10-15 so we can unhighlight
44
+ @selected_index = crow
45
+ lse = ListSelectionEvent.new(crow, crow, self, :INSERT)
46
+ fire_handler :LIST_SELECTION_EVENT, lse
47
+ end
48
+ end
49
+ end
50
+ #
51
+ # Only for multiple mode.
52
+ # add an item to selection, if selection mode is multiple
53
+ # if item already selected, it is deselected, else selected
54
+ # typically bound to Ctrl-Space
55
+ # @example
56
+ # bind_key(0) { add_to_selection }
57
+ def add_to_selection crow=@current_index-@_header_adjustment
58
+ @last_clicked ||= crow
59
+ min = [@last_clicked, crow].min
60
+ max = [@last_clicked, crow].max
61
+ case @selection_mode
62
+ when :multiple
63
+ @widget_scrolled = true # FIXME we need a better name
64
+ if @selected_indices.include? crow
65
+ # delete from last_clicked until this one in any direction
66
+ min.upto(max){ |i| @selected_indices.delete i }
67
+ lse = ListSelectionEvent.new(min, max, self, :DELETE)
68
+ fire_handler :LIST_SELECTION_EVENT, lse
69
+ else
70
+ # add to selection from last_clicked until this one in any direction
71
+ min.upto(max){ |i| @selected_indices << i unless @selected_indices.include?(i) }
72
+ lse = ListSelectionEvent.new(min, max, self, :INSERT)
73
+ fire_handler :LIST_SELECTION_EVENT, lse
74
+ end
75
+ else
76
+ end
77
+ @repaint_required = true
78
+ self
79
+ end
80
+ # clears selected indices, typically called when multiple select
81
+ # Key binding is application specific
82
+ def clear_selection
83
+ return if @selected_indices.nil? || @selected_indices.empty?
84
+ @selected_indices = []
85
+ @selected_index = nil
86
+ @old_selected_index = nil
87
+ # Not sure what event type I should give, DELETE or a new one, user should
88
+ # understand that selection has been cleared, and ignore first two params
89
+ lse = ListSelectionEvent.new(0, @list.size, self, :CLEAR)
90
+ fire_handler :LIST_SELECTION_EVENT, lse
91
+ @repaint_required = true
92
+ @widget_scrolled = true # FIXME we need a better name
93
+ end
94
+ def is_row_selected crow=@current_index-@_header_adjustment
95
+ case @selection_mode
96
+ when :multiple
97
+ @selected_indices.include? crow
98
+ else
99
+ crow == @selected_index
100
+ end
101
+ end
102
+ alias :is_selected? is_row_selected
103
+ # FIXME add adjustment and test
104
+ def goto_next_selection
105
+ return if selected_rows().length == 0
106
+ row = selected_rows().sort.find { |i| i > @current_index }
107
+ row ||= @current_index
108
+ @current_index = row
109
+ @repaint_required = true # fire list_select XXX
110
+ end
111
+ # FIXME add adjustment and test
112
+ def goto_prev_selection
113
+ return if selected_rows().length == 0
114
+ row = selected_rows().sort{|a,b| b <=> a}.find { |i| i < @current_index }
115
+ row ||= @current_index
116
+ @current_index = row
117
+ @repaint_required = true # fire list_select XXX
118
+ end
119
+ # add the following range to selected items, unless already present
120
+ # should only be used if multiple selection interval
121
+ def add_selection_interval ix0, ix1
122
+ return if @selection_mode != :multiple
123
+ @widget_scrolled = true # FIXME we need a better name
124
+ @anchor_selection_index = ix0
125
+ @lead_selection_index = ix1
126
+ ix0.upto(ix1) {|i| @selected_indices << i unless @selected_indices.include? i }
127
+ lse = ListSelectionEvent.new(ix0, ix1, self, :INSERT)
128
+ fire_handler :LIST_SELECTION_EVENT, lse
129
+ #$log.debug " DLSM firing LIST_SELECTION EVENT #{lse}"
130
+ end
131
+ alias :add_row_selection_interval :add_selection_interval
132
+ def remove_selection_interval ix0, ix1
133
+ @anchor_selection_index = ix0
134
+ @lead_selection_index = ix1
135
+ @selected_indices.delete_if {|x| x >= ix0 and x <= ix1}
136
+ lse = ListSelectionEvent.new(ix0, ix1, self, :DELETE)
137
+ fire_handler :LIST_SELECTION_EVENT, lse
138
+ end
139
+ alias :remove_row_selection_interval :remove_selection_interval
140
+ # convenience method to select next len rows
141
+ def insert_index_interval ix0, len
142
+ @anchor_selection_index = ix0
143
+ @lead_selection_index = ix0+len
144
+ add_selection_interval @anchor_selection_index, @lead_selection_index
145
+ end
146
+ # select all rows, you may specify starting row.
147
+ # if header row, then 1 else should be 0. Actually we should have a way to determine
148
+ # this, and the default should be zero.
149
+ def select_all start_row=0 #+@_header_adjustment
150
+ @repaint_required = true
151
+ # don't select header row - need to make sure this works for all cases. we may
152
+ # need a variable instead of hardoded value
153
+ add_row_selection_interval start_row, row_count()
154
+ end
155
+ def invert_selection start_row=0 #+@_header_adjustment
156
+ start_row.upto(row_count()){|i| invert_row_selection i }
157
+ end
158
+
159
+ def invert_row_selection row=@current_index-@_header_adjustment
160
+ @repaint_required = true
161
+ if is_selected? row
162
+ remove_row_selection_interval(row, row)
163
+ else
164
+ add_row_selection_interval(row, row)
165
+ end
166
+ end
167
+ # selects all rows with the values given, leaving existing selections
168
+ # intact. Typically used after accepting search criteria, and getting a list of values
169
+ # to select (such as file names). Will not work with tables (array or array)
170
+ def select_values values
171
+ return unless values
172
+ values.each do |val|
173
+ row = @list.index val
174
+ add_row_selection_interval row, row unless row.nil?
175
+ end
176
+ end
177
+ # unselects all rows with the values given, leaving all other rows intact
178
+ # You can map "-" to ask_select and call this from there.
179
+ # bind_key(?+, :ask_select) # --> calls select_values
180
+ # bind_key(?-, :ask_unselect)
181
+ def unselect_values values
182
+ return unless values
183
+ values.each do |val|
184
+ row = @list.index val
185
+ remove_row_selection_interval row, row unless row.nil?
186
+ end
187
+ end
188
+ # please override this, this is just very basic and default
189
+ # Please implement get_matching_indices(String).
190
+ def ask_select prompt="Enter selection pattern: "
191
+ ret = ask(prompt, String) {|q| yield q if block_given? }
192
+ return if ret.nil? || ret == ""
193
+ indices = get_matching_indices ret
194
+ return if indices.nil? || indices.empty?
195
+ indices.each { |e|
196
+ # will not work if single select !! FIXME
197
+ add_row_selection_interval e,e
198
+ }
199
+ @repaint_required = true
200
+ end
201
+ def get_matching_indices pattern
202
+ alert "please implement this method get_matching_indices(pattern)->[] in your class "
203
+ return []
204
+ end # mod
205
+ # Applications may call this or just copy and modify
206
+ def list_bindings
207
+ # what about users wanting 32 and ENTER to also go to next row automatically
208
+ # should make that optional, TODO
209
+ bind_key(32, 'toggle selection') { toggle_row_selection }
210
+ bind_key(0, 'range select') { add_to_selection }
211
+ bind_key(?+, :ask_select) # --> calls select_values
212
+ bind_key(?-, :ask_unselect) # please implement FIXME TODO
213
+ bind_key(?a, :select_all)
214
+ bind_key(?*, :invert_selection)
215
+ bind_key(?u, :clear_selection)
216
+ @_header_adjustment ||= 0 # incase caller does not use
217
+ @_events << :LIST_SELECTION_EVENT unless @_events.include? :LIST_SELECTION_EVENT
218
+ end
219
+ def list_init_vars
220
+ @selected_indices = []
221
+ @selected_index = nil
222
+ @old_selected_index = nil
223
+ #@row_selected_symbol = ''
224
+ if @show_selector
225
+ @row_selected_symbol ||= '*'
226
+ @row_unselected_symbol ||= ' '
227
+ @left_margin ||= @row_selected_symbol.length
228
+ end
229
+ end
230
+ # paint the selector. Called from repaint, prior to printing data row
231
+ # remember to set left_margin at top of repaint method as:
232
+ # @left_margin ||= @row_selected_symbol.length
233
+ def paint_selector crow, r, c, acolor, attrib
234
+ selected = is_row_selected crow
235
+ selection_symbol = ''
236
+ if @show_selector
237
+ if selected
238
+ selection_symbol = @row_selected_symbol
239
+ else
240
+ selection_symbol = @row_unselected_symbol
241
+ end
242
+ @graphic.printstring r, c, selection_symbol, acolor,attrib
243
+ end
244
+ end
245
+ def selected_rows
246
+ @selected_indices
247
+ end
248
+ end # mod
249
+ class ListSelectionEvent
250
+ attr_accessor :firstrow, :lastrow, :source, :type
251
+ def initialize firstrow, lastrow, source, type
252
+ @firstrow = firstrow
253
+ @lastrow = lastrow
254
+ @source = source
255
+ @type = type
256
+ end
257
+ def to_s
258
+ "#{@type.to_s}, firstrow: #{@firstrow}, lastrow: #{@lastrow}, source: #{@source}"
259
+ end
260
+ def inspect
261
+ to_s
262
+ end
263
+ end
264
+ end # mod
@@ -0,0 +1,83 @@
1
+ module RubyCurses
2
+ # this module makes it possible for a textview to maintain multiple buffers
3
+ # The first buffer has been placed using set_content(lines, config).
4
+ # After this, additional buffers mst be supplied with add_content text, config.
5
+ # Also, please note that after you call set_content the first time, you must call
6
+ # add_content so the buffer can be accessed while cycling. will try to fix this.
7
+ # (I don't want to touch textview, would prefer not to write a decorator).
8
+
9
+ # TODO allow setting of a limit, so in some cases where we keep adding
10
+ # programatically, the
11
+ module MultiBuffers
12
+ extend self
13
+
14
+ # add content to buffers of a textview
15
+ # @param [Array] text
16
+ # @param [Hash] options, typically :content_type => :ansi or :tmux
17
+ def add_content text, config={}
18
+ unless @_buffers
19
+ bind_key(?\M-n, :buffer_next)
20
+ bind_key(?\M-p, :buffer_prev)
21
+ bind_key(KEY_BACKSPACE, :buffer_prev) # backspace, already hardcoded in textview !
22
+ bind_key(?:, :buffer_menu)
23
+ end
24
+ @_buffers ||= []
25
+ @_buffers_conf ||= []
26
+ @_buffers << text
27
+ @_buffers_conf << config
28
+ @_buffer_ctr ||= 0
29
+ $log.debug "XXX: HELP adding text #{@_buffers.size} "
30
+ end
31
+
32
+ # display next buffer
33
+ def buffer_next
34
+ @_buffer_ctr += 1
35
+ x = @_buffer_ctr
36
+ l = @_buffers[x]
37
+ @_buffer_ctr = 0 unless l
38
+ set_content @_buffers[@_buffer_ctr], @_buffers_conf[@_buffer_ctr]
39
+ end
40
+ #
41
+ # display previous buffer if any
42
+ def buffer_prev
43
+ if @_buffer_ctr < 1
44
+ buffer_last
45
+ return
46
+ end
47
+ @_buffer_ctr -= 1 if @_buffer_ctr > 0
48
+ x = @_buffer_ctr
49
+ l = @_buffers[x]
50
+ if l
51
+ set_content l, @_buffers_conf[x]
52
+ end
53
+ end
54
+ def buffer_last
55
+ @_buffer_ctr = @_buffers.count - 1
56
+ l = @_buffers.last
57
+ set_content l, @_buffers_conf.last
58
+ end
59
+ # close window, a bit clever
60
+ def close
61
+ @graphic.ungetch(?q.ord)
62
+ end
63
+ # display a menu so user can do buffer management
64
+ # However, how can application add to these. Or disable, such as when we
65
+ # add buffer delete or buffer insert or edit
66
+ def buffer_menu
67
+ menu = PromptMenu.new self do
68
+ item :n, :buffer_next
69
+ item :p, :buffer_prev
70
+ item :b, :scroll_backward
71
+ item :f, :scroll_forward
72
+ item :q, :close
73
+ submenu :m, "submenu..." do
74
+ item :p, :goto_last_position
75
+ item :r, :scroll_right
76
+ item :l, :scroll_left
77
+ end
78
+ end
79
+ menu.display_new :title => "Buffer Menu"
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,77 @@
1
+ ## Insert order preserving hash
2
+ # Thanks to Bill Kelly, posted on http://www.ruby-forum.com/topic/166075
3
+ #
4
+ class OrderedHash
5
+ include Enumerable
6
+
7
+ def initialize(*args, &block)
8
+ @h = Hash.new(*args, &block)
9
+ @ordered_keys = []
10
+ end
11
+
12
+ def []=(key, val)
13
+ @ordered_keys << key unless @h.has_key? key
14
+ @h[key] = val
15
+ end
16
+
17
+ def each
18
+ @ordered_keys.each {|k| yield(k, @h[k])}
19
+ end
20
+ alias :each_pair :each
21
+
22
+ def each_value
23
+ @ordered_keys.each {|k| yield(@h[k])}
24
+ end
25
+
26
+ def each_key
27
+ @ordered_keys.each {|k| yield k}
28
+ end
29
+
30
+ def keys
31
+ @ordered_keys
32
+ end
33
+
34
+ def values
35
+ @ordered_keys.map {|k| @h[k]}
36
+ end
37
+
38
+ def clear
39
+ @ordered_keys.clear
40
+ @h.clear
41
+ end
42
+
43
+ def delete(k, &block)
44
+ @ordered_keys.delete k
45
+ @h.delete(k, &block)
46
+ end
47
+
48
+ def reject!
49
+ del = []
50
+ each_pair {|k,v| del << k if yield k,v}
51
+ del.each {|k| delete k}
52
+ del.empty? ? nil : self
53
+ end
54
+
55
+ def delete_if(&block)
56
+ reject!(&block)
57
+ self
58
+ end
59
+ ## added since the normal hash will give it in unordered. so debugging sucks
60
+ def inspect
61
+ out = []
62
+ each do | k,v |
63
+ out << " #{k} => #{v} "
64
+ end
65
+ res = %Q[ { #{out.join(",\n ")} } ]
66
+ end
67
+
68
+ %w(merge!).each do |name|
69
+ define_method(name) do |*args|
70
+ raise NotImplementedError, "#{name} not implemented"
71
+ end
72
+ end
73
+
74
+ def method_missing(*args)
75
+ @h.send(*args)
76
+ end
77
+ end
@@ -0,0 +1,67 @@
1
+ =begin
2
+ * Name: ActionEvent
3
+ * Description: Event used to notify interested parties that an action has happened on component
4
+ Usually a button press. Nothing more.
5
+ * Author: rkumar (arunachalesha)
6
+
7
+ --------
8
+ * Date: 2010-09-12 18:53
9
+ * License:
10
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
11
+
12
+ =end
13
+
14
+ # Event created when state changed (as in ViewPort)
15
+ module RubyCurses
16
+ # source - as always is the object whose event has been fired
17
+ # id - event identifier (seems redundant since we bind events often separately.
18
+ # event - is :PRESS
19
+ # action_command - command string associated with event (such as title of button that changed
20
+ ActionEvent = Struct.new(:source, :event, :action_command) do
21
+ # This should always return the most relevant text associated with this object
22
+ # so the user does not have to go through the source object's documentation.
23
+ # It should be a user-friendly string
24
+ # @return text associated with source (label of button)
25
+ def text
26
+ source.text
27
+ end
28
+
29
+ # This is similar to text and can often be just an alias.
30
+ # However, i am putting this for backward compatibility with programs
31
+ # that received the object and called it's getvalue. It is better to use text.
32
+ # @return text associated with source (label of button)
33
+ def getvalue
34
+ source.getvalue
35
+ end
36
+ end
37
+ # a derivative of Action Event for textviews
38
+ # We allow a user to press ENTER on a row and use that for processing.
39
+ # We are basically using TextView as a list in which user can scroll around
40
+ # and move cursor at will.
41
+ class TextActionEvent < ActionEvent
42
+ # current_index or line number starting 0
43
+ attr_accessor :current_index
44
+ # cursor position on the line
45
+ attr_accessor :curpos
46
+ def initialize source, event, action_command, current_index, curpos
47
+ super source, event, action_command
48
+ @current_index = current_index
49
+ @curpos = curpos
50
+ end
51
+ # the text of the line on which the user is
52
+ def text
53
+ source.current_value.to_s
54
+ end
55
+ # the word under the cursor TODO
56
+ # if its a text with pipe delim, then ??
57
+ def word_under_cursor line=text(), pos=@curpos, delim=" "
58
+ line ||= text()
59
+ pos ||= @curpos
60
+ finish = line.index(delim, pos)
61
+ start = line.rindex(delim,pos)
62
+ finish = -1 if finish.nil?
63
+ start = 0 if start.nil?
64
+ return line[start..finish]
65
+ end
66
+ end
67
+ end