Real-world Rawline usage

Published on

By Fabio Cevasco

So I finally decided to update RawLine last week, and I added a more Readline-like API. When I first started the project, I was determined not to do that, because the current Readline wrapper shipped with Ruby is not very Ruby-ish: it’s a wrapper, after all!

The good thing of having a new API compatible with Readline is that now people can use RawLine in their Readline-powered scripts, with very minor modifications.

Let’s have a look at some examples (they are also shipped with Rawline v0.3.1):
h3. Rush

Rush is an excellent gem which provides a cross-platform shell environment, entirely written in Ruby.
Being a shell, it obviously uses Readline for tab completion, and that does the job on Linux. On Windows though, things aren’t that easy:

  • text gets garbled if you write long lines
  • you can’t type certain characters if they use some key modifiers like , etc.

RawLine doesn’t have these problems (that’s the very reason why I created it), so here’s a simple script which launches a Rawline-enabled Rush shell:

 1require 'rubygems'
 2require 'rush'
 3require 'rawline'
 4
 5class RawlineRush < Rush::Shell
 6
 7  def initialize
 8    Rawline.basic_word_break_characters = "" 
 9    Rawline.completion_proc = completion_proc
10    super
11  end
12
13  def run
14    loop do
15      cmd = Rawline.readline('rawline_rush> ')
16      finish if cmd.nil? or cmd == 'exit'
17      next if cmd == ""
18      Rawline::HISTORY.push(cmd)
19      execute(cmd)
20    end
21  end
22end
23
24shell = RawlineRush.new.run

What happens here? Nothing much really, all I had to do was:

  1. Derive a new class from Rush::Shell
  2. Set Rawline.basic_word_break_characters to the same value used in the original Rush code
  3. Set Rawline.completion_proc to the same completion Proc used in the original Rush code
  4. Rewrite the original run replacing Readline with Rawline

And it works as it was intended to, i.e. typing root['b<TAB> will expand to root['bin/, etc.
Note that I didn’t write the completion Proc from scratch: it was already there.

IRB

After trying out Rush, the next logical step was trying IRB itself: I could never use it properly on Windows, and that was really frustrating.
After a few minutes trying to figure out how to start IRB programmatically, I quickly came up with a similar example:

 1require 'irb'
 2require 'irb/completion'
 3require 'rubygems'
 4require 'rawline'
 5
 6Rawline.basic_word_break_characters= " \t\n\"\\'`><;|&{(" 
 7Rawline.completion_append_character = nil
 8Rawline.completion_proc = IRB::InputCompletor::CompletionProc
 9
10class RawlineInputMethod < IRB::ReadlineInputMethod
11  include Rawline
12  def gets
13    if l = readline(@prompt, false)
14      HISTORY.push(l) if !l.empty?
15      @line[@line_no += 1] = l + "\n"
16    else
17      @eof = true
18      l
19    end
20  end
21end
22
23module IRB
24  @CONF[:SCRIPT] = RawlineInputMethod.new
25end
26IRB.start

In this case, Rawline is included in the RawlineInputMethod class, derived from the original ReadlineInputMethod class, i.e. the class IRB uses to define (guess…) how to input characters.
Again, all I had to do was set a few Rawline variables to match the ones used in Readline, and then redefine the function used to get characters. All done.

It works as expected (only with inline completion, of course): typing "test".ma<TAB> will give you "test".map, "test".match, etc.

You also get all Rawline key mappings for free (CTRL-K to clear the line, CTRL-U and CTRL-R to undo and redo, etc.), and you can define your own.

Legacy Comments

These comments were imported automatically from an old version of this web site. Scroll down for the newest stuff.

Nice work! Loving the irb script. For anyone unsure of how to add keybindings to the above irb script, try this:

editor = Rawline.editor
#move to beginning of line
editor.bind(:ctrl_a) { editor.move_left while (!editor.line.bol?) }

  1. move to end of line
    editor.bind(:ctrl_e) { editor.move_right while (!editor.line.eol?) }

uggh, that last bit should read:

editor = Rawline.editor

editor.bind(:ctrl_a) { editor.move_left while (!editor.line.bol?) }
#move to beginning of line

editor.bind(:ctrl_e) { editor.move_right while (!editor.line.eol?) }
#move to end of line

Yep, that’s it! Thanks Gabriel for pointing it out!

I’m glad you’re enjoying using RawLine.