[ANN] fxirb 0.2.0 - Multiline Edit (and request for help)

M

Martin DeMello

available at http://rubyforge.org/projects/fxirb/

Finally got around to my 0.2 milestone, proper multiline editing.

You can now:

1. Paste in a multiline block of code and edit it immediately using all
four arrow keys

2. Enter a multiline block line by line, and have it occupy a single
multiline slot in the history once it's done

3. Edit a multiline history item using all four arrow keys

Associated behaviour change:

Up/Down arrows now only scroll history if not in multiline mode
PgUp/PgDn always scroll history

The other major change is the ability to pass in an on_exit block, which
is instance_evaled by the FxIRB widget when its internal IRB thread
exits. Usage:

fxirb = FXIrb.init(window, nil, 0,
LAYOUT_FILL_X|LAYOUT_FILL_Y|TEXT_WORDWRAP|TEXT_SHOWACTIVE)
fxirb.on_exit {exit}

This should make it possible to embed fxirb in another application, and
not have the whole application exit when IRB exits.

The target for the 0.3 and 0.4 milestones are a menu-and-button frame in
standalone mode, and an implementation of 'gets' (I really would like
some help with the latter - I don't know enough about IRB internals or
FOX to see what I need to do. To see the problem, just start up FXIrb
and type in "a = gets")

martin

Changelog:

0.2.0 - Martin DeMello - 2005/04/10
* Multiline edit
* Settable on_exit proc

0.1.4 - Martin DeMello - 2005/02/19
* Minor code cleanup
* Dedentation on ], } or end
* Ctrl-D, Ctrl-U and Ctrl-K keys bound

0.1.3 - Martin DeMello - 2004/03/21

* Added ability to select text, and return the cursor to the proper position
* Changed font to Lucida Console
* Added indentation

0.1.2 - Frailis - 2003/01/10

* Fixed commands history

0.1.1 - Frailis - 2003/01/07

* Removed IOEmulate module because it redirects every "p" operation in a program which embeds FXIrb

0.1.0 - Frailis - 2003/01/02

* Tested on ruby 1.6.7 and 1.7.3
* Added commands history and terminal behaviour
 
B

B. K. Oxley (binkley)

To use fxirb I need fox12 but am having difficulty using gem to install
it on Cygwin. What is the suggestion for getting fox ruby support for
Cygwin?


Cheers,
--binkley
 
M

Martin DeMello

B. K. Oxley (binkley) said:
To use fxirb I need fox12 but am having difficulty using gem to install
it on Cygwin. What is the suggestion for getting fox ruby support for
Cygwin?

Sorry, I've never tried this - I just use the one-click installer.

http://www.fox-toolkit.org/install.html suggests that fox compiles
cleanly under cygwin, at least.

Also, I'm not using any fancy fox features, so it should be possible to get
this running under Fox 1.0 if that is less problematic than 1.2. Let me
know if you need to go down that route, and I'll help port it back to
1.0 (IIRC porting it to 1.2 in the first place was trivial, but I don't
have a Fox 1.0 install around any more to check it).

martin
 
P

Peter Suk

To use fxirb I need fox12 but am having difficulty using gem to
install it on Cygwin. What is the suggestion for getting fox ruby
support for Cygwin?

Binkley,

Would you be interested in getting together sometime? Feel free to
give me a call. 713-807-9023.

--Peter
 
P

Peter Suk

To use fxirb I need fox12 but am having difficulty using gem to
install it on Cygwin. What is the suggestion for getting fox ruby
support for Cygwin?

Drat, I didn't mean to send to that address!

--Peter
 
C

Csaba Henk

available at http://rubyforge.org/projects/fxirb/

Finally got around to my 0.2 milestone, proper multiline editing.

That sounds cool. I wanted to give it a try under Linux, but with my
existing fxruby installation (1.2.2) it segfaulted; then I upgraded my
fxruby to 1.2.5, which just hanged upon pressing enter.
The target for the 0.3 and 0.4 milestones are a menu-and-button frame in
standalone mode, and an implementation of 'gets' (I really would like
some help with the latter - I don't know enough about IRB internals or
FOX to see what I need to do. To see the problem, just start up FXIrb
and type in "a = gets")

