opal-irb 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +113 -0
- data/Guardfile +5 -0
- data/LICENSE +21 -0
- data/README.md +175 -0
- data/Rakefile +65 -0
- data/Roadmap.org +17 -0
- data/app/assets/stylesheets/opal-irb/jqconsole.css +263 -0
- data/compiled/app-embeddable.js +39765 -0
- data/compiled/app-jqconsole.js +39767 -0
- data/compiled/application.js +27399 -0
- data/css/ansi.css +172 -0
- data/css/opal_irb_jqconsole.css +79 -0
- data/css/show-hint.css +38 -0
- data/doc/presentations/opal_irb_overview.html +678 -0
- data/doc/presentations/opal_irb_overview.org +448 -0
- data/examples/app-embeddable.rb +8 -0
- data/examples/app-jqconsole.rb +10 -0
- data/examples/application.rb +8 -0
- data/index-embeddable.html +29 -0
- data/index-homebrew.html +115 -0
- data/index-jq.html +80 -0
- data/js/anyword-hint.js +44 -0
- data/js/jqconsole.js +1583 -0
- data/js/nodeutil.js +546 -0
- data/js/ruby.js +285 -0
- data/js/show-hint.js +383 -0
- data/lib/opal-irb/rails_engine.rb +3 -0
- data/lib/opal-irb/version.rb +3 -0
- data/lib/opal-irb-rails.rb +2 -0
- data/lib/opal-irb.rb +44 -0
- data/opal/object_extensions.rb +20 -0
- data/opal/opal_irb/completion_engine.rb +202 -0
- data/opal/opal_irb/completion_formatter.rb +49 -0
- data/opal/opal_irb/completion_results.rb +88 -0
- data/opal/opal_irb.rb +88 -0
- data/opal/opal_irb_homebrew_console.rb +398 -0
- data/opal/opal_irb_jqconsole.rb +517 -0
- data/opal/opal_irb_jqconsole_css.rb +259 -0
- data/opal/opal_irb_log_redirector.rb +32 -0
- data/opal/opal_phantomjs.rb +49 -0
- data/opal-irb.gemspec +20 -0
- data/spec/code_link_handler_spec.rb +30 -0
- data/spec/jquery.js +5 -0
- data/spec/object_extensions_spec.rb +32 -0
- data/spec/opal_irb/completion_engine_spec.rb +204 -0
- data/spec/opal_irb/completion_results_spec.rb +32 -0
- data/spec/opal_irb_log_director_spec.rb +19 -0
- data/spec/opal_irb_spec.rb +19 -0
- data/spec/spec_helper.rb +1 -0
- metadata +151 -0
@@ -0,0 +1,517 @@
|
|
1
|
+
require 'opal'
|
2
|
+
require 'opal-jquery'
|
3
|
+
require 'opal_irb_log_redirector'
|
4
|
+
require 'opal_irb'
|
5
|
+
require 'opal_irb/completion_engine'
|
6
|
+
require 'opal_irb/completion_formatter'
|
7
|
+
require 'jqconsole'
|
8
|
+
|
9
|
+
# top level methods for irb cmd line
|
10
|
+
def irb_link_for history_num=nil
|
11
|
+
OpalIrbJqconsole.console.irb_link_for history_num
|
12
|
+
end
|
13
|
+
|
14
|
+
class Timeout
|
15
|
+
def initialize(time=0, &block)
|
16
|
+
@timeout = `setTimeout(#{block}, time)`
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear
|
20
|
+
`clearTimeout(#{@timeout})`
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# module Kernel
|
25
|
+
# # just like osx's say command, only tested on desktop safari and chrome on osx
|
26
|
+
# def say msg
|
27
|
+
# %x|
|
28
|
+
# var msg = new SpeechSynthesisUtterance(#{msg});
|
29
|
+
# window.speechSynthesis.speak(msg);
|
30
|
+
# |
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
|
34
|
+
class OpalIrbJqconsole
|
35
|
+
def self.console
|
36
|
+
@console
|
37
|
+
end
|
38
|
+
|
39
|
+
# create on a pre existing div
|
40
|
+
def self.create(parent_element_id)
|
41
|
+
@console = OpalIrbJqconsole.new(parent_element_id)
|
42
|
+
end
|
43
|
+
|
44
|
+
BOTTOM_PANEL_ID = "opal-irb-console-bottom-panel"
|
45
|
+
# create a bottom panel
|
46
|
+
def self.create_bottom_panel(hidden = false)
|
47
|
+
parent_element_id="opal-irb-console"
|
48
|
+
style = hidden ? "style=\"display:none\"" : ""
|
49
|
+
# <a href="#" id="collapse-opal-irb-console" class=\"boxclose\"></a>
|
50
|
+
|
51
|
+
html = <<HTML
|
52
|
+
<div id="#{BOTTOM_PANEL_ID}" #{style}>
|
53
|
+
<div id="opal-irb-console-topbar">
|
54
|
+
<span id="collapse-opal-irb-console" class=\"boxclose\"></span>
|
55
|
+
</div>
|
56
|
+
<div id='#{parent_element_id}'>
|
57
|
+
</div>
|
58
|
+
</div>
|
59
|
+
HTML
|
60
|
+
Element.find("body").append(html)
|
61
|
+
Element.id("collapse-opal-irb-console").on(:click) {
|
62
|
+
Element.id("#{BOTTOM_PANEL_ID}").hide;
|
63
|
+
}
|
64
|
+
create("##{parent_element_id}")
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.add_hot_key_panel_behavior(keys_hash)
|
68
|
+
Element.find("body").on(:keydown) { |evt|
|
69
|
+
if create_key_filter(keys_hash, evt)
|
70
|
+
if panel.visible?
|
71
|
+
hide_panel
|
72
|
+
else
|
73
|
+
show_panel
|
74
|
+
end
|
75
|
+
end
|
76
|
+
}
|
77
|
+
end
|
78
|
+
# set $DEBUG_KEY_FILTER = true somewhere in your app to see the keys for debugging
|
79
|
+
def self.create_key_filter(keys_hash, evt)
|
80
|
+
puts "evt.ctrl_key #{evt.ctrl_key} evt.meta_key #{evt.meta_key} evt.shift_key #{evt.shift_key} evt.key_code #{evt.key_code}_" if $DEBUG_KEY_FILTER
|
81
|
+
keys_hash[:modifiers].all? { |modifier| evt.send("#{modifier}_key") } && evt.key_code == keys_hash[:key].upcase.ord
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.add_open_panel_behavior(link_id)
|
85
|
+
Element.id(link_id).on(:click) {
|
86
|
+
if panel.visible?
|
87
|
+
alert "OpalIRB is already showing"
|
88
|
+
else
|
89
|
+
show_panel
|
90
|
+
end
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.panel
|
95
|
+
Element.id("#{BOTTOM_PANEL_ID}")
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.show_panel
|
99
|
+
panel.show
|
100
|
+
Timeout.new { console.focus}
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.hide_panel
|
104
|
+
panel.hide
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
def focus
|
109
|
+
@jqconsole.Focus
|
110
|
+
end
|
111
|
+
|
112
|
+
attr_reader :irb
|
113
|
+
def initialize(parent_element_id)
|
114
|
+
@irb = OpalIrb.new
|
115
|
+
setup_cmd_line_methods
|
116
|
+
setup_jqconsole(parent_element_id)
|
117
|
+
create_multiline_editor
|
118
|
+
redirect_console_dot_log
|
119
|
+
handler()
|
120
|
+
setup_code_link_handling
|
121
|
+
end
|
122
|
+
|
123
|
+
# logs only to js console, not to irb, for things you want only for
|
124
|
+
# debug and not public viewing
|
125
|
+
def log thing
|
126
|
+
`console.orig_log(#{thing})`
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
def setup_code_link_handling
|
131
|
+
@code_link_handler = CodeLinkHandler.new
|
132
|
+
link_code = @code_link_handler.grab_link_code
|
133
|
+
if link_code
|
134
|
+
# do this after everything initializes
|
135
|
+
Timeout.new {
|
136
|
+
print_and_process_code link_code
|
137
|
+
self.class.show_panel
|
138
|
+
}
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def create_and_display_code_link code
|
143
|
+
code_link = @code_link_handler.create_link_for_code code
|
144
|
+
unescaped_write "<a href=#{code_link}>#{code_link}</a>\n" if code_link
|
145
|
+
end
|
146
|
+
|
147
|
+
class CodeLinkHandler
|
148
|
+
|
149
|
+
def initialize(location=`window.location`)
|
150
|
+
@location = Native(location) # inject this so we can test
|
151
|
+
end
|
152
|
+
|
153
|
+
def create_link_for_code code
|
154
|
+
if code
|
155
|
+
@location.origin + @location.pathname + "#code:" + `encodeURIComponent(#{code})`
|
156
|
+
else
|
157
|
+
nil
|
158
|
+
end
|
159
|
+
end
|
160
|
+
# initialize irb w/link passed in code ala try opal
|
161
|
+
def grab_link_code
|
162
|
+
link_code = `decodeURIComponent(#{@location.hash})`
|
163
|
+
if link_code != ''
|
164
|
+
link_code[6..-1]
|
165
|
+
else
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
def irb_link_for history_num
|
173
|
+
history_num = -1 unless history_num # pick last command before irb_link_for if nil
|
174
|
+
history_num -= 1 # offset off by 1
|
175
|
+
code = jqconsole.GetHistory[history_num] #
|
176
|
+
create_and_display_code_link code
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
def irb_link_for_current_line
|
181
|
+
current_code = jqconsole.GetPromptText
|
182
|
+
create_and_display_code_link current_code
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
def redirect_console_dot_log
|
187
|
+
OpalIrbLogRedirector.add_to_redirect(lambda {|args| OpalIrbJqconsole.write(args)})
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
def create_multiline_editor
|
192
|
+
editor = <<EDITOR
|
193
|
+
<div id="multiline-editor-dialog" class="dialog" style="display:none" >
|
194
|
+
<textarea name="multi_line_input" id="multi_line_input"></textarea>
|
195
|
+
</div>
|
196
|
+
EDITOR
|
197
|
+
myself = self # self is now the div and not self anymore
|
198
|
+
Element.find("body") << editor
|
199
|
+
%x|
|
200
|
+
$( ".dialog" ).dialog({
|
201
|
+
autoOpen: false,
|
202
|
+
show: "blind",
|
203
|
+
hide: "explode",
|
204
|
+
modal: true,
|
205
|
+
width: "500px",
|
206
|
+
title: "Multi Line Edit",
|
207
|
+
buttons: {
|
208
|
+
"Run it": function() {
|
209
|
+
$( this ).dialog( "close" );
|
210
|
+
#{myself}.$process_multiline();
|
211
|
+
},
|
212
|
+
"Cancel": function() {
|
213
|
+
$( this ).dialog( "close" );
|
214
|
+
},
|
215
|
+
}
|
216
|
+
});
|
217
|
+
|
|
218
|
+
|
219
|
+
@open_editor_dialog_function = %x|function() {
|
220
|
+
$( ".dialog" ).dialog( "open" );
|
221
|
+
setTimeout(function(){editor.refresh();}, 20);
|
222
|
+
}
|
223
|
+
|
|
224
|
+
# setup opal auto complete
|
225
|
+
OpalIrb::CompletionEngine.set_irb @irb
|
226
|
+
%x*
|
227
|
+
var WORD = /[\w$]+/, RANGE = 500;
|
228
|
+
CodeMirror.commands.autocomplete = function(cm) {
|
229
|
+
CodeMirror.showHint(cm, function(editor, options) {
|
230
|
+
var word = options && options.word || WORD;
|
231
|
+
var range = options && options.range || RANGE;
|
232
|
+
var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
|
233
|
+
var end = cur.ch, start = end;
|
234
|
+
// debugger
|
235
|
+
while (start && word.test(curLine.charAt(start - 1))) --start;
|
236
|
+
var curWord = start != end && curLine.slice(start, end);
|
237
|
+
var token = editor.getTokenAt(editor.getCursor()).string;
|
238
|
+
console.orig_log('The receiver is');
|
239
|
+
|
240
|
+
if( token.string === '.') {
|
241
|
+
var receiver = editor.getTokenAt(CodeMirror.Pos(cur.line, start-1)).string;
|
242
|
+
console.orig_log(receiver);
|
243
|
+
// token = receiver + ".";
|
244
|
+
}
|
245
|
+
var anyList = CodeMirror.hint.anyword(editor, options);
|
246
|
+
var list = Opal.OpalIrb.CompletionEngine.$editor_complete(token);
|
247
|
+
list = list.concat(anyList.list);
|
248
|
+
return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)};
|
249
|
+
}
|
250
|
+
);
|
251
|
+
};
|
252
|
+
*
|
253
|
+
@editor = %x|
|
254
|
+
editor = CodeMirror.fromTextArea(document.getElementById("multi_line_input"),
|
255
|
+
{ mode: "ruby",
|
256
|
+
lineNumbers: true,
|
257
|
+
matchBrackets: true,
|
258
|
+
extraKeys: {
|
259
|
+
"Ctrl-Space": "autocomplete",
|
260
|
+
"Ctrl-Enter": function(cm) { $(".ui-dialog-buttonset").find("button:eq(0)").trigger("click"); } // submit on ctrl-enter
|
261
|
+
},
|
262
|
+
keyMap: "emacs",
|
263
|
+
/* foldGutter: {
|
264
|
+
rangeFinder: new CodeMirror.fold.combine(CodeMirror.fold.brace, CodeMirror.fold.comment)
|
265
|
+
},
|
266
|
+
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], */
|
267
|
+
theme: "default"
|
268
|
+
});
|
269
|
+
|
270
|
+
|
|
271
|
+
@editor = Native(@editor) # seamless bridging removed
|
272
|
+
|
273
|
+
end
|
274
|
+
def open_multiline_dialog
|
275
|
+
@editor.setValue(@jqconsole.GetPromptText)
|
276
|
+
@open_editor_dialog_function.call
|
277
|
+
end
|
278
|
+
|
279
|
+
def print_and_process_code code
|
280
|
+
@jqconsole.SetPromptText code
|
281
|
+
@jqconsole._HandleEnter
|
282
|
+
end
|
283
|
+
|
284
|
+
def process_multiline
|
285
|
+
multi_line_value = @editor.getValue.sub(/(\n)+$/, "")
|
286
|
+
print_and_process_code multi_line_value
|
287
|
+
end
|
288
|
+
|
289
|
+
# show completions on hitting tab. This modeled after irb.
|
290
|
+
# * If there are completions it will print the prompt, show the
|
291
|
+
# completions and reprint the prompt line. Same as irb behavior,
|
292
|
+
# but these are the steps you need to take w/jq-console
|
293
|
+
# * If no completions it acts as jq-console tab
|
294
|
+
# @param text [String] text on the opal-irb command line
|
295
|
+
# @returns [Boolean] returns true if opal-irb is to actually tab - i.e. no completion found
|
296
|
+
# results.prompt_change(@jqconsole, 'jqconsole-old-prompt')
|
297
|
+
# results.write_results(@jqconsole)
|
298
|
+
# results.change_prompt(@jqconsole)
|
299
|
+
def tab_complete(text)
|
300
|
+
results = OpalIrb::CompletionEngine.complete(text, @irb)
|
301
|
+
# if results
|
302
|
+
# if results.size > 1
|
303
|
+
# @jqconsole.Write("#{CONSOLE_PROMPT}#{text}\n", "jqconsole-old-prompt")
|
304
|
+
# @jqconsole.Write(OpalIrb::CompletionFormatter.format(results))
|
305
|
+
# append_common_prefix_if_exists(text, results)
|
306
|
+
# else
|
307
|
+
# @jqconsole.SetPromptText(results.first)
|
308
|
+
# end
|
309
|
+
# false
|
310
|
+
# else
|
311
|
+
# true
|
312
|
+
# end
|
313
|
+
results.set_old_prompt(@jqconsole, CONSOLE_PROMPT, 'jqconsole-old-prompt')
|
314
|
+
results.display_matches(@jqconsole)
|
315
|
+
results.update_prompt(@jqconsole)
|
316
|
+
results.insert_tab?
|
317
|
+
end
|
318
|
+
|
319
|
+
|
320
|
+
CONSOLE_PROMPT = 'opal> '
|
321
|
+
attr_reader :jqconsole
|
322
|
+
def setup_jqconsole(parent_element_id)
|
323
|
+
Element.expose(:jqconsole)
|
324
|
+
|
325
|
+
@jqconsole = Native(Element.find(parent_element_id).jqconsole("Welcome to Opal #{Opal::VERSION}\ntype help for assistance\n", CONSOLE_PROMPT)) # seamless jquery plugin removed
|
326
|
+
@jqconsole.RegisterTabHandler(lambda { |text| tab_complete(text)})
|
327
|
+
@jqconsole.RegisterShortcut('M', lambda { open_multiline_dialog; handler})
|
328
|
+
@jqconsole.RegisterShortcut('C', lambda { @jqconsole.AbortPrompt(); handler})
|
329
|
+
|
330
|
+
# These are the ubiquitous emacs commands that I have to implement now, my other
|
331
|
+
# solution I got them all for free in OSX
|
332
|
+
@jqconsole.RegisterShortcut('A', lambda{ @jqconsole.MoveToStart(); handler})
|
333
|
+
@jqconsole.RegisterShortcut('E', lambda{ @jqconsole.MoveToEnd(); handler})
|
334
|
+
@jqconsole.RegisterShortcut('B', lambda{ @jqconsole._MoveLeft(); handler})
|
335
|
+
@jqconsole.RegisterShortcut('F', lambda{ @jqconsole._MoveRight(); handler})
|
336
|
+
@jqconsole.RegisterShortcut('N', lambda{ @jqconsole._HistoryNext(); handler})
|
337
|
+
@jqconsole.RegisterShortcut('P', lambda{ @jqconsole._HistoryPrevious(); handler})
|
338
|
+
@jqconsole.RegisterShortcut('D', lambda{ @jqconsole._Delete(); handler})
|
339
|
+
@jqconsole.RegisterShortcut('K', lambda{ @jqconsole.Kill; handler})
|
340
|
+
@jqconsole.RegisterShortcut('L', lambda{ irb_link_for_current_line})
|
341
|
+
|
342
|
+
@jqconsole.RegisterAltShortcut('B', lambda{ @jqconsole._MoveLeft(true); handler})
|
343
|
+
@jqconsole.RegisterAltShortcut('F', lambda{ @jqconsole._MoveRight(true); handler})
|
344
|
+
@jqconsole.RegisterAltShortcut('D', lambda{ @jqconsole._Delete(true); handler})
|
345
|
+
|
346
|
+
# to implement in jq-console emacs key bindings you get for free normally
|
347
|
+
# in all Cocoa text widgets
|
348
|
+
# alt-u upcase
|
349
|
+
# alt-l lowercase
|
350
|
+
# alt-c capitalize
|
351
|
+
# ctrl-t toggle character
|
352
|
+
# ctrl-y yanking the kill buffer - can I override the system here?
|
353
|
+
|
354
|
+
end
|
355
|
+
|
356
|
+
CMD_LINE_METHOD_DEFINITIONS = [
|
357
|
+
'def help
|
358
|
+
OpalIrbJqconsole.help
|
359
|
+
nil
|
360
|
+
end',
|
361
|
+
'def history
|
362
|
+
OpalIrbJqconsole.history
|
363
|
+
nil
|
364
|
+
end',
|
365
|
+
'def js_require(js_file)
|
366
|
+
s = DOM do
|
367
|
+
script({ src: js_file})
|
368
|
+
end
|
369
|
+
$document.body << s
|
370
|
+
end', # js_require "http://www.goodboydigital.com/runpixierun/js/pixi.js"
|
371
|
+
'def say msg
|
372
|
+
%x|
|
373
|
+
var msg = new SpeechSynthesisUtterance(#{msg});
|
374
|
+
window.speechSynthesis.speak(msg);
|
375
|
+
|
|
376
|
+
end'
|
377
|
+
|
378
|
+
]
|
379
|
+
def setup_cmd_line_methods
|
380
|
+
CMD_LINE_METHOD_DEFINITIONS.each {|method_definition|
|
381
|
+
compiled = @irb.parse method_definition
|
382
|
+
`eval(compiled)`
|
383
|
+
}
|
384
|
+
end
|
385
|
+
|
386
|
+
def self.history
|
387
|
+
history = @console.jqconsole.GetHistory
|
388
|
+
lines = []
|
389
|
+
history.each_with_index {|history_line, i|
|
390
|
+
lines << "#{i+1}: #{history_line}"
|
391
|
+
}
|
392
|
+
@console.jqconsole.Write("#{lines.join("\n")}\n")
|
393
|
+
|
394
|
+
end
|
395
|
+
|
396
|
+
|
397
|
+
def handler(cmd)
|
398
|
+
if cmd && `#{cmd } != undefined`
|
399
|
+
begin
|
400
|
+
@jqconsole.Write( " => #{process(cmd)} \n")
|
401
|
+
rescue Exception => e
|
402
|
+
@jqconsole.Write('Error: ' + e.message + "\n")
|
403
|
+
end
|
404
|
+
end
|
405
|
+
@jqconsole.Prompt(true, lambda {|c| handler(c) }, lambda {|c| check_is_incomplete(c)})
|
406
|
+
|
407
|
+
end
|
408
|
+
|
409
|
+
def check_is_incomplete(cmd)
|
410
|
+
begin
|
411
|
+
@irb.parse cmd
|
412
|
+
false
|
413
|
+
rescue Exception => e
|
414
|
+
# make this a global so we can inspect this
|
415
|
+
$check_error = e
|
416
|
+
# 1st attempt to return on bad code vs incomplete code
|
417
|
+
if parse_error? $check_error
|
418
|
+
# TODO when rescue is fixed to return last evaluated value remove returns
|
419
|
+
return 0
|
420
|
+
else
|
421
|
+
# see above to-do
|
422
|
+
return false
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
def parse_error? check_error
|
428
|
+
# for Chrome errors
|
429
|
+
check_error.backtrace.first =~ /unexpected 'false/ || check_error.backtrace[2] =~ /unexpected 'false/ ||
|
430
|
+
# safari error
|
431
|
+
check_error.message =~/error occurred while compiling/
|
432
|
+
end
|
433
|
+
|
434
|
+
|
435
|
+
def write *stuff
|
436
|
+
@jqconsole.Write *stuff
|
437
|
+
end
|
438
|
+
|
439
|
+
def unescaped_write str
|
440
|
+
# `#{@jqconsole}.Write(str, "unescaped", false)`
|
441
|
+
@jqconsole.Write(str, "unescaped", false)
|
442
|
+
end
|
443
|
+
|
444
|
+
def self.write *stuff
|
445
|
+
@console.write *stuff
|
446
|
+
end
|
447
|
+
|
448
|
+
def self.puts *stuff
|
449
|
+
@console.write *stuff
|
450
|
+
@console.write "\n"
|
451
|
+
end
|
452
|
+
|
453
|
+
def self.unescaped_write *stuff
|
454
|
+
@console.unescaped_write *stuff
|
455
|
+
|
456
|
+
end
|
457
|
+
|
458
|
+
def self.help
|
459
|
+
help = <<HELP
|
460
|
+
<b>help</b>: This text
|
461
|
+
<b>$_</b> last value returned is stored in this global
|
462
|
+
<b>history</b>: Shows history
|
463
|
+
<b>irb_link_for history_num</b>: Create a link for the code in the history
|
464
|
+
<b>ctrl-c</b>: Abort prompt
|
465
|
+
<b>ctrl-m</b>: Pop up multi-line editor
|
466
|
+
<b>ctrl-Enter</b>: Submit code in multi-line editor
|
467
|
+
<b>ctrl-l</b>: Creates a link with the code you have on the current line/lines
|
468
|
+
<hr/>
|
469
|
+
<b>EDITOR FUNCTIONALITY</b>
|
470
|
+
<b>Up/Down Arrow and ctrl-p/ctrl-n</b>: Navigate through history
|
471
|
+
<b>ctrl-a</b>: Beginning of line
|
472
|
+
<b>ctrl-e</b>: End of line
|
473
|
+
<b>ctrl-b</b>: Back 1 character
|
474
|
+
<b>ctrl-f</b>: Forward 1 character
|
475
|
+
<b>ctrl-d</b>: Delete 1 character
|
476
|
+
<b>ctrl-k</b>: Kill to the end of the line
|
477
|
+
<b>alt-b</b>: Back 1 word
|
478
|
+
<b>alt-f</b>: Forward 1 word
|
479
|
+
<b>alt-d</b>: Delete 1 word
|
480
|
+
HELP
|
481
|
+
unescaped_write help
|
482
|
+
end
|
483
|
+
|
484
|
+
|
485
|
+
def process(cmd)
|
486
|
+
begin
|
487
|
+
log "\n\n|#{cmd}|"
|
488
|
+
if cmd
|
489
|
+
$last_cmd = cmd
|
490
|
+
$irb_last_compiled = @irb.parse cmd
|
491
|
+
log $irb_last_compiled
|
492
|
+
value = `eval(#{$irb_last_compiled})`
|
493
|
+
$_ = value
|
494
|
+
Native($_).inspect # coz native JS objects don't support inspect
|
495
|
+
end
|
496
|
+
rescue Exception => e
|
497
|
+
$last_exception = e
|
498
|
+
# alert e.backtrace.join("\n")
|
499
|
+
if e.backtrace
|
500
|
+
output = "FOR:\n#{$irb_last_compiled}\n============\n" + "#{e.message}\n" + e.backtrace.join("\n")
|
501
|
+
# TODO remove return when bug is fixed in rescue block
|
502
|
+
return output
|
503
|
+
# FF doesn't have Error.toString() as the first line of Error.stack
|
504
|
+
# while Chrome does.
|
505
|
+
# if output.split("\n")[0] != `e.toString()`
|
506
|
+
# output = "#{`e.toString()`}\n#{`e.stack`}"
|
507
|
+
# end
|
508
|
+
else
|
509
|
+
output = `e.toString()`
|
510
|
+
log "\nReturning NO have backtrace |#{output}|"
|
511
|
+
# TODO remove return when bug is fixed in rescue block
|
512
|
+
return output
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
end
|