all repos — h3rald @ 75134b0d01189ee2c8097c9605c3d46b27133559

The sources of https://h3rald.com

content/articles/rawline-030.textile

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
----- 
permalink: rawline-030
title: "RawLine 0.3.0 released \xC3\xA2\xE2\x82\xAC\xE2\x80\x9D now with Readline emulation"
tags: 
- ruby opensource rawline
type: article
filter_pre: textile
-----
"RawLine":/rawline 0.3.0 has been "released":http://rubyforge.org/projects/rawline. 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):

<typo:code lang="ruby">
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
</typo:code>

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

<typo:code lang="ruby">
	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
</typo:code>

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 &mdash; 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@ &mdash; the Proc object used for TAB completion (defaults to FILENAME_COMPLETION_PROC).
* @Rawline.completion_matches@ &mdash; an array of completion matches.
* @Rawline.completion_append_char@ &mdash; a character to append after a successful completion.
* @Rawline.basic_word_break_characters@ &mdash; a String listing all the characters used as word separators.
* @Rawline.completer_word_break_characters@ &mdash; same as above. 
* @Rawline.library_version@ &mdash; the current version of the Rawline library.
* @Rawline.clear_history@ &mdash; to clear the current history.
* @Rawline.match_hidden_files@ &mdash; 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":/rawline and especially its Resources section!