What's the problem? As you can see, I can't try this now.

Csaba
 
M

Martin DeMello

itsme213 said:
in message news:Wtc6e.953812$8l.185173@pd7tw1no...

Thanks! I'm getting quite a nice flow between my editor and fxirb now!

btw, on XP some messages (streams?) seem to come out on the command window,
not the fx window e.g.
(irb):14: warning: parenthesize argument(s) for future version
(irb):14: warning: parenthesize argument(s) for future version

Can you paste in a sample session? Not seen this happen on Win2k.

martin
 
M

Martin DeMello

Csaba Henk said:
That sounds cool. I wanted to give it a try under Linux, but with my
existing fxruby installation (1.2.2) it segfaulted; then I upgraded my
fxruby to 1.2.5, which just hanged upon pressing enter.

I've not tested this at all under linux - I based it off Marco Frailis's
win32 fxirb. I should make that my next priority, actually - it's
somewhat more useful than a menu and button frame :).

martin
 
M

Martin DeMello

Csaba Henk said:
What's the problem? As you can see, I can't try this now.

The whole thing just hangs up (windows says 'this application is not
responding'). I thought it might be infinitely recursing
FXIRBInputMethod#gets, but it isn't, so I'm at a bit of a loss as how to
even debug it (no stack trace).

martin
 
C

Csaba Henk

The whole thing just hangs up (windows says 'this application is not
responding'). I thought it might be infinitely recursing
FXIRBInputMethod#gets, but it isn't, so I'm at a bit of a loss as how to
even debug it (no stack trace).

A line read by irb is evaluated in an IRB::Irb instance (that class is
defined in irb.rb). As I can read fxirb.rb, you didn't overwrite #gets
anywhere seeked by IRB::Irb upon method lookup. So what happens is that
the good old Kernel#gets is called.

Csaba
 
M

Martin DeMello

Csaba Henk said:
A line read by irb is evaluated in an IRB::Irb instance (that class is
defined in irb.rb). As I can read fxirb.rb, you didn't overwrite #gets
anywhere seeked by IRB::Irb upon method lookup. So what happens is that
the good old Kernel#gets is called.

I tried IRB::Irb#gets and IRB::Context#gets, but neither of them were
getting called. It did indeed turn out to be Kernel#gets - is it safe to
just override that?

martin
 
C

Csaba Henk

I tried IRB::Irb#gets and IRB::Context#gets, but neither of them were
getting called. It did indeed turn out to be Kernel#gets - is it safe to
just override that?

I'm sorry, I was wrong. A command read by irb is evaluated
in the toplevel.

In general, you can access the toplevel object as

eval "self", TOPLEVEL_BINDING

but with irb, the api-friendly way is as follows:

IRB.context.workspace.main

(that is, with an alternative config this might differ from the toplevel
object, but this form always gives you the object which is used by irb
for evaluation).

So, just define #gets as a singleton method of the above object.

Csaba
 
M

Martin DeMello

Csaba Henk said:
but with irb, the api-friendly way is as follows:

IRB.context.workspace.main

irb.context.workspace.main actually
(that is, with an alternative config this might differ from the toplevel
object, but this form always gives you the object which is used by irb
for evaluation).

So, just define #gets as a singleton method of the above object.

perfect! thanks a lot - hopefully I'll actually manage to get something
working tonight.

martin
 
C

Csaba Henk

irb.context.workspace.main actually

Uh-oh. Stupid me, again.

irb.context.workspace.main

starts a new reader first, and when that's completes, it gives you the
respective IRB::Irb object. So even if that's the toplevel object again,
I don't think you really want this. IRB.context.workspace.main is the
correct solution, under the right circumstances... :) no wonder it
doesn't work for you. For my irb hacks, I use

module IRB
def self.context
conf[:MAIN_CONTEXT]
end
end

and having this, what I told you will work.

To put it simply:

IRB.conf[:MAIN_CONTEXT].workspace.main

is the right thing.

Sorry for iterating confusion.

Though... even the above will break if someone starts a subirb with a
different workspace.main. Not that likely, but why not. To get the
evaluator of the current irb object, you have to do something like

IRB.conf[:MAIN_CONTEXT].workspace.main.jobs.current_job.context.workspace.main

Whew! OK, I looked up how to simplify that:

IRB.JobManager.current_job.context.workspace.main

So, the purest solution would be to get #gets dynamically dispatch to
the vaule of the above expression.

Such things are handled by the module IRB::ExtendCommandBundle of
'irb/extend-command.rb'.

I guess by adding the right thing to @EXTEND_COMMANDS of the above,
the magic would happen. I don't know though if you can actually overwrite
existing methods this way. Maybe you'd have to do something with
IRB::ExtendCommandBundle.included.

I'd say that if you are lazy, just use
"IRB.conf[:MAIN_CONTEXT].workspace.main", that's a 97% solution at least
anyway.

Csaba
 
M

Martin DeMello

Csaba Henk said:
Uh-oh. Stupid me, again.

irb.context.workspace.main

starts a new reader first, and when that's completes, it gives you the
respective IRB::Irb object. So even if that's the toplevel object again,
I don't think you really want this. IRB.context.workspace.main is the
correct solution, under the right circumstances... :) no wonder it
doesn't work for you. For my irb hacks, I use

