freeride-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[FR-devel] FXIrb (Windows problem solved: blocking pipes)


From: Marco Frailis
Subject: [FR-devel] FXIrb (Windows problem solved: blocking pipes)
Date: Fri, 27 Dec 2002 18:57:14 +0100 (CET)

Hi,

I've seen that some month ago there was an attempt to embed irb into 
FreeRIDE, so maybe some of you is interested to this topic. FXIrb is a 
widget which embeds irb and has been developed by Gilles Filippini  
(http://www.rubygarden.org/ruby?FXIrb). On Windows platform  it 
freezes because of blocking pipes, that is, when a thread does "gets" on 
one hand of a pipe and on the other hand of the pipe nothing has been put 
yet, than the thread continues to wait something, blocking also the 
scheduling of other threads (on Linux it simply goes into sleep status 
until something is put on the pipe, so the other threads can go on). Maybe 
this is a problem only of ruby compilded by Visual C++.
I've done a little workaround to let it work on both platforms 
I 've also added the commands history (using up/down arrows) and a 
widget behaviour more similar to a terminal. So here it is the code:

-----------------------------------------------------------------

#! /usr/bin/env ruby

# TODO
# - handle user input redirection
# - ^D
# - readline

require "fox"
require "irb"
require "singleton"

include Fox

STDOUT.sync = true

module IOEmulate # Named after RubyWin's IOEmulate module
  def gets
    return FXIrb.instance.gets
  end
  
  def p(obj)
    return FXIrb.instance.write(obj.to_s + "\n")
  end
  
  def putc(ch)
    FXIrb.instance.write("" << ch)
  end
end

include IOEmulate

class FXIRBInputMethod < IRB::StdioInputMethod

  attr_reader :line_no

  def initialize
    super 
    @history = 1
  end

  def gets 
    print @prompt
    str = IOEmulate.gets
    if /^exit/ =~ str
      exit
    end
    @line_no += 1
    @history = @line_no + 1
    @address@hidden = str
  end

  def prevCmd
    @history -= 1 unless @history <= 1
    return @history
  end

  def nextCmd
    @history += 1 unless @history >= @line_no
    return @history
  end

end

module IRB

  def IRB.start_in_fxirb(im)
#     IRB.initialize(nil)
#     IRB.parse_opts
#     IRB.load_modules

    IRB.setup(nil)

    irb = Irb.new(nil, im)    

    @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 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")
    FXMAPFUNC(SEL_KEYPRESS, 0, "onKeyPress")
    FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,"onLeftBtnPress")
    FXMAPFUNC(SEL_MIDDLEBUTTONPRESS,0,"onMiddleBtnPress")

    super
    
setFont(FXFont.new(FXApp.instance,"-misc-fixed-medium-r-semicondensed-*-*-120-*-*-c-*-iso8859-1"))
  end
  
  def create
    super
    setFocus
    # IRB initialization
    @inputAdded = false
    @input = IO.pipe
    $> = self
    @im = FXIRBInputMethod.new
    @irb = Thread.new {
      IRB.start_in_fxirb(@im)
    }
  end
  
  def onKeyRelease(sender, sel, event)
    case event.code
      when Fox::KEY_Return, Fox::KEY_KP_Enter
        newLineEntered
    end
    return 1
  end
  
  def onKeyPress(sender,sel,event)
    case event.code    
      when Fox::KEY_Up,Fox::KEY_KP_Up
        if @im.line_no>0
          removeText(@anchor, address@hidden)
          write(@im.line(@im.prevCmd).chop)
        end
      when Fox::KEY_Down,Fox::KEY_KP_Down
        if @im.line_no>0
          removeText(@anchor, address@hidden)
          write(@im.line(@im.nextCmd).chop)
        end
      when Fox::KEY_Left,Fox::KEY_KP_Left
        if getCursorPos > @anchor
          super
        end
      when Fox::KEY_Delete,Fox::KEY_KP_Delete,Fox::KEY_BackSpace
        if getCursorPos > @anchor
          super
        end
      else
        super
    end
  end

  def onLeftBtnPress(sender,sel,event)
    pos=getPosAt(event.win_x,event.win_y)
    if pos >= @anchor
      super
    end
  end

  def onMiddleBtnPress(sender,sel,event)
        pos=getPosAt(event.win_x,event.win_y)
        if pos >= @anchor
      super
    end
  end

  def newLineEntered
    processCommandLine(extractText(@anchor, address@hidden))
  end
  
  def processCommandLine(cmd)
    @input[1].puts cmd
    @inputAdded = true
    @irb.run
  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
    @anchor = getLength
    if address@hidden
      Thread.stop
    end
    @inputAdded = false
    return @input[0].gets
  end
end

# Stand alone run
if __FILE__ == $0
  application = FXApp.new("FXIrb", "ruby")
  application.threadsEnabled = true
  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|TEXT_OVERSTRIKE)
  application.create
  window.show(PLACEMENT_SCREEN)
  application.run
end






reply via email to

[Prev in Thread] Current Thread [Next in Thread]