Class: Chitin::Session
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#editor ⇒ Object
readonly
Returns the value of attribute editor.
-
#out ⇒ Object
Returns the value of attribute out.
-
#sandbox ⇒ Object
Returns the value of attribute sandbox.
Instance Method Summary collapse
- #all_not_ruby?(res) ⇒ Boolean (also: #all_shell?)
- #display(res) ⇒ Object
-
#evaluate(val) ⇒ Object
we need to save the frame or something i think.
-
#initialize(config = nil) ⇒ Session
constructor
A new instance of Session.
- #inspect ⇒ Object
- #print(*args) ⇒ Object
- #puts(*args) ⇒ Object
-
#read ⇒ Object
THIS METHOD WILL POSSIBLY RETURN NIL!!!!! So it can return a string or nil.
- #returning_ruby?(res) ⇒ Boolean
-
#start ⇒ Object
Read Evaluate Print (display) Loop.
Constructor Details
#initialize(config = nil) ⇒ Session
Returns a new instance of Session.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/chitin/session.rb', line 11 def initialize(config=nil) @config = config @out = STDOUT @sandbox = Sandbox.new # give it its own private space to work (class << @sandbox; self; end).send :include, @config # include the config and builtins @editor = Coolline.new do |c| # Remove the default of '-' and add support for strings # starting after parentheses. c.word_boundaries = [' ', "\t", "(", ")", '[', ']'] c.history_file = File.join ENV['HOME'], '.chitin_history' # Make sure we don't kill the shell accidentally when we're trying to # kill a file. That's what the default does, so we're overriding that # here. c.bind(?\C-c) {} c.transform_proc = proc do CodeRay.scan(c.line, :ruby).term end c.completion_proc = Proc.new do line = c.completed_word # expand ~ to homedir if line.start_with? '~' line = ENV['HOME'] + line[1..-1] end # if there's a quote, remove it. we'll add it back in later, but it ruins # searching so we need it removed for now. unquoted_line = ['"', '\''].include?(line[0, 1]) ? line[1..-1] : line #options = Dir[unquoted_line + '*'] #options += Dir[unquoted_line + '*'].map do |w| slash_it = File.directory?(w) and line[-1] != '/' and w[-1] != '/' "\"#{w}#{slash_it ? '/' : ''}" end end end if @sandbox.completion_proc @editor.completion_proc = @sandbox.completion_proc end end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
8 9 10 |
# File 'lib/chitin/session.rb', line 8 def config @config end |
#editor ⇒ Object (readonly)
Returns the value of attribute editor.
9 10 11 |
# File 'lib/chitin/session.rb', line 9 def editor @editor end |
#out ⇒ Object
Returns the value of attribute out.
6 7 8 |
# File 'lib/chitin/session.rb', line 6 def out @out end |
#sandbox ⇒ Object
Returns the value of attribute sandbox.
5 6 7 |
# File 'lib/chitin/session.rb', line 5 def sandbox @sandbox end |
Instance Method Details
#all_not_ruby?(res) ⇒ Boolean Also known as: all_shell?
129 130 131 132 133 134 135 |
# File 'lib/chitin/session.rb', line 129 def all_not_ruby?(res) if Array === res !res.empty? && res.map {|r| not returning_ruby? r }.all? else not returning_ruby? res end end |
#display(res) ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/chitin/session.rb', line 138 def display(res) # The reason that this is here instead of in #evaluate is that # pipes could, in fact, have NO display output, but that isn't for # #evaluate to decide: rather, it is for #display if all_shell? res res = [res] unless Array === res res.each do |res| res[:run] res[:wait] unless res[:bg] end else # else it's a standard ruby type (or a pipe returning as such) if Pipe === res || StringMethod === res val = res[:raw_run] else val = res end # if the input is ruby, then this is redundant # if the input is a pipe that returns ruby, # then this is needed because while the expression # returns a pipe, when we run it it returns a ruby # value. we want to remember the ruby value. @sandbox.previous = val txt = @config.post_processing[:color].call val.inspect puts " => #{txt}" end # Run all the post_processing stuff # Not sure where I should really put this or what arguments it should have @config.post_processing[:default].each {|b| b.call } end |
#evaluate(val) ⇒ Object
we need to save the frame or something i think. could use fibers to make the whole thing a generator so that original frame would be saved. why did i write those lines. that makes no sense. AH now i remember. we need to save a frame and use that frame as a sandbox.
110 111 112 113 114 115 |
# File 'lib/chitin/session.rb', line 110 def evaluate(val) val.strip! @config.pre_processing[:default].each {|p| val = p.call val } @sandbox.evaluate val end |
#inspect ⇒ Object
182 183 184 |
# File 'lib/chitin/session.rb', line 182 def inspect "#<Chitin::Session #{object_id}>" end |
#print(*args) ⇒ Object
178 179 180 |
# File 'lib/chitin/session.rb', line 178 def print(*args) @out.print *args end |
#puts(*args) ⇒ Object
174 175 176 |
# File 'lib/chitin/session.rb', line 174 def puts(*args) @out.puts *args end |
#read ⇒ Object
THIS METHOD WILL POSSIBLY RETURN NIL!!!!! So it can return a string or nil. Remember that, folks.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/chitin/session.rb', line 85 def read # find out the column (1-indexed) that will next be printed # if it's NOT 1, then something was printed, and we want to insert # a newline a = nil STDIN.raw do print "\e[6n" a = STDIN.gets 'R' end if a.chomp('R').split(';').last != '1' puts puts "(no trailing newline)" end inp = @editor.readline @sandbox.prompt inp ? inp.chomp : nil # return nil so that the while loop in #start can end end |
#returning_ruby?(res) ⇒ Boolean
117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/chitin/session.rb', line 117 def returning_ruby?(res) # We have to use #stat here because reopened pipes retain the file # descriptor of the original pipe. Example: # r, w = IO.pipe; r.reopen STDIN; r == STDIN # => false # Thus, we have to use #stat (or, more lamely, #inspect). return true unless Runnable === res res[:returning] == :ruby && (res[:out] == nil || res[:out].stat == STDOUT.stat) end |
#start ⇒ Object
Read Evaluate Print (display) Loop
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/chitin/session.rb', line 64 def start while (val = read) next if val.empty? begin res = evaluate val display res unless val.lstrip[0, 1] == '#' rescue StandardError, ScriptError, Interrupt => e @config.post_processing[e.class].call e, val print e.backtrace.first, ': ' puts "#{e.} (#{e.class})" e.backtrace[1..-1].each {|l| puts "\t#{l}" } nil end end end |