fxri 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,31 @@
1
+ 0.2.1 - Martin DeMello - 2005/04/13
2
+ * 'gets' implemented (with much help from Csaba Henk)
3
+
4
+ 0.2.0 - Martin DeMello - 2005/04/10
5
+ * Multiline edit
6
+ * Settable on_exit proc
7
+
8
+ 0.1.4 - Martin DeMello - 2005/02/19
9
+ * Minor code cleanup
10
+ * Dedentation on ], } or end
11
+ * Ctrl-D, Ctrl-U and Ctrl-K keys bound
12
+
13
+ 0.1.3 - Martin DeMello - 2004/03/21
14
+
15
+ * Added ability to select text, and return the cursor to the proper position
16
+ * Changed font to Lucida Console
17
+ * Added indentation
18
+
19
+ 0.1.2 - Frailis - 2003/01/10
20
+
21
+ * Fixed commands history
22
+
23
+ 0.1.1 - Frailis - 2003/01/07
24
+
25
+ * Removed IOEmulate module because it redirects every "p" operation in a program which embeds FXIrb
26
+
27
+ 0.1.0 - Frailis - 2003/01/02
28
+
29
+ * Tested on ruby 1.6.7 and 1.7.3
30
+ * Added commands history and terminal behaviour
31
+
@@ -0,0 +1,395 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # TODO
4
+ # - handle user input redirection
5
+ # - readline
6
+
7
+ # Credits:
8
+ # - Initial linux version: Gilles Filippini
9
+ # - Initial windows port : Marco Frailis
10
+ # - Currently maintained and developed by
11
+ # Martin DeMello <martindemello@gmail.com>
12
+
13
+ require "fox12"
14
+ require "irb"
15
+ require "singleton"
16
+ require "English"
17
+
18
+ include Fox
19
+
20
+ STDOUT.sync = true
21
+
22
+ class FXIRBInputMethod < IRB::StdioInputMethod
23
+
24
+ attr_accessor :print_prompt, :gets_mode
25
+
26
+ def initialize
27
+ super
28
+ @history = 1
29
+ @begin = nil
30
+ @print_prompt = true
31
+ @end = nil
32
+ @continued_from = nil
33
+ @gets_mode = false
34
+ end
35
+
36
+ def gets
37
+ if @gets_mode
38
+ return FXIrb.instance.get_line
39
+ end
40
+
41
+ if (a = @prompt.match(/(\d+)[>*]/))
42
+ level = a[1].to_i
43
+ else
44
+ level = 0
45
+ end
46
+
47
+ if level > 0
48
+ @continued_from ||= @line_no
49
+ elsif @continued_from
50
+ merge_last(@line_no-@continued_from+1)
51
+ @continued_from = nil
52
+ end
53
+
54
+ if @print_prompt
55
+ print @prompt
56
+
57
+ #indentation
58
+ print " "*level
59
+ end
60
+
61
+ str = FXIrb.instance.get_line
62
+
63
+ @line_no += 1
64
+ @history = @line_no + 1
65
+ @line[@line_no] = str
66
+
67
+ str
68
+ end
69
+
70
+ # merge a block spanning several lines into one \n-separated line
71
+ def merge_last(i)
72
+ return unless i > 1
73
+ range = -i..-1
74
+ @line[range] = @line[range].map {|l| l.chomp}.join("\n")
75
+ @line_no -= (i-1)
76
+ @history -= (i-1)
77
+ end
78
+
79
+ def prevCmd
80
+ return "" if @gets_mode
81
+
82
+ if @line_no > 0
83
+ @history -= 1 unless @history <= 1
84
+ return line(@history)
85
+ end
86
+ return ""
87
+ end
88
+
89
+ def nextCmd
90
+ return "" if @gets_mode
91
+
92
+ if (@line_no > 0) && (@history < @line_no)
93
+ @history += 1
94
+ return line(@history)
95
+ end
96
+ return ""
97
+ end
98
+
99
+ end
100
+
101
+ module IRB
102
+
103
+ def IRB.start_in_fxirb(im)
104
+ if RUBY_VERSION < "1.7.3"
105
+ IRB.initialize(nil)
106
+ IRB.parse_opts
107
+ IRB.load_modules
108
+ else
109
+ IRB.setup(nil)
110
+ end
111
+
112
+ irb = Irb.new(nil, im)
113
+
114
+ @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
115
+ @CONF[:MAIN_CONTEXT] = irb.context
116
+ trap("SIGINT") do
117
+ irb.signal_handle
118
+ end
119
+
120
+ class << irb.context.workspace.main
121
+ def gets
122
+ inp = IRB.conf[:MAIN_CONTEXT].io
123
+ inp.gets_mode = true
124
+ retval = IRB.conf[:MAIN_CONTEXT].io.gets
125
+ inp.gets_mode = false
126
+ retval
127
+ end
128
+ end
129
+
130
+ catch(:IRB_EXIT) do
131
+ irb.eval_input
132
+ end
133
+ print "\n"
134
+
135
+ end
136
+
137
+ end
138
+
139
+
140
+ class FXIrb < FXText
141
+ include Singleton
142
+ include Responder
143
+
144
+ attr_reader :input
145
+
146
+ def FXIrb.init(p, tgt, sel, opts)
147
+ unless @__instance__
148
+ Thread.critical = true
149
+ begin
150
+ @__instance__ ||= new(p, tgt, sel, opts)
151
+ ensure
152
+ Thread.critical = false
153
+ end
154
+ end
155
+ return @__instance__
156
+ end
157
+
158
+ def initialize(p, tgt, sel, opts)
159
+ FXMAPFUNC(SEL_KEYRELEASE, 0, "onKeyRelease")
160
+ FXMAPFUNC(SEL_KEYPRESS, 0, "onKeyPress")
161
+ FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,"onLeftBtnPress")
162
+ FXMAPFUNC(SEL_MIDDLEBUTTONPRESS,0,"onMiddleBtnPress")
163
+ FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,"onLeftBtnRelease")
164
+
165
+ super
166
+ setFont(FXFont.new(FXApp.instance, "lucida console", 9))
167
+ @anchor = 0
168
+ end
169
+
170
+ def create
171
+ super
172
+ setFocus
173
+ # IRB initialization
174
+ @inputAdded = 0
175
+ @input = IO.pipe
176
+ $DEFAULT_OUTPUT = self
177
+
178
+ @im = FXIRBInputMethod.new
179
+ @irb = Thread.new {
180
+ IRB.start_in_fxirb(@im)
181
+ self.crash
182
+ }
183
+
184
+
185
+ @multiline = false
186
+
187
+ @exit_proc = lambda {exit}
188
+ end
189
+
190
+ def on_exit(&block)
191
+ @exit_proc = block
192
+ end
193
+
194
+ def crash
195
+ instance_eval(&@exit_proc)
196
+ end
197
+
198
+ def onKeyRelease(sender, sel, event)
199
+ case event.code
200
+ when Fox::KEY_Return, Fox::KEY_KP_Enter
201
+ newLineEntered
202
+ end
203
+ return 1
204
+ end
205
+
206
+ def onKeyPress(sender,sel,event)
207
+ case event.code
208
+ when Fox::KEY_Return, Fox::KEY_KP_Enter
209
+ setCursorPos(getLength)
210
+ super
211
+ when Fox::KEY_Up,Fox::KEY_KP_Up
212
+ str = extractText(@anchor, getCursorPos-@anchor)
213
+ if str =~ /\n/
214
+ @multiline = true
215
+ super
216
+ setCursorPos(@anchor+1) if getCursorPos < @anchor
217
+ else
218
+ history(:prev) unless @multiline
219
+ end
220
+ when Fox::KEY_Down,Fox::KEY_KP_Down
221
+ str = extractText(getCursorPos, getLength - getCursorPos)
222
+ if str =~ /\n/
223
+ @multiline = true
224
+ super
225
+ else
226
+ history(:next) unless @multiline
227
+ end
228
+ when Fox::KEY_Left,Fox::KEY_KP_Left
229
+ if getCursorPos > @anchor
230
+ super
231
+ end
232
+ when Fox::KEY_Delete,Fox::KEY_KP_Delete,Fox::KEY_BackSpace
233
+ if getCursorPos > @anchor
234
+ super
235
+ end
236
+ when Fox::KEY_Home, Fox::KEY_KP_Home
237
+ setCursorPos(@anchor)
238
+ when Fox::KEY_End, Fox::KEY_KP_End
239
+ setCursorPos(getLength)
240
+ when Fox::KEY_Page_Up, Fox::KEY_KP_Page_Up
241
+ history(:prev)
242
+ when Fox::KEY_Page_Down, Fox::KEY_KP_Page_Down
243
+ history(:next)
244
+ when Fox::KEY_bracketright
245
+ #auto-dedent if the } or ] is on a line by itself
246
+ if (emptyline? or (getline == "en")) and indented?
247
+ dedent
248
+ end
249
+ super
250
+ when Fox::KEY_u
251
+ if (event.state & CONTROLMASK) != 0
252
+ str = extractText(getCursorPos, getLength - getCursorPos)
253
+ rmline
254
+ appendText(str)
255
+ setCursorPos(@anchor)
256
+ end
257
+ super
258
+ when Fox::KEY_k
259
+ if (event.state & CONTROLMASK) != 0
260
+ str = extractText(@anchor, getCursorPos-@anchor)
261
+ rmline
262
+ appendText(str)
263
+ setCursorPos(getLength)
264
+ end
265
+ super
266
+ when Fox::KEY_d
267
+ if (event.state & CONTROLMASK) != 0
268
+ #Ctrl - D
269
+ rmline
270
+ appendText("exit")
271
+ newLineEntered
272
+ else
273
+ # test for 'end' so we can dedent
274
+ if (getline == "en") and indented?
275
+ dedent
276
+ end
277
+ end
278
+ super
279
+ else
280
+ super
281
+ end
282
+ end
283
+
284
+ def dedent
285
+ str = getline
286
+ @anchor -= 2
287
+ rmline
288
+ appendText(str)
289
+ setCursorPos(getLength)
290
+ end
291
+
292
+ def history(dir)
293
+ str = (dir == :prev) ? @im.prevCmd.chomp : @im.nextCmd.chomp
294
+ if str != ""
295
+ removeText(@anchor, getLength-@anchor)
296
+ write(str)
297
+ end
298
+ end
299
+
300
+ def getline
301
+ extractText(@anchor, getLength-@anchor)
302
+ end
303
+
304
+ def rmline
305
+ str = getline
306
+ removeText(@anchor, getLength-@anchor)
307
+ str
308
+ end
309
+
310
+ def emptyline?
311
+ getline == ""
312
+ end
313
+
314
+ def indented?
315
+ extractText(@anchor-2, 2) == " "
316
+ end
317
+
318
+ def onLeftBtnPress(sender,sel,event)
319
+ @store_anchor = @anchor
320
+ setFocus
321
+ super
322
+ end
323
+
324
+ def onLeftBtnRelease(sender,sel,event)
325
+ super
326
+ @anchor = @store_anchor
327
+ setCursorPos(@anchor)
328
+ setCursorPos(getLength)
329
+ end
330
+
331
+ def onMiddleBtnPress(sender,sel,event)
332
+ pos=getPosAt(event.win_x,event.win_y)
333
+ if pos >= @anchor
334
+ super
335
+ end
336
+ end
337
+
338
+ def newLineEntered
339
+ processCommandLine(extractText(@anchor, getLength-@anchor))
340
+ end
341
+
342
+ def processCommandLine(cmd)
343
+ @multiline = false
344
+ lines = cmd.split(/\n/)
345
+ lines.each {|i|
346
+ @input[1].puts i
347
+ @inputAdded += 1
348
+ }
349
+ @im.print_prompt = false
350
+ while (@inputAdded > 0) do
351
+ @irb.run
352
+ end
353
+ @im.merge_last(lines.length)
354
+ @im.print_prompt = true
355
+ end
356
+
357
+ def sendCommand(cmd)
358
+ setCursorPos(getLength)
359
+ makePositionVisible(getLength) unless isPosVisible(getLength)
360
+ cmd += "\n"
361
+ appendText(cmd)
362
+ processCommandLine(cmd)
363
+ end
364
+
365
+ def write(obj)
366
+ str = obj.to_s
367
+ appendText(str)
368
+ setCursorPos(getLength)
369
+ makePositionVisible(getLength) unless isPosVisible(getLength)
370
+ return str.length
371
+ end
372
+
373
+ def get_line
374
+ @anchor = getLength
375
+ if @inputAdded == 0
376
+ Thread.stop
377
+ end
378
+ @inputAdded -= 1
379
+ return @input[0].gets
380
+ end
381
+ end
382
+
383
+ # Stand alone run
384
+ if __FILE__ == $0
385
+ application = FXApp.new("FXIrb", "ruby")
386
+ application.threadsEnabled = true
387
+ Thread.abort_on_exception = true
388
+ application.init(ARGV)
389
+ window = FXMainWindow.new(application, "FXIrb", nil, nil, DECOR_ALL, 0, 0, 580, 500)
390
+ fxirb = FXIrb.init(window, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP|TEXT_SHOWACTIVE)
391
+ application.create
392
+ window.show(PLACEMENT_SCREEN)
393
+ fxirb.on_exit {exit}
394
+ application.run
395
+ end
@@ -1,395 +1,400 @@
1
- #! /usr/bin/env ruby
2
-
3
- # TODO
4
- # - handle user input redirection
5
- # - readline
6
-
7
- # Credits:
8
- # - Initial linux version: Gilles Filippini
9
- # - Initial windows port : Marco Frailis
10
- # - Currently maintained and developed by
11
- # Martin DeMello <martindemello@gmail.com>
12
-
13
- require "fox12"
14
- require "irb"
15
- require "singleton"
16
- require "English"
17
-
18
- include Fox
19
-
20
- STDOUT.sync = true
21
-
22
- class FXIRBInputMethod < IRB::StdioInputMethod
23
-
24
- attr_accessor :print_prompt, :gets_mode
25
-
26
- def initialize
27
- super
28
- @history = 1
29
- @begin = nil
30
- @print_prompt = true
31
- @end = nil
32
- @continued_from = nil
33
- @gets_mode = false
34
- end
35
-
36
- def gets
37
- if @gets_mode
38
- return FXIrb.instance.get_line
39
- end
40
-
41
- if (a = @prompt.match(/(\d+)[>*]/))
42
- level = a[1].to_i
43
- else
44
- level = 0
45
- end
46
-
47
- if level > 0
48
- @continued_from ||= @line_no
49
- elsif @continued_from
50
- merge_last(@line_no-@continued_from+1)
51
- @continued_from = nil
52
- end
53
-
54
- if @print_prompt
55
- print @prompt
56
-
57
- #indentation
58
- print " "*level
59
- end
60
-
61
- str = FXIrb.instance.get_line
62
-
63
- @line_no += 1
64
- @history = @line_no + 1
65
- @line[@line_no] = str
66
-
67
- str
68
- end
69
-
70
- # merge a block spanning several lines into one \n-separated line
71
- def merge_last(i)
72
- return unless i > 1
73
- range = -i..-1
74
- @line[range] = @line[range].map {|l| l.chomp}.join("\n")
75
- @line_no -= (i-1)
76
- @history -= (i-1)
77
- end
78
-
79
- def prevCmd
80
- return "" if @gets_mode
81
-
82
- if @line_no > 0
83
- @history -= 1 unless @history <= 1
84
- return line(@history)
85
- end
86
- return ""
87
- end
88
-
89
- def nextCmd
90
- return "" if @gets_mode
91
-
92
- if (@line_no > 0) && (@history < @line_no)
93
- @history += 1
94
- return line(@history)
95
- end
96
- return ""
97
- end
98
-
99
- end
100
-
101
- module IRB
102
-
103
- def IRB.start_in_fxirb(im)
104
- if RUBY_VERSION < "1.7.3"
105
- IRB.initialize(nil)
106
- IRB.parse_opts
107
- IRB.load_modules
108
- else
109
- IRB.setup(nil)
110
- end
111
-
112
- irb = Irb.new(nil, im)
113
-
114
- @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
115
- @CONF[:MAIN_CONTEXT] = irb.context
116
- trap("SIGINT") do
117
- irb.signal_handle
118
- end
119
-
120
- class << irb.context.workspace.main
121
- def gets
122
- inp = IRB.conf[:MAIN_CONTEXT].io
123
- inp.gets_mode = true
124
- retval = IRB.conf[:MAIN_CONTEXT].io.gets
125
- inp.gets_mode = false
126
- retval
127
- end
128
- end
129
-
130
- catch(:IRB_EXIT) do
131
- irb.eval_input
132
- end
133
- print "\n"
134
-
135
- end
136
-
137
- end
138
-
139
-
140
- class FXIrb < FXText
141
- include Singleton
142
- include Responder
143
-
144
- attr_reader :input
145
-
146
- def FXIrb.init(p, tgt, sel, opts)
147
- unless @__instance__
148
- Thread.critical = true
149
- begin
150
- @__instance__ ||= new(p, tgt, sel, opts)
151
- ensure
152
- Thread.critical = false
153
- end
154
- end
155
- return @__instance__
156
- end
157
-
158
- def initialize(p, tgt, sel, opts)
159
- FXMAPFUNC(SEL_KEYRELEASE, 0, "onKeyRelease")
160
- FXMAPFUNC(SEL_KEYPRESS, 0, "onKeyPress")
161
- FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,"onLeftBtnPress")
162
- FXMAPFUNC(SEL_MIDDLEBUTTONPRESS,0,"onMiddleBtnPress")
163
- FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,"onLeftBtnRelease")
164
-
165
- super
166
- setFont(FXFont.new(FXApp.instance, "lucida console", 9))
167
- @anchor = 0
168
- end
169
-
170
- def create
171
- super
172
- setFocus
173
- # IRB initialization
174
- @inputAdded = 0
175
- @input = IO.pipe
176
- $DEFAULT_OUTPUT = self
177
-
178
- @im = FXIRBInputMethod.new
179
- @irb = Thread.new {
180
- IRB.start_in_fxirb(@im)
181
- self.crash
182
- }
183
-
184
-
185
- @multiline = false
186
-
187
- @exit_proc = lambda {exit}
188
- end
189
-
190
- def on_exit(&block)
191
- @exit_proc = block
192
- end
193
-
194
- def crash
195
- instance_eval(&@exit_proc)
196
- end
197
-
198
- def onKeyRelease(sender, sel, event)
199
- case event.code
200
- when Fox::KEY_Return, Fox::KEY_KP_Enter
201
- newLineEntered
202
- end
203
- return 1
204
- end
205
-
206
- def onKeyPress(sender,sel,event)
207
- case event.code
208
- when Fox::KEY_Return, Fox::KEY_KP_Enter
209
- setCursorPos(getLength)
210
- super
211
- when Fox::KEY_Up,Fox::KEY_KP_Up
212
- str = extractText(@anchor, getCursorPos-@anchor)
213
- if str =~ /\n/
214
- @multiline = true
215
- super
216
- setCursorPos(@anchor+1) if getCursorPos < @anchor
217
- else
218
- history(:prev) unless @multiline
219
- end
220
- when Fox::KEY_Down,Fox::KEY_KP_Down
221
- str = extractText(getCursorPos, getLength - getCursorPos)
222
- if str =~ /\n/
223
- @multiline = true
224
- super
225
- else
226
- history(:next) unless @multiline
227
- end
228
- when Fox::KEY_Left,Fox::KEY_KP_Left
229
- if getCursorPos > @anchor
230
- super
231
- end
232
- when Fox::KEY_Delete,Fox::KEY_KP_Delete,Fox::KEY_BackSpace
233
- if getCursorPos > @anchor
234
- super
235
- end
236
- when Fox::KEY_Home, Fox::KEY_KP_Home
237
- setCursorPos(@anchor)
238
- when Fox::KEY_End, Fox::KEY_KP_End
239
- setCursorPos(getLength)
240
- when Fox::KEY_Page_Up, Fox::KEY_KP_Page_Up
241
- history(:prev)
242
- when Fox::KEY_Page_Down, Fox::KEY_KP_Page_Down
243
- history(:next)
244
- when Fox::KEY_bracketright
245
- #auto-dedent if the } or ] is on a line by itself
246
- if (emptyline? or (getline == "en")) and indented?
247
- dedent
248
- end
249
- super
250
- when Fox::KEY_u
251
- if (event.state & CONTROLMASK) != 0
252
- str = extractText(getCursorPos, getLength - getCursorPos)
253
- rmline
254
- appendText(str)
255
- setCursorPos(@anchor)
256
- end
257
- super
258
- when Fox::KEY_k
259
- if (event.state & CONTROLMASK) != 0
260
- str = extractText(@anchor, getCursorPos-@anchor)
261
- rmline
262
- appendText(str)
263
- setCursorPos(getLength)
264
- end
265
- super
266
- when Fox::KEY_d
267
- if (event.state & CONTROLMASK) != 0
268
- #Ctrl - D
269
- rmline
270
- appendText("exit")
271
- newLineEntered
272
- else
273
- # test for 'end' so we can dedent
274
- if (getline == "en") and indented?
275
- dedent
276
- end
277
- end
278
- super
279
- else
280
- super
281
- end
282
- end
283
-
284
- def dedent
285
- str = getline
286
- @anchor -= 2
287
- rmline
288
- appendText(str)
289
- setCursorPos(getLength)
290
- end
291
-
292
- def history(dir)
293
- str = (dir == :prev) ? @im.prevCmd.chomp : @im.nextCmd.chomp
294
- if str != ""
295
- removeText(@anchor, getLength-@anchor)
296
- write(str)
297
- end
298
- end
299
-
300
- def getline
301
- extractText(@anchor, getLength-@anchor)
302
- end
303
-
304
- def rmline
305
- str = getline
306
- removeText(@anchor, getLength-@anchor)
307
- str
308
- end
309
-
310
- def emptyline?
311
- getline == ""
312
- end
313
-
314
- def indented?
315
- extractText(@anchor-2, 2) == " "
316
- end
317
-
318
- def onLeftBtnPress(sender,sel,event)
319
- @store_anchor = @anchor
320
- setFocus
321
- super
322
- end
323
-
324
- def onLeftBtnRelease(sender,sel,event)
325
- super
326
- @anchor = @store_anchor
327
- setCursorPos(@anchor)
328
- setCursorPos(getLength)
329
- end
330
-
331
- def onMiddleBtnPress(sender,sel,event)
332
- pos=getPosAt(event.win_x,event.win_y)
333
- if pos >= @anchor
334
- super
335
- end
336
- end
337
-
338
- def newLineEntered
339
- processCommandLine(extractText(@anchor, getLength-@anchor))
340
- end
341
-
342
- def processCommandLine(cmd)
343
- @multiline = false
344
- lines = cmd.split(/\n/)
345
- lines.each {|i|
346
- @input[1].puts i
347
- @inputAdded += 1
348
- }
349
- @im.print_prompt = false
350
- while (@inputAdded > 0) do
351
- @irb.run
352
- end
353
- @im.merge_last(lines.length)
354
- @im.print_prompt = true
355
- end
356
-
357
- def sendCommand(cmd)
358
- setCursorPos(getLength)
359
- makePositionVisible(getLength) unless isPosVisible(getLength)
360
- cmd += "\n"
361
- appendText(cmd)
362
- processCommandLine(cmd)
363
- end
364
-
365
- def write(obj)
366
- str = obj.to_s
367
- appendText(str)
368
- setCursorPos(getLength)
369
- makePositionVisible(getLength) unless isPosVisible(getLength)
370
- return str.length
371
- end
372
-
373
- def get_line
374
- @anchor = getLength
375
- if @inputAdded == 0
376
- Thread.stop
377
- end
378
- @inputAdded -= 1
379
- return @input[0].gets
380
- end
381
- end
382
-
383
- # Stand alone run
384
- if __FILE__ == $0
385
- application = FXApp.new("FXIrb", "ruby")
386
- application.threadsEnabled = true
387
- Thread.abort_on_exception = true
388
- application.init(ARGV)
389
- window = FXMainWindow.new(application, "FXIrb", nil, nil, DECOR_ALL, 0, 0, 580, 500)
390
- fxirb = FXIrb.init(window, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP|TEXT_SHOWACTIVE)
391
- application.create
392
- window.show(PLACEMENT_SCREEN)
393
- fxirb.on_exit {exit}
394
- application.run
395
- end
1
+ #! /usr/bin/env ruby
2
+
3
+ # TODO
4
+ # - handle user input redirection
5
+ # - readline
6
+
7
+ # Credits:
8
+ # - Initial linux version: Gilles Filippini
9
+ # - Initial windows port : Marco Frailis
10
+ # - Currently maintained and developed by
11
+ # Martin DeMello <martindemello@gmail.com>
12
+
13
+ require "fox16"
14
+ require "irb"
15
+ require "singleton"
16
+ require "English"
17
+
18
+ include Fox
19
+
20
+ STDOUT.sync = true
21
+
22
+ class FXIRBInputMethod < IRB::StdioInputMethod
23
+
24
+ attr_accessor :print_prompt, :gets_mode
25
+
26
+ def initialize
27
+ super
28
+ @history = 1
29
+ @begin = nil
30
+ @print_prompt = true
31
+ @end = nil
32
+ @continued_from = nil
33
+ @gets_mode = false
34
+ end
35
+
36
+ def gets
37
+ if @gets_mode
38
+ return FXIrb.instance.get_line
39
+ end
40
+
41
+ if (a = @prompt.match(/(\d+)[>*]/))
42
+ level = a[1].to_i
43
+ else
44
+ level = 0
45
+ end
46
+
47
+ if level > 0
48
+ @continued_from ||= @line_no
49
+ elsif @continued_from
50
+ merge_last(@line_no-@continued_from+1)
51
+ @continued_from = nil
52
+ end
53
+
54
+ if @print_prompt
55
+ print @prompt
56
+
57
+ #indentation
58
+ print " "*level
59
+ end
60
+
61
+ str = FXIrb.instance.get_line
62
+
63
+ @line_no += 1
64
+ @history = @line_no + 1
65
+ @line[@line_no] = str
66
+
67
+ str
68
+ end
69
+
70
+ # merge a block spanning several lines into one \n-separated line
71
+ def merge_last(i)
72
+ return unless i > 1
73
+ range = -i..-1
74
+ @line[range] = @line[range].map {|l| l.chomp}.join("\n")
75
+ @line_no -= (i-1)
76
+ @history -= (i-1)
77
+ end
78
+
79
+ def prevCmd
80
+ return "" if @gets_mode
81
+
82
+ if @line_no > 0
83
+ @history -= 1 unless @history <= 1
84
+ return line(@history)
85
+ end
86
+ return ""
87
+ end
88
+
89
+ def nextCmd
90
+ return "" if @gets_mode
91
+
92
+ if (@line_no > 0) && (@history < @line_no)
93
+ @history += 1
94
+ return line(@history)
95
+ end
96
+ return ""
97
+ end
98
+
99
+ end
100
+
101
+ module IRB
102
+
103
+ def IRB.start_in_fxirb(im)
104
+ if RUBY_VERSION < "1.7.3"
105
+ IRB.initialize(nil)
106
+ IRB.parse_opts
107
+ IRB.load_modules
108
+ else
109
+ IRB.setup(nil)
110
+ end
111
+
112
+ irb = Irb.new(nil, im)
113
+
114
+ @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
115
+ @CONF[:MAIN_CONTEXT] = irb.context
116
+ trap("SIGINT") do
117
+ irb.signal_handle
118
+ end
119
+
120
+ class << irb.context.workspace.main
121
+ def gets
122
+ inp = IRB.conf[:MAIN_CONTEXT].io
123
+ inp.gets_mode = true
124
+ retval = IRB.conf[:MAIN_CONTEXT].io.gets
125
+ inp.gets_mode = false
126
+ retval
127
+ end
128
+ end
129
+
130
+ catch(:IRB_EXIT) do
131
+ irb.eval_input
132
+ end
133
+ print "\n"
134
+
135
+ end
136
+
137
+ end
138
+
139
+
140
+ class FXIrb < FXText
141
+ include Singleton
142
+ include Responder
143
+
144
+ attr_reader :input
145
+
146
+ def FXIrb.init(p, tgt, sel, opts)
147
+ unless @__instance__
148
+ Thread.critical = true
149
+ begin
150
+ @__instance__ ||= new(p, tgt, sel, opts)
151
+ ensure
152
+ Thread.critical = false
153
+ end
154
+ end
155
+ return @__instance__
156
+ end
157
+
158
+ def initialize(p, tgt, sel, opts)
159
+ FXMAPFUNC(SEL_KEYRELEASE, 0, "onKeyRelease")
160
+ FXMAPFUNC(SEL_KEYPRESS, 0, "onKeyPress")
161
+ FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,"onLeftBtnPress")
162
+ FXMAPFUNC(SEL_MIDDLEBUTTONPRESS,0,"onMiddleBtnPress")
163
+ FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,"onLeftBtnRelease")
164
+
165
+ super
166
+ setFont(FXFont.new(FXApp.instance, "lucida console", 9))
167
+ @anchor = 0
168
+ end
169
+
170
+ def create
171
+ super
172
+ setFocus
173
+ # IRB initialization
174
+ @inputAdded = 0
175
+ @input = IO.pipe
176
+ $DEFAULT_OUTPUT = self
177
+
178
+ @im = FXIRBInputMethod.new
179
+ @irb = Thread.new {
180
+ IRB.start_in_fxirb(@im)
181
+ self.crash
182
+ }
183
+
184
+
185
+ @multiline = false
186
+
187
+ @exit_proc = lambda {exit}
188
+ end
189
+
190
+ def on_exit(&block)
191
+ @exit_proc = block
192
+ end
193
+
194
+ def crash
195
+ instance_eval(&@exit_proc)
196
+ end
197
+
198
+ def onKeyRelease(sender, sel, event)
199
+ case event.code
200
+ when Fox::KEY_Return, Fox::KEY_KP_Enter
201
+ newLineEntered
202
+ end
203
+ return 1
204
+ end
205
+
206
+ def onKeyPress(sender,sel,event)
207
+ case event.code
208
+ when Fox::KEY_Return, Fox::KEY_KP_Enter
209
+ setCursorPos(getLength)
210
+ super
211
+ when Fox::KEY_Up,Fox::KEY_KP_Up
212
+ str = extractText(@anchor, getCursorPos-@anchor)
213
+ if str =~ /\n/
214
+ @multiline = true
215
+ super
216
+ setCursorPos(@anchor+1) if getCursorPos < @anchor
217
+ else
218
+ history(:prev) unless @multiline
219
+ end
220
+ when Fox::KEY_Down,Fox::KEY_KP_Down
221
+ str = extractText(getCursorPos, getLength - getCursorPos)
222
+ if str =~ /\n/
223
+ @multiline = true
224
+ super
225
+ else
226
+ history(:next) unless @multiline
227
+ end
228
+ when Fox::KEY_Left,Fox::KEY_KP_Left
229
+ if getCursorPos > @anchor
230
+ super
231
+ end
232
+ when Fox::KEY_Delete,Fox::KEY_KP_Delete,Fox::KEY_BackSpace
233
+ if getCursorPos > @anchor
234
+ super
235
+ end
236
+ when Fox::KEY_Home, Fox::KEY_KP_Home
237
+ setCursorPos(@anchor)
238
+ when Fox::KEY_End, Fox::KEY_KP_End
239
+ setCursorPos(getLength)
240
+ when Fox::KEY_Page_Up, Fox::KEY_KP_Page_Up
241
+ history(:prev)
242
+ when Fox::KEY_Page_Down, Fox::KEY_KP_Page_Down
243
+ history(:next)
244
+ when Fox::KEY_bracketright
245
+ #auto-dedent if the } or ] is on a line by itself
246
+ if (emptyline? or (getline == "en")) and indented?
247
+ dedent
248
+ end
249
+ super
250
+ when Fox::KEY_u
251
+ if (event.state & CONTROLMASK) != 0
252
+ str = extractText(getCursorPos, getLength - getCursorPos)
253
+ rmline
254
+ appendText(str)
255
+ setCursorPos(@anchor)
256
+ end
257
+ super
258
+ when Fox::KEY_k
259
+ if (event.state & CONTROLMASK) != 0
260
+ str = extractText(@anchor, getCursorPos-@anchor)
261
+ rmline
262
+ appendText(str)
263
+ setCursorPos(getLength)
264
+ end
265
+ super
266
+ when Fox::KEY_d
267
+ if (event.state & CONTROLMASK) != 0
268
+ #Ctrl - D
269
+ rmline
270
+ appendText("exit")
271
+ newLineEntered
272
+ else
273
+ # test for 'end' so we can dedent
274
+ if (getline == "en") and indented?
275
+ dedent
276
+ end
277
+ end
278
+ super
279
+ else
280
+ super
281
+ end
282
+ end
283
+
284
+ def dedent
285
+ str = getline
286
+ @anchor -= 2
287
+ rmline
288
+ appendText(str)
289
+ setCursorPos(getLength)
290
+ end
291
+
292
+ def history(dir)
293
+ str = (dir == :prev) ? @im.prevCmd.chomp : @im.nextCmd.chomp
294
+ if str != ""
295
+ removeText(@anchor, getLength-@anchor)
296
+ write(str)
297
+ end
298
+ end
299
+
300
+ def getline
301
+ extractText(@anchor, getLength-@anchor)
302
+ end
303
+
304
+ def rmline
305
+ str = getline
306
+ removeText(@anchor, getLength-@anchor)
307
+ str
308
+ end
309
+
310
+ def emptyline?
311
+ getline == ""
312
+ end
313
+
314
+ def indented?
315
+ extractText(@anchor-2, 2) == " "
316
+ end
317
+
318
+ def onLeftBtnPress(sender,sel,event)
319
+ @store_anchor = @anchor
320
+ setFocus
321
+ super
322
+ end
323
+
324
+ def onLeftBtnRelease(sender,sel,event)
325
+ super
326
+ @anchor = @store_anchor
327
+ setCursorPos(@anchor)
328
+ setCursorPos(getLength)
329
+ end
330
+
331
+ def onMiddleBtnPress(sender,sel,event)
332
+ pos=getPosAt(event.win_x,event.win_y)
333
+ if pos >= @anchor
334
+ super
335
+ end
336
+ end
337
+
338
+ def newLineEntered
339
+ if getLength-@anchor > 0
340
+ processCommandLine(extractText(@anchor, getLength-@anchor))
341
+ else
342
+ # Probably wrong, but might work
343
+ processCommandLine(extractText(@anchor, getLength))
344
+ end
345
+ end
346
+
347
+ def processCommandLine(cmd)
348
+ @multiline = false
349
+ lines = cmd.split(/\n/)
350
+ lines.each {|i|
351
+ @input[1].puts i
352
+ @inputAdded += 1
353
+ }
354
+ @im.print_prompt = false
355
+ while (@inputAdded > 0) do
356
+ @irb.run
357
+ end
358
+ @im.merge_last(lines.length)
359
+ @im.print_prompt = true
360
+ end
361
+
362
+ def sendCommand(cmd)
363
+ setCursorPos(getLength)
364
+ makePositionVisible(getLength) unless isPosVisible(getLength)
365
+ cmd += "\n"
366
+ appendText(cmd)
367
+ processCommandLine(cmd)
368
+ end
369
+
370
+ def write(obj)
371
+ str = obj.to_s
372
+ appendText(str)
373
+ setCursorPos(getLength)
374
+ makePositionVisible(getLength) unless isPosVisible(getLength)
375
+ return str.length
376
+ end
377
+
378
+ def get_line
379
+ @anchor = getLength
380
+ if @inputAdded == 0
381
+ Thread.stop
382
+ end
383
+ @inputAdded -= 1
384
+ return @input[0].gets
385
+ end
386
+ end
387
+
388
+ # Stand alone run
389
+ if __FILE__ == $0
390
+ application = FXApp.new("FXIrb", "ruby")
391
+ application.threadsEnabled = true
392
+ Thread.abort_on_exception = true
393
+ application.init(ARGV)
394
+ window = FXMainWindow.new(application, "FXIrb", nil, nil, DECOR_ALL, 0, 0, 580, 500)
395
+ fxirb = FXIrb.init(window, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP|TEXT_SHOWACTIVE)
396
+ application.create
397
+ window.show(PLACEMENT_SCREEN)
398
+ fxirb.on_exit {exit}
399
+ application.run
400
+ end