fxri 0.3.3 → 0.3.4

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.
@@ -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