fxirb 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (8) hide show
  1. data/CHANGELOG +47 -0
  2. data/Manifest.txt +7 -0
  3. data/TODO +6 -0
  4. data/bin/fxirb +15 -0
  5. data/lib/fxirb.rb +482 -0
  6. data/rakefile +13 -0
  7. data/setup.rb +1585 -0
  8. metadata +59 -0
@@ -0,0 +1,47 @@
1
+ 0.3.1 - Martin DeMello - 2006/12/21
2
+ * Fallback chain for requiring fxruby
3
+ * Packaged as a gem
4
+
5
+ 0.3 - Martin DeMello - 2006/12/17
6
+ * Code cleanups:
7
+ - Removed Fox:: from keynames
8
+ - added FxEvent#ctrl? and FxEvent#shift?
9
+ - moved FxText method calls outside the onKeyPress function
10
+ - changed a bunch of methods from camelcase to underscores
11
+ - public and private methods marked off clearly
12
+ * Bugfixes
13
+ - {Ctrl, Shift}-{backspace, del} not passed through to FxText
14
+ - Ctrl-D only exits if the current line is empty
15
+ - Lots of fixes for multiline input
16
+ * Features
17
+ - Unique history entries
18
+ - Ignore 'enter' on empty line
19
+
20
+ 0.2.1 - Martin DeMello - 2005/04/13
21
+ * 'gets' implemented (with much help from Csaba Henk)
22
+
23
+ 0.2.0 - Martin DeMello - 2005/04/10
24
+ * Multiline edit
25
+ * Settable on_exit proc
26
+
27
+ 0.1.4 - Martin DeMello - 2005/02/19
28
+ * Minor code cleanup
29
+ * Dedentation on ], } or end
30
+ * Ctrl-D, Ctrl-U and Ctrl-K keys bound
31
+
32
+ 0.1.3 - Martin DeMello - 2004/03/21
33
+ * Added ability to select text, and return the cursor to the proper position
34
+ * Changed font to Lucida Console
35
+ * Added indentation
36
+
37
+ 0.1.2 - Frailis - 2003/01/10
38
+ * Fixed commands history
39
+
40
+ 0.1.1 - Frailis - 2003/01/07
41
+ * Removed IOEmulate module because it redirects every "p" operation in a
42
+ program which embeds FXIrb
43
+
44
+ 0.1.0 - Frailis - 2003/01/02
45
+ * Tested on ruby 1.6.7 and 1.7.3
46
+ * Added commands history and terminal behaviour
47
+
@@ -0,0 +1,7 @@
1
+ bin/fxirb
2
+ lib/fxirb.rb
3
+ TODO
4
+ CHANGELOG
5
+ Manifest.txt
6
+ rakefile
7
+ setup.rb
data/TODO ADDED
@@ -0,0 +1,6 @@
1
+ - handle user input redirection
2
+ - readline
3
+ - ctrl-l support
4
+ - syntax colouring
5
+ - frontends other than fox
6
+ - session export
@@ -0,0 +1,15 @@
1
+ #! /usr/bin/ruby18
2
+
3
+ require 'fxirb'
4
+
5
+ application = FXApp.new("FXIrb", "ruby")
6
+ application.threadsEnabled = true
7
+ Thread.abort_on_exception = true
8
+ window = FXMainWindow.new(application, "FXIrb",
9
+ nil, nil, DECOR_ALL, 0, 0, 580, 500)
10
+ fxirb = FXIrb.init(window, nil, 0,
11
+ LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP|TEXT_SHOWACTIVE)
12
+ application.create
13
+ window.show(PLACEMENT_SCREEN)
14
+ fxirb.on_exit {exit}
15
+ application.run
@@ -0,0 +1,482 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # Credits:
4
+ # - Initial linux version: Gilles Filippini
5
+ # - Initial windows port : Marco Frailis
6
+ # - Currently maintained and developed by
7
+ # Martin DeMello <martindemello@gmail.com>
8
+
9
+ class FxIrb
10
+ VERSION = '0.3.1'
11
+ end
12
+
13
+ begin
14
+ require 'rubygems'
15
+ require_gem 'fxruby', '>= 1.2.0'
16
+ rescue LoadError
17
+ begin
18
+ require 'fox16'
19
+ rescue LoadError
20
+ begin
21
+ require 'fox14'
22
+ rescue LoadError
23
+ require 'fox12'
24
+ end
25
+ end
26
+ end
27
+
28
+ require "irb"
29
+ require "singleton"
30
+ require "English"
31
+ require 'thread'
32
+
33
+ include Fox
34
+
35
+ STDOUT.sync = true
36
+
37
+ class FXIRBInputMethod < IRB::StdioInputMethod
38
+
39
+ attr_accessor :print_prompt, :gets_mode
40
+
41
+ def initialize
42
+ super
43
+ @history = 1
44
+ @begin = nil
45
+ @end = nil
46
+ @print_prompt = true
47
+ @continued_from = nil
48
+ @gets_mode = false
49
+ end
50
+
51
+ def gets
52
+ if @gets_mode
53
+ return FXIrb.instance.get_line
54
+ end
55
+
56
+ if (a = @prompt.match(/(\d+)[>*]/))
57
+ level = a[1].to_i
58
+ continued = @prompt =~ /\*\s*$/
59
+ else
60
+ level = 0
61
+ end
62
+
63
+ if level > 0 or continued
64
+ @continued_from ||= @line_no
65
+ elsif @continued_from
66
+ merge_last(@line_no-@continued_from+1)
67
+ @continued_from = nil
68
+ end
69
+
70
+ l = @line.length
71
+ @line = @line.reverse.uniq.reverse
72
+ delta = l - @line.length
73
+ @line_no -= delta
74
+ @history -= delta
75
+
76
+ if print_prompt
77
+ print @prompt
78
+
79
+ #indentation
80
+ print " "*level
81
+ end
82
+
83
+ str = FXIrb.instance.get_line
84
+
85
+ @line_no += 1
86
+ @history = @line_no + 1
87
+ @line[@line_no] = str
88
+
89
+ str
90
+ end
91
+
92
+ # merge a block spanning several lines into one \n-separated line
93
+ def merge_last(i)
94
+ return unless i > 1
95
+ range = -i..-1
96
+ @line[range] = @line[range].join
97
+ @line_no -= (i-1)
98
+ @history -= (i-1)
99
+ end
100
+
101
+ def prev_cmd
102
+ return "" if @gets_mode
103
+
104
+ if @line_no > 0
105
+ @history -= 1 unless @history <= 1
106
+ return line(@history)
107
+ end
108
+ return ""
109
+ end
110
+
111
+ def next_cmd
112
+ return "" if @gets_mode
113
+
114
+ if (@line_no > 0) && (@history < @line_no)
115
+ @history += 1
116
+ return line(@history)
117
+ end
118
+ return ""
119
+ end
120
+
121
+ end
122
+
123
+ module IRB
124
+
125
+ def IRB.start_in_fxirb(im)
126
+ if RUBY_VERSION < "1.7.3"
127
+ IRB.initialize(nil)
128
+ IRB.parse_opts
129
+ IRB.load_modules
130
+ else
131
+ IRB.setup(nil)
132
+ end
133
+
134
+ irb = Irb.new(nil, im)
135
+
136
+ @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
137
+ @CONF[:MAIN_CONTEXT] = irb.context
138
+ trap("SIGINT") do
139
+ irb.signal_handle
140
+ end
141
+
142
+ class << irb.context.workspace.main
143
+ def gets
144
+ inp = IRB.conf[:MAIN_CONTEXT].io
145
+ inp.gets_mode = true
146
+ retval = IRB.conf[:MAIN_CONTEXT].io.gets
147
+ inp.gets_mode = false
148
+ retval
149
+ end
150
+ end
151
+
152
+ catch(:IRB_EXIT) do
153
+ irb.eval_input
154
+ end
155
+ print "\n"
156
+ end
157
+
158
+ end
159
+
160
+ class FXEvent
161
+ def ctrl?
162
+ (self.state & CONTROLMASK) != 0
163
+ end
164
+
165
+ def shift?
166
+ (self.state & SHIFTMASK) != 0
167
+ end
168
+ end
169
+
170
+
171
+ class FXIrb < FXText
172
+ include Singleton
173
+ include Responder
174
+
175
+ attr_reader :input
176
+ attr_accessor :multiline
177
+
178
+ def FXIrb.init(p, tgt, sel, opts)
179
+ unless @__instance__
180
+ Thread.critical = true
181
+ begin
182
+ @__instance__ ||= new(p, tgt, sel, opts)
183
+ ensure
184
+ Thread.critical = false
185
+ end
186
+ end
187
+ return @__instance__
188
+ end
189
+
190
+ def initialize(p, tgt, sel, opts)
191
+ FXMAPFUNC(SEL_KEYRELEASE, 0, "onKeyRelease")
192
+ FXMAPFUNC(SEL_KEYPRESS, 0, "onKeyPress")
193
+ FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,"onLeftBtnPress")
194
+ FXMAPFUNC(SEL_MIDDLEBUTTONPRESS,0,"onMiddleBtnPress")
195
+ FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,"onLeftBtnRelease")
196
+
197
+ super
198
+ setFont(FXFont.new(FXApp.instance, "lucida console", 9))
199
+ @anchor = 0
200
+ end
201
+
202
+ def create
203
+ super
204
+ setFocus
205
+ # IRB initialization
206
+ @inputAdded = 0
207
+ @input = IO.pipe
208
+ $DEFAULT_OUTPUT = self
209
+
210
+ @im = FXIRBInputMethod.new
211
+ @irb = Thread.new {
212
+ IRB.start_in_fxirb(@im)
213
+ self.crash
214
+ }
215
+
216
+ @multiline = false
217
+
218
+ @exit_proc = lambda {exit}
219
+ end
220
+
221
+ def on_exit(&block)
222
+ @exit_proc = block
223
+ end
224
+
225
+ def crash
226
+ instance_eval(&@exit_proc)
227
+ end
228
+
229
+ private
230
+
231
+ def onLeftBtnPress(sender,sel,event)
232
+ @store_anchor = @anchor
233
+ setFocus
234
+ super
235
+ end
236
+
237
+ def onLeftBtnRelease(sender,sel,event)
238
+ super
239
+ @anchor = @store_anchor
240
+ setCursorPos(getLength)
241
+ end
242
+
243
+ def onMiddleBtnPress(sender,sel,event)
244
+ pos = getPosAt(event.win_x,event.win_y)
245
+ if pos >= @anchor
246
+ super
247
+ end
248
+ end
249
+
250
+ def onKeyRelease(sender, sel, event)
251
+ case event.code
252
+ when KEY_Return, KEY_KP_Enter
253
+ new_line_entered unless empty_frame?
254
+ end
255
+ return 1
256
+ end
257
+
258
+ def onKeyPress(sender,sel,event)
259
+ case event.code
260
+ when KEY_Return, KEY_KP_Enter
261
+ move_to_end_of_frame
262
+ super unless empty_frame?
263
+
264
+ when KEY_Up,KEY_KP_Up
265
+ multiline = true if get_from_start_of_line =~ /\n/
266
+ multiline ? super : history(:prev)
267
+ move_to_start_of_line if invalid_pos?
268
+
269
+ when KEY_Down,KEY_KP_Down
270
+ multiline = true if get_to_end_of_line =~ /\n/
271
+ multiline ? super : history(:next)
272
+
273
+ when KEY_Left,KEY_KP_Left
274
+ super if can_move_left?
275
+
276
+ when KEY_Delete,KEY_KP_Delete,KEY_BackSpace
277
+ if event.shift? or event.ctrl?
278
+ event.code == KEY_BackSpace ?
279
+ delete_from_start_of_line :
280
+ delete_to_end_of_line
281
+ elsif can_move_left?
282
+ super
283
+ end
284
+
285
+ when KEY_Home, KEY_KP_Home
286
+ move_to_start_of_line
287
+
288
+ when KEY_End, KEY_KP_End
289
+ move_to_end_of_line
290
+
291
+ when KEY_Page_Up, KEY_KP_Page_Up
292
+ history(:prev)
293
+
294
+ when KEY_Page_Down, KEY_KP_Page_Down
295
+ history(:next)
296
+
297
+ when KEY_bracketright, KEY_braceright
298
+ #auto-auto_dedent if the } or ] is on a line by itself
299
+ auto_dedent if empty_frame? and indented?
300
+ super
301
+
302
+ when KEY_u
303
+ event.ctrl? ? delete_from_start_of_line : super
304
+
305
+ when KEY_k
306
+ event.ctrl? ? delete_to_end_of_line : super
307
+
308
+ when KEY_d
309
+ if event.ctrl? and empty_frame?
310
+ quit_irb
311
+ else
312
+ # test for 'end' so we can auto_dedent
313
+ if (get_frame == "en") and indented?
314
+ auto_dedent
315
+ end
316
+ super
317
+ end
318
+
319
+ else
320
+ super
321
+ end
322
+ end
323
+
324
+ def auto_dedent
325
+ str = get_frame
326
+ clear_frame
327
+ @anchor -= 2
328
+ appendText(str)
329
+ setCursorPos(getLength)
330
+ end
331
+
332
+ def history(dir)
333
+ str = (dir == :prev) ? @im.prev_cmd.chomp : @im.next_cmd.chomp
334
+ if str != ""
335
+ clear_frame
336
+ write(str)
337
+ end
338
+ end
339
+
340
+ def quit_irb
341
+ clear_frame
342
+ appendText("exit")
343
+ new_line_entered
344
+ end
345
+
346
+ def get_frame
347
+ extractText(@anchor, getLength-@anchor)
348
+ end
349
+
350
+ def invalid_pos?
351
+ getCursorPos < @anchor
352
+ end
353
+
354
+ def can_move_left?
355
+ getCursorPos > @anchor
356
+ end
357
+
358
+ def move_to_start_of_frame
359
+ setCursorPos(@anchor)
360
+ end
361
+
362
+ def move_to_end_of_frame
363
+ setCursorPos(getLength)
364
+ end
365
+
366
+ def move_to_start_of_line
367
+ if multiline
368
+ cur = getCursorPos
369
+ pos = lineStart(cur)
370
+ pos = @anchor if pos < @anchor
371
+ else
372
+ pos = @anchor
373
+ end
374
+ setCursorPos(pos)
375
+ end
376
+
377
+ def move_to_end_of_line
378
+ if multiline
379
+ cur = getCursorPos
380
+ pos = lineEnd(cur)
381
+ else
382
+ pos = getLength
383
+ end
384
+ setCursorPos(pos)
385
+ end
386
+
387
+ def get_from_start_of_line
388
+ extractText(@anchor, getCursorPos-@anchor)
389
+ end
390
+
391
+ def get_to_end_of_line
392
+ extractText(getCursorPos, getLength - getCursorPos)
393
+ end
394
+
395
+ def clear_frame
396
+ removeText(@anchor, getLength-@anchor)
397
+ end
398
+
399
+ def delete_from_start_of_line
400
+ str = get_to_end_of_line
401
+ clear_frame
402
+ appendText(str)
403
+ setCursorPos(@anchor)
404
+ end
405
+
406
+ def delete_to_end_of_line
407
+ str = get_from_start_of_line
408
+ clear_frame
409
+ appendText(str)
410
+ setCursorPos(getLength)
411
+ end
412
+
413
+ def empty_frame?
414
+ get_frame == ""
415
+ end
416
+
417
+ def indented?
418
+ extractText(@anchor-2, 2) == " "
419
+ end
420
+
421
+ def new_line_entered
422
+ process_commandline(extractText(@anchor, getLength-@anchor))
423
+ end
424
+
425
+ def process_commandline(cmd)
426
+ multiline = false
427
+ lines = cmd.split(/\n/)
428
+ lines.each {|i|
429
+ @input[1].puts i
430
+ @inputAdded += 1
431
+ }
432
+
433
+ while (@inputAdded > 0) do
434
+ @irb.run
435
+ end
436
+ end
437
+
438
+ public
439
+
440
+ def send_command(cmd)
441
+ setCursorPos(getLength)
442
+ makePositionVisible(getLength) unless isPosVisible(getLength)
443
+ cmd += "\n"
444
+ appendText(cmd)
445
+ process_commandline(cmd)
446
+ end
447
+
448
+ def write(obj)
449
+ str = obj.to_s
450
+ appendText(str)
451
+ setCursorPos(getLength)
452
+ makePositionVisible(getLength) unless isPosVisible(getLength)
453
+ return str.length
454
+ end
455
+
456
+ def get_line
457
+ @anchor = getLength
458
+ if @inputAdded == 0
459
+ Thread.stop
460
+ end
461
+ @inputAdded -= 1
462
+ retval = @input[0].gets
463
+ # don't print every prompt for multiline input
464
+ @im.print_prompt = (@inputAdded == 0)
465
+ return retval
466
+ end
467
+ end
468
+
469
+ # Stand alone run
470
+ if __FILE__ == $0
471
+ application = FXApp.new("FXIrb", "ruby")
472
+ application.threadsEnabled = true
473
+ Thread.abort_on_exception = true
474
+ window = FXMainWindow.new(application, "FXIrb",
475
+ nil, nil, DECOR_ALL, 0, 0, 580, 500)
476
+ fxirb = FXIrb.init(window, nil, 0,
477
+ LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP|TEXT_SHOWACTIVE)
478
+ application.create
479
+ window.show(PLACEMENT_SCREEN)
480
+ fxirb.on_exit {exit}
481
+ application.run
482
+ end