module IRB
def self.context
conf[:MAIN_CONTEXT]
end
end

and having this, what I told you will work.

I'm a bit confused about lifecycle issues now. What I have at the moment
is this:

module IRB

def IRB.start_in_fxirb(im)
if RUBY_VERSION < "1.7.3"
IRB.initialize(nil)
IRB.parse_opts
IRB.load_modules
else
IRB.setup(nil)
end

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

class << irb.context.workspace.main
def gets
inp = IRB.conf[:MAIN_CONTEXT].io
inp.gets_mode = true
retval = IRB.conf[:MAIN_CONTEXT].io.gets
inp.gets_mode = false
retval
end
end

catch:)IRB_EXIT) do
irb.eval_input
end
print "\n"

end

end

and inside the FXIrb class:

def create
super
setFocus
# IRB initialization
@inputAdded = 0
@input = IO.pipe
$DEFAULT_OUTPUT = self

@im = FXIRBInputMethod.new
@irb = Thread.new {
IRB.start_in_fxirb(@im)
self.crash
}

@multiline = false

@exit_proc = lambda {exit}
end
end

As far as I can make out, inside IRB.start_in_fxirb is the only place I
have access to the IRB.conf[:MAIN_CONTEXT] object after it is
initialised to Irb.new, so that I can create the appropriate singleton
method. Also I looked at the Context and Workspace code, and don't see
why irb.context.workspace.main would create a new reader. (Thanks for
being patient, btw - the IRB code is fairly labyrinthine until one gets
used to it.)

martin
 
B

B. K. Oxley (binkley)

B. K. Oxley (binkley) said:
To use fxirb I need fox12 but am having difficulty using gem to install
it on Cygwin. What is the suggestion for getting fox ruby support for
Cygwin?

Here is how I did it.

* Download Fox 1.2.16 (latest in Fox 1.2.x series corresponding with the
1.2.x fxruby sources) and unpack.

* Configure thus:

$ ./configure --prefix=/usr/local --without-xcursor

For whatever reason, since Fox's configure script saw I had a xcursor.h
header, it hooked in Xcursor support even though Fox otherwise
recognized that I was on a Windows system (note that I did not say
--with-x). This was ok as far as it went, except that it broke the
compile as the X libraries were not in the link paths. Simply saying
--wihtout-xcursor fixed that

* Build normally, install.

$ make && make install

* Build fxruby

$ gem install fxruby

Select the 1.2.5 (ruby) version, the lastest that builds from source.


All done!


Cheers,
--binkley
 
C

Csaba Henk

I'm a bit confused about lifecycle issues now. What I have at the moment
is this:

module IRB

def IRB.start_in_fxirb(im)
[snip]

irb = Irb.new(nil, im)
[snip]

class << irb.context.workspace.main
def gets
[snip]

end
end
end

end

and inside the FXIrb class:

[snip]

Well, this code look fine to me, but of course, just looking at the code
is not enough.
As far as I can make out, inside IRB.start_in_fxirb is the only place I
have access to the IRB.conf[:MAIN_CONTEXT] object after it is
initialised to Irb.new, so that I can create the appropriate singleton
method.

It might be that IRB.start_in_fxirb is the appropriate place to define
the singleton (I'd say so). But what do you mean by "the only place I
have access to ..."? IRB.conf[:MAIN_CONTEXT] is a global accessor, it
should work everywhere (unless you have somewhere another IRB constant,
which I'm sure is not the case, but even then you could access the
object as such via TOPLEVEL_BINDING).
Also I looked at the Context and Workspace code, and don't see
why irb.context.workspace.main would create a new reader. (Thanks for
being patient, btw - the IRB code is fairly labyrinthine until one gets
used to it.)

Um, what irb is the irb in "irb.context.workspace.main"?

It seems that we were speaking about entirely different things here.

When I said, "irb.context.workspace.main" creates a new reader, that
happened after checking its effect pasted into an irb prompt. There the
respective ...main evaluator object's irb method has been called, and
that just creates a new reader.

Where you use "irb.context.workspace.main", that is after doing
"irb = Irb.new(nil, im)", so the object which the
"context.workspace.main" method chain has been passed to, is referred to
a local, of course that behaves differently from the above. You could as
well say "irb = 5" and complain that "irb.context.workspace.main" blows
up with a NoMethodError...

However, I made a mistake here as well, as "irb" is really ambigouous...
eg., within an IRB::Context object it gives you the main object again
(although there you could probably do just "workspace.main").

So, both of us should be more careful about being unambiguous when
referring to objects and methods somewhere living in irb's realm.

* * *

What problems do you have with the code posted? What are "lifecycle
problems" you refer to?

Csaba
 
M

Martin DeMello

Csaba Henk said:
As far as I can make out, inside IRB.start_in_fxirb is the only place I
have access to the IRB.conf[:MAIN_CONTEXT] object after it is
initialised to Irb.new, so that I can create the appropriate singleton
method.

It might be that IRB.start_in_fxirb is the appropriate place to define
the singleton (I'd say so). But what do you mean by "the only place I
have access to ..."? IRB.conf[:MAIN_CONTEXT] is a global accessor, it
should work everywhere (unless you have somewhere another IRB constant,
which I'm sure is not the case, but even then you could access the
object as such via TOPLEVEL_BINDING).

I was referring to the fact that I created the Irb.new instance within
start_in_fxirb, and called that within a thread, so I didn't really have
any other logical place to add a singleton method to the object. Ignore
the rest - it looks like we were talking at cross purposes :) I was jsut
a bit worried by your comment about creating a new reader 'cause I
couldn't see where that was happening.

martin
 
C

Csaba Henk

It might be that IRB.start_in_fxirb is the appropriate place to define
the singleton (I'd say so). But what do you mean by "the only place I
have access to ..."? IRB.conf[:MAIN_CONTEXT] is a global accessor, it
should work everywhere (unless you have somewhere another IRB constant,
which I'm sure is not the case, but even then you could access the
object as such via TOPLEVEL_BINDING).

I was referring to the fact that I created the Irb.new instance within
start_in_fxirb, and called that within a thread, so I didn't really have
any other logical place to add a singleton method to the object. Ignore
the rest - it looks like we were talking at cross purposes :) I was jsut
a bit worried by your comment about creating a new reader 'cause I
couldn't see where that was happening.

OK, I see.

Csaba
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,007
Latest member
obedient dusk

Latest Threads

Top