fxirb 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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