| 1 | require 'irb/ruby-lex' |
|---|
| 2 | require 'stringio' |
|---|
| 3 | |
|---|
| 4 | class MimickIRB < RubyLex |
|---|
| 5 | attr_accessor :started |
|---|
| 6 | |
|---|
| 7 | class Continue < StandardError; end |
|---|
| 8 | class Empty < StandardError; end |
|---|
| 9 | |
|---|
| 10 | def initialize |
|---|
| 11 | super |
|---|
| 12 | set_input(StringIO.new) |
|---|
| 13 | end |
|---|
| 14 | |
|---|
| 15 | def run(str) |
|---|
| 16 | obj = nil |
|---|
| 17 | @io << str |
|---|
| 18 | @io.rewind |
|---|
| 19 | unless l = lex |
|---|
| 20 | raise Empty if @line == '' |
|---|
| 21 | else |
|---|
| 22 | case l.strip |
|---|
| 23 | when "reset" |
|---|
| 24 | @line = "" |
|---|
| 25 | when "time" |
|---|
| 26 | @line = "puts %{You started \#{IRBalike.started.since} ago.}" |
|---|
| 27 | else |
|---|
| 28 | @line << l << "\n" |
|---|
| 29 | if @ltype or @continue or @indent > 0 |
|---|
| 30 | raise Continue |
|---|
| 31 | end |
|---|
| 32 | end |
|---|
| 33 | end |
|---|
| 34 | unless @line.empty? |
|---|
| 35 | obj = eval @line, TOPLEVEL_BINDING, "(irb)", @line_no |
|---|
| 36 | end |
|---|
| 37 | @line_no += @line.scan(/\n/).length |
|---|
| 38 | @line = '' |
|---|
| 39 | @exp_line_no = @line_no |
|---|
| 40 | |
|---|
| 41 | @indent = 0 |
|---|
| 42 | @indent_stack = [] |
|---|
| 43 | |
|---|
| 44 | $stdout.rewind |
|---|
| 45 | output = $stdout.read |
|---|
| 46 | $stdout.truncate(0) |
|---|
| 47 | $stdout.rewind |
|---|
| 48 | [output, obj] |
|---|
| 49 | rescue Object => e |
|---|
| 50 | case e when Empty, Continue |
|---|
| 51 | else @line = "" |
|---|
| 52 | end |
|---|
| 53 | raise e |
|---|
| 54 | ensure |
|---|
| 55 | set_input(StringIO.new) |
|---|
| 56 | end |
|---|
| 57 | |
|---|
| 58 | end |
|---|
| 59 | |
|---|
| 60 | CURSOR = ">>" |
|---|
| 61 | IRBalike = MimickIRB.new |
|---|
| 62 | $stdout = StringIO.new |
|---|
| 63 | |
|---|
| 64 | Shoes.app do |
|---|
| 65 | @str, @cmd = [CURSOR + " "], "" |
|---|
| 66 | stack do |
|---|
| 67 | background "#555" |
|---|
| 68 | para "Interactive Ruby ready.", :fill => white, :stroke => red |
|---|
| 69 | @scroll = |
|---|
| 70 | stack :width => 1.0, :height => 400 do |
|---|
| 71 | background "#555" |
|---|
| 72 | @console = para @str, :font => "Monospace 12px", :stroke => "#dfa" |
|---|
| 73 | @console.cursor = -1 |
|---|
| 74 | end |
|---|
| 75 | end |
|---|
| 76 | keypress do |k| |
|---|
| 77 | case k |
|---|
| 78 | when "\n" |
|---|
| 79 | begin |
|---|
| 80 | out, obj = IRBalike.run(@cmd) |
|---|
| 81 | @str += ["#@cmd\n", |
|---|
| 82 | span("#{out}=> #{obj.inspect}\n", :stroke => "#fda"), |
|---|
| 83 | "#{CURSOR} "] |
|---|
| 84 | @cmd = "" |
|---|
| 85 | rescue MimickIRB::Empty |
|---|
| 86 | rescue MimickIRB::Continue |
|---|
| 87 | @str += ["#@cmd\n.. "] |
|---|
| 88 | @cmd = "" |
|---|
| 89 | rescue Object => e |
|---|
| 90 | @str += ["#@cmd\n", span("#{e.class}: #{e.message}\n", :stroke => "#fcf"), |
|---|
| 91 | "#{CURSOR} "] |
|---|
| 92 | @cmd = "" |
|---|
| 93 | end |
|---|
| 94 | when String |
|---|
| 95 | @cmd += k |
|---|
| 96 | when :backspace |
|---|
| 97 | @cmd.slice!(-1) |
|---|
| 98 | when :tab |
|---|
| 99 | @cmd += " " |
|---|
| 100 | when :alt_q |
|---|
| 101 | quit |
|---|
| 102 | when :alt_c |
|---|
| 103 | self.clipboard = @cmd |
|---|
| 104 | when :alt_v |
|---|
| 105 | @cmd += self.clipboard |
|---|
| 106 | end |
|---|
| 107 | @console.replace *(@str + [@cmd]) |
|---|
| 108 | @scroll.scroll_top = @scroll.scroll_max |
|---|
| 109 | end |
|---|
| 110 | end |
|---|