all repos — h3rald @ 3823f20ada8de57b8a16651ddb10048224bbe828

The sources of https://h3rald.com

contents/articles/rawline-030.html

 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
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
-----
title: "RawLine 0.3.0 released — now with Readline emulation"
content-type: article
timestamp: 1235890020
tags: "ruby|opensource|rawline"
-----
<p><a href="/rawline">RawLine</a> 0.3.0 has been <a href="http://rubyforge.org/projects/rawline">released</a>. This new
	milestones fixes some minor bugs and adds some new functionalities, must notably:</p>
<ul>
	<li>Ruby 1.9 support</li>
	<li>A filename completion function</li>
	<li>A new <span class="caps">API</span> very similar to the one exposed by the Ruby wrapper for <span
			class="caps">GNU</span> Readline</li>
</ul>
<p>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.</p>
<p>The <code>RawLine</code> module (you can spell it &#8220;Rawline&#8221; as well, if you wish) now behaves like
	<code>Readline</code>. This means that you can now use RawLine like this (taken from
	examples/readline_emulation.rb):</p>
<div class='ruby'>
	<pre><code>include Rawline

puts "*** Readline Emulation Test Shell ***"
puts " * Press CTRL+X to exit"
puts " * Press &lt;TAB&gt; for file completion"

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

Dir.chdir '..'

loop do
	puts "You typed: [#{readline("=&gt; ", true).chomp!}]"
end</code></pre>
</div>
<p>Basically you get a <code>readline</code> method, a <code>HISTORY</code> constant like the one exposed by Readline
	(Rawline's is a RawLine::HistoryBuffer object though &mdash; much more manageable), and a
	<code>FILENAME_COMPLETION_PROC</code> constant, which provides basic filename completion. Here it is:</p>
<div class='ruby'>
	<pre><code>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</code></pre>
</div>
<p>You can find this function as part of the <code>RawLine::Editor</code> 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.</p>
<p>A few methods of the <code>RawLine::Editor</code> class can now be accessed directly from the <code>RawLine</code>
	module, like with Readline:</p>
<ul>
	<li><code>Rawline.completion_proc</code> &mdash; the Proc object used for <span class="caps">TAB</span> completion
		(defaults to FILENAME_COMPLETION_PROC).</li>
	<li><code>Rawline.completion_matches</code> &mdash; an array of completion matches.</li>
	<li><code>Rawline.completion_append_char</code> &mdash; a character to append after a successful completion.</li>
	<li><code>Rawline.basic_word_break_characters</code> &mdash; a String listing all the characters used as word
		separators.</li>
	<li><code>Rawline.completer_word_break_characters</code> &mdash; same as above.</li>
	<li><code>Rawline.library_version</code> &mdash; the current version of the Rawline library.</li>
	<li><code>Rawline.clear_history</code> &mdash; to clear the current history.</li>
	<li><code>Rawline.match_hidden_files</code> &mdash; whether FILENAME_COMPLETION_PROC matches hidden files and
		folders or not.</li>
</ul>
<p>I bet you didn't know these methods were even in the Readline wrapper, did you? Probably because of lack of
	documentation.<br />
	Anyhow, another very important difference beween Rawline and Readline is <code>Rawline.editor</code>, i.e. the
	default instance of RawLine::Editor used by the Rawline module itself.</p>
<p>This makes things easier if you want more control over the line which is being edited and the previously-edited
	lines. Sure, <code>Readline#completion_proc</code> exposes the current <em>word</em> being typed before hitting tab,
	and so does <code>Rawline#completion_proc</code> the difference is that if you access
	<code>Rawline.editor.line</code> you get a <code>RawLine::Line</code> 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. <br />
	Now you can imagine why it took me a few minutes to write the <code>filename_completion_proc</code> 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 <em>and previous</em> lines (through
	<code>Rawline.editor.history</code> or just <code>Rawline::HISTORY</code>)!</p>
<p>It must be said, as usual, that Rawline is <em>not</em> 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.</p>
<p>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:</p>
<ul>
	<li><code>win32console</code> (on Windows)</li>
	<li><code>termios</code> (on *nix)</li>
</ul>
<p>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 <span class="caps">ASCII</span>
	escape codes).</p>
<p>Unfortunately, there's no <code>vi_editing_mode</code> or <code>emacs_editing_mode</code> yet (for time constraints:
	they <em>can</em> be implemented!) but patches are very welcome. Also, if you need more features, all you have to do
	is ask :-)</p>
<p>P.S.: Check out the new <a href="/rawline">Project Page</a> and especially its Resources section!</p>