contents/articles/real-world-rawline-usage.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 |
----- title: Real-world Rawline usage content-type: article timestamp: 1236398040 tags: ruby|rawline ----- <p>So I finally decided to update <a href="/rawline">RawLine</a> last week, and I added a more Readline-like <span class="caps">API</span>. When I first started the project, I was determined <em>not</em> to do that, because the current Readline wrapper shipped with Ruby is not very Ruby-ish: it’s a wrapper, after all!</p> <p>The good thing of having a new <span class="caps">API</span> compatible with Readline is that now people can use RawLine in their Readline-powered scripts, with very minor modifications.</p> <p>Let’s have a look at some examples (they are also shipped with <a href="http://rubyforge.org/projects/rawline">Rawline v0.3.1</a>):<br /> h3. Rush</p> <p><a href="http://rush.heroku.com">Rush</a> is an excellent gem which provides a cross-platform shell environment, entirely written in Ruby.<br /> 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:</p> <ul> <li>text gets garbled if you write long lines</li> <li>you can’t type certain characters if they use some key modifiers like <RIGHT-ALT>, etc.</li> </ul> <p>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:</p> <div class='ruby'><pre><code>require 'rubygems' require 'rush' require 'rawline' class RawlineRush < Rush::Shell def initialize Rawline.basic_word_break_characters = "" Rawline.completion_proc = completion_proc super end def run loop do cmd = Rawline.readline('rawline_rush> ') finish if cmd.nil? or cmd == 'exit' next if cmd == "" Rawline::HISTORY.push(cmd) execute(cmd) end end end shell = RawlineRush.new.run</code></pre></div><p>What happens here? Nothing much really, all I had to do was:</p> <ol> <li>Derive a new class from Rush::Shell</li> <li>Set <code>Rawline.basic_word_break_characters</code> to the same value used in the original Rush code</li> <li>Set <code>Rawline.completion_proc</code> to <em>the same</em> completion Proc used in the original Rush code</li> <li>Rewrite the original <code>run</code> replacing <code>Readline</code> with <code>Rawline</code></li> </ol> <p>And it works as it was intended to, i.e. typing <code>root['b<TAB></code> will expand to <code>root['bin/</code>, etc.<br /> Note that I didn’t write the completion Proc from scratch: it was already there.</p> <h3><span class="caps">IRB</span></h3> <p>After trying out Rush, the next logical step was trying <span class="caps">IRB</span> itself: I could never use it properly on Windows, and that was really frustrating.<br /> After a few minutes trying to figure out how to start <span class="caps">IRB</span> programmatically, I quickly came up with a similar example:</p> <div class='ruby'><pre><code>require 'irb' require 'irb/completion' require 'rubygems' require 'rawline' Rawline.basic_word_break_characters= " \t\n\"\\'`><;|&{(" Rawline.completion_append_character = nil Rawline.completion_proc = IRB::InputCompletor::CompletionProc class RawlineInputMethod < IRB::ReadlineInputMethod include Rawline def gets if l = readline(@prompt, false) HISTORY.push(l) if !l.empty? @line[@line_no += 1] = l + "\n" else @eof = true l end end end module IRB @CONF[:SCRIPT] = RawlineInputMethod.new end IRB.start</code></pre></div><p>In this case, Rawline is included in the <code>RawlineInputMethod</code> class, derived from the original <code>ReadlineInputMethod</code> class, i.e. the class <span class="caps">IRB</span> uses to define (guess…) how to input characters.<br /> 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.</p> <p>It works as expected (only with inline completion, of course): typing <code>"test".ma<TAB></code> will give you <code>"test".map</code>, <code>"test".match</code>, etc.</p> <p>You also get all Rawline key mappings for free (<span class="caps">CTRL</span>-K to clear the line, <span class="caps">CTRL</span>-U and <span class="caps">CTRL</span>-R to undo and redo, etc.), and you can define your own.</p> |