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.
- data/CHANGELOG +47 -0
- data/Manifest.txt +7 -0
- data/TODO +6 -0
- data/bin/fxirb +15 -0
- data/lib/fxirb.rb +482 -0
- data/rakefile +13 -0
- data/setup.rb +1585 -0
- metadata +59 -0
data/CHANGELOG
ADDED
@@ -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
|
+
|
data/Manifest.txt
ADDED
data/TODO
ADDED
data/bin/fxirb
ADDED
@@ -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
|
data/lib/fxirb.rb
ADDED
@@ -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
|