RawLine 0.3.0 released — now with Readline emulation

RawLine 0.3.0 has been released. This new milestones fixes some minor bugs and adds some new functionalities, must notably:

  • Ruby 1.9 support
  • A filename completion function
  • A new API very similar to the one exposed by the Ruby wrapper for GNU Readline

Some of you asked for Readline compatibility/emulation and that was actually not too difficult to implement: all the bricks were already there, I just had to put them together in the right place.

The RawLine module (you can spell it “Rawline” as well, if you wish) now behaves like Readline. This means that you can now use RawLine like this (taken from examples/readline_emulation.rb):

include Rawline

puts "*** Readline Emulation Test Shell ***"
puts " * Press CTRL+X to exit"
puts " * Press <TAB> for file completion"

Rawline.editor.bind(:ctrl_x) { puts; puts "Exiting..."; exit }

Dir.chdir '..'

loop do
	puts "You typed: [#{readline("=> ", true).chomp!}]"
end

Basically you get a readline method, a HISTORY constant like the one exposed by Readline (Rawline’s is a RawLine::HistoryBuffer object though — much more manageable), and a FILENAME_COMPLETION_PROC constant, which provides basic filename completion. Here it is:

def filename_completion_proc
			lambda do |word|
				dirs = @line.text.split('/')
					path = @line.text.match(/^\/|[a-zA-Z]:\//) ? "/" : Dir.pwd+"/"
				if dirs.length == 0 then # starting directory
					dir = path
				else
					dirs.delete(dirs.last) unless File.directory?(path+dirs.join('/'))
					dir = path+dirs.join('/')
				end
				Dir.entries(dir).select { |e| (e =~ /^\./ && @match_hidden_files && word == '') || (e =~ /^#{word}/ && e !~ /^\./) }
			end
		end

You can find this function as part of the RawLine::Editor class. The result is not exactly the same Readline, because completion matches are not displayed underneath the line but inline and can be cycled through — which is one of Readline’s completion modes anyway.

A few methods of the RawLine::Editor class can now be accessed directly from the RawLine module, like with Readline:

  • Rawline.completion_proc — the Proc object used for TAB completion (defaults to FILENAME_COMPLETION_PROC).
  • Rawline.completion_matches — an array of completion matches.
  • Rawline.completion_append_char — a character to append after a successful completion.
  • Rawline.basic_word_break_characters — a String listing all the characters used as word separators.
  • Rawline.completer_word_break_characters — same as above.
  • Rawline.library_version — the current version of the Rawline library.
  • Rawline.clear_history — to clear the current history.
  • Rawline.match_hidden_files — whether FILENAME_COMPLETION_PROC matches hidden files and folders or not.

I bet you didn’t know these methods were even in the Readline wrapper, did you? Probably because of lack of documentation.
Anyhow, another very important difference beween Rawline and Readline is Rawline.editor, i.e. the default instance of RawLine::Editor used by the Rawline module itself.

This makes things easier if you want more control over the line which is being edited and the previously-edited lines. Sure, Readline#completion_proc exposes the current word being typed before hitting tab, and so does Rawline#completion_proc the difference is that if you access Rawline.editor.line you get a RawLine::Line object with all the information you could possibly need about the current line: the position of the cursor, the text, the order the characters were entered, etc. etc.
Now you can imagine why it took me a few minutes to write the filename_completion_proc method (and why it will take you even less time to write your own similar method if you wanna do something different): you can access not only the last word being typed but also the current and previous lines (through Rawline.editor.history or just Rawline::HISTORY)!

It must be said, as usual, that Rawline is not a complete replacement for the Readline library yet (and it will probably never be, as Readline is huge!), but it’s a good cross-platform, more Ruby-esque alternative to what’s currently available by the Readline wrapper for Ruby.

It’s not as fast, of course, especially when completing long words, but it’s quite usable. The following libraries are not required but recommended:

  • win32console (on Windows)
  • termios (on *nix)

They basically make Rawline faster. If you don’t use them, Rawline will fall back on its pure-Ruby implementation to move left and right (i.e. printing backspaces and spaces character codes instead of ASCII escape codes).

Unfortunately, there’s no vi_editing_mode or emacs_editing_mode yet (for time constraints: they can be implemented!) but patches are very welcome. Also, if you need more features, all you have to do is ask :-)

P.S.: Check out the new Project Page and especially its Resources section!