#! /usr/bin/env ruby # # This is version 0.1.1 of Gilles Filippini's FXIrb, an attempt to embed # IRB into an FXRuby FXText widget. The master page for this is here: # # http://www.rubygarden.org/ruby?FXIrb # # TODO # - handle user input redirection # - ^D # - readonly everywhere but for the command line # - readline require "irb" require "singleton" require "fcntl" module IRB def IRB.start_in_fxirb(redir) IRB.initialize(nil) IRB.parse_opts IRB.load_modules irb = Irb.new(nil, redir) @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC] @CONF[:MAIN_CONTEXT] = irb.context trap("SIGINT") do irb.signal_handle end catch(:IRB_EXIT) do irb.eval_input end print "\n" end end class Redirect < IRB::StdioInputMethod def initialize(dest) super() @dest = dest end def gets close @dest.write(prompt) str = @dest.gets(@prompt) if /^exit/ =~ str exit end @line[@line_no += 1] = str end def close if @thread $defout = @old_out.dup $stderr = @old_err.dup $stdin = @old_in.dup @output[1].close @thread.join end end def redir @output = IO.pipe @old_out = $defout.dup @old_err = $stderr.dup @old_in = $stdin.dup $stdin = @dest.input[0] $defout = $stderr = @output[1] @output[1].fcntl(Fcntl::F_SETFL, File::NONBLOCK) @thread = Thread.new { while not @output[0].eof? select([@output[0]]) @dest.write(@output[0].read) end @output[0].close } end end module Fox class FXIrb < FXText include Singleton include Responder attr_reader :input def FXIrb.init(p, tgt, sel, opts) unless @__instance__ Thread.critical = true begin @__instance__ ||= new(p, tgt, sel, opts) ensure Thread.critical = false end end return @__instance__ end def initialize(p, tgt, sel, opts) FXMAPFUNC(SEL_KEYRELEASE, 0, "onKeyRelease") super setFont(FXFont.new(FXApp.instance, "-misc-fixed-medium-r-semicondensed-*-*-120-*-*-c-*-iso8859-1")) end def create super setFocus # IRB initialization @redir = Redirect.new(self) @input = IO.pipe @irb = Thread.new { IRB.start_in_fxirb(@redir) } end def onKeyRelease(sender, sel, event) if [Fox::KEY_Return, Fox::KEY_KP_Enter].include?(event.code) newLineEntered end return 1 end def newLineEntered if @running start = prevLine(getLength) @input[1].puts(extractText(start, getLength - start)) else processCommandLine(extractText(@anchor, getLength-@anchor)) end end def processCommandLine(cmd) @redir.redir @running = true @input[1].puts cmd end def sendCommand(cmd) setCursorPos(getLength) makePositionVisible(getLength) unless isPosVisible(getLength) cmd += "\n" appendText(cmd) processCommandLine(cmd) end def write(obj) str = obj.to_s appendText(str) setCursorPos(getLength) makePositionVisible(getLength) unless isPosVisible(getLength) return str.length end def gets(prompt) @running = false @anchor = getLength return @input[0].gets end end end # Stand alone run if __FILE__ == $0 include Fox application = FXApp.new("FXIrb", "ruby") Thread.abort_on_exception = true application.init(ARGV) window = FXMainWindow.new(application, "FXIrb", nil, nil, DECOR_ALL, 0, 0, 580, 600) FXIrb.init(window, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y) application.create window.show(PLACEMENT_SCREEN) application.run end