<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>H3RALD - Tag 'rawline' (RSS Feed)</title>
    <language>en-us</language>
    <lastBuildDate>Fri, 06 Mar 2009 20:54:00 -0700</lastBuildDate>
    <ttl>40</ttl>
    <link>http://www.h3rald.com</link>
    <description/>
    <item>
      <title>Real-world Rawline usage</title>
      <description>&lt;p&gt;So I finally decided to update &lt;a href="/rawline"&gt;RawLine&lt;/a&gt; last week, and I added a more Readline-like &lt;span class="caps"&gt;API&lt;/span&gt;. When I first started the project, I was determined &lt;em&gt;not&lt;/em&gt; to do that, because the current Readline wrapper shipped with Ruby is not very Ruby-ish: it&amp;#8217;s a wrapper, after all!&lt;/p&gt;
&lt;p&gt;The good thing of having a new &lt;span class="caps"&gt;API&lt;/span&gt; compatible with Readline is that now people can use RawLine in their Readline-powered scripts, with very minor modifications.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s have a look at some examples (they are also shipped with &lt;a href="http://rubyforge.org/projects/rawline"&gt;Rawline v0.3.1&lt;/a&gt;):&lt;br /&gt;
h3. Rush&lt;/p&gt;
&lt;p&gt;&lt;a href="http://rush.heroku.com"&gt;Rush&lt;/a&gt; is an excellent gem which provides a cross-platform shell environment, entirely written in Ruby.&lt;br /&gt;
Being a shell, it obviously uses Readline for tab completion, and that does the job on Linux. On Windows though, things aren&amp;#8217;t that easy:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;text gets garbled if you write long lines&lt;/li&gt;
	&lt;li&gt;you can&amp;#8217;t type certain characters if they use some key modifiers like &lt;RIGHT-ALT&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;RawLine doesn&amp;#8217;t have these problems (that&amp;#8217;s the very reason why I created it), so here&amp;#8217;s a simple script which launches a Rawline-enabled Rush shell:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt; &lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;require &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rubygems&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n2" name="n2"&gt;2&lt;/a&gt;&lt;/span&gt;require &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rush&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n3" name="n3"&gt;3&lt;/a&gt;&lt;/span&gt;require &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rawline&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n4" name="n4"&gt;4&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n5" name="n5"&gt;5&lt;/a&gt;&lt;/span&gt;&lt;span class="keyword"&gt;class&lt;/span&gt; &lt;span class="class"&gt;RawlineRush&lt;/span&gt; &amp;lt; &lt;span class="constant"&gt;Rush&lt;/span&gt;::&lt;span class="constant"&gt;Shell&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n6" name="n6"&gt;6&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n7" name="n7"&gt;7&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function"&gt;initialize&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n8" name="n8"&gt;8&lt;/a&gt;&lt;/span&gt;    &lt;span class="constant"&gt;Rawline&lt;/span&gt;.basic_word_break_characters = &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; 
&lt;span class="line-numbers"&gt; &lt;a href="#n9" name="n9"&gt;9&lt;/a&gt;&lt;/span&gt;    &lt;span class="constant"&gt;Rawline&lt;/span&gt;.completion_proc = completion_proc
&lt;span class="line-numbers"&gt;&lt;strong&gt;&lt;a href="#n10" name="n10"&gt;10&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;    &lt;span class="keyword"&gt;super&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n11" name="n11"&gt;11&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n12" name="n12"&gt;12&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n13" name="n13"&gt;13&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function"&gt;run&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n14" name="n14"&gt;14&lt;/a&gt;&lt;/span&gt;    loop &lt;span class="keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n15" name="n15"&gt;15&lt;/a&gt;&lt;/span&gt;      cmd = &lt;span class="constant"&gt;Rawline&lt;/span&gt;.readline(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rawline_rush&amp;gt; &lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;&lt;a href="#n16" name="n16"&gt;16&lt;/a&gt;&lt;/span&gt;      finish &lt;span class="keyword"&gt;if&lt;/span&gt; cmd.nil? &lt;span class="keyword"&gt;or&lt;/span&gt; cmd == &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;exit&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n17" name="n17"&gt;17&lt;/a&gt;&lt;/span&gt;      &lt;span class="keyword"&gt;next&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; cmd == &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n18" name="n18"&gt;18&lt;/a&gt;&lt;/span&gt;      &lt;span class="constant"&gt;Rawline&lt;/span&gt;::&lt;span class="constant"&gt;HISTORY&lt;/span&gt;.push(cmd)
&lt;span class="line-numbers"&gt;&lt;a href="#n19" name="n19"&gt;19&lt;/a&gt;&lt;/span&gt;      execute(cmd)
&lt;span class="line-numbers"&gt;&lt;strong&gt;&lt;a href="#n20" name="n20"&gt;20&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n21" name="n21"&gt;21&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n22" name="n22"&gt;22&lt;/a&gt;&lt;/span&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n23" name="n23"&gt;23&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n24" name="n24"&gt;24&lt;/a&gt;&lt;/span&gt;shell = &lt;span class="constant"&gt;RawlineRush&lt;/span&gt;.new.run
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;What happens here? Nothing much really, all I had to do was:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Derive a new class from Rush::Shell&lt;/li&gt;
	&lt;li&gt;Set &lt;code&gt;Rawline.basic_word_break_characters&lt;/code&gt; to the same value used in the original Rush code&lt;/li&gt;
	&lt;li&gt;Set &lt;code&gt;Rawline.completion_proc&lt;/code&gt; to &lt;em&gt;the same&lt;/em&gt; completion Proc used in the original Rush code&lt;/li&gt;
	&lt;li&gt;Rewrite the original &lt;code&gt;run&lt;/code&gt; replacing &lt;code&gt;Readline&lt;/code&gt; with &lt;code&gt;Rawline&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And it works as it was intended to, i.e. typing &lt;code&gt;root['b&amp;lt;TAB&amp;gt;&lt;/code&gt; will expand to &lt;code&gt;root['bin/&lt;/code&gt;, etc.&lt;br /&gt;
Note that I didn&amp;#8217;t write the completion Proc from scratch: it was already there.&lt;/p&gt;
&lt;h3&gt;&lt;span class="caps"&gt;IRB&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;After trying out Rush, the next logical step was trying &lt;span class="caps"&gt;IRB&lt;/span&gt; itself: I could never use it properly on Windows, and that was really frustrating.&lt;br /&gt;
After a few minutes trying to figure out how to start &lt;span class="caps"&gt;IRB&lt;/span&gt; programmatically, I quickly came up with a similar example:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt; &lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;require &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;irb&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n2" name="n2"&gt;2&lt;/a&gt;&lt;/span&gt;require &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;irb/completion&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n3" name="n3"&gt;3&lt;/a&gt;&lt;/span&gt;require &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rubygems&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n4" name="n4"&gt;4&lt;/a&gt;&lt;/span&gt;require &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rawline&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n5" name="n5"&gt;5&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n6" name="n6"&gt;6&lt;/a&gt;&lt;/span&gt;&lt;span class="constant"&gt;Rawline&lt;/span&gt;.basic_word_break_characters= &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt; &lt;/span&gt;&lt;span class="char"&gt;\t&lt;/span&gt;&lt;span class="char"&gt;\n&lt;/span&gt;&lt;span class="char"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="char"&gt;\\&lt;/span&gt;&lt;span class="content"&gt;'`&amp;gt;&amp;lt;;|&amp;amp;{(&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; 
&lt;span class="line-numbers"&gt; &lt;a href="#n7" name="n7"&gt;7&lt;/a&gt;&lt;/span&gt;&lt;span class="constant"&gt;Rawline&lt;/span&gt;.completion_append_character = &lt;span class="predefined-constant"&gt;nil&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n8" name="n8"&gt;8&lt;/a&gt;&lt;/span&gt;&lt;span class="constant"&gt;Rawline&lt;/span&gt;.completion_proc = &lt;span class="constant"&gt;IRB&lt;/span&gt;::&lt;span class="constant"&gt;InputCompletor&lt;/span&gt;::&lt;span class="constant"&gt;CompletionProc&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n9" name="n9"&gt;9&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;strong&gt;&lt;a href="#n10" name="n10"&gt;10&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;&lt;span class="keyword"&gt;class&lt;/span&gt; &lt;span class="class"&gt;RawlineInputMethod&lt;/span&gt; &amp;lt; &lt;span class="constant"&gt;IRB&lt;/span&gt;::&lt;span class="constant"&gt;ReadlineInputMethod&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n11" name="n11"&gt;11&lt;/a&gt;&lt;/span&gt;  include &lt;span class="constant"&gt;Rawline&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n12" name="n12"&gt;12&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function"&gt;gets&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n13" name="n13"&gt;13&lt;/a&gt;&lt;/span&gt;    &lt;span class="keyword"&gt;if&lt;/span&gt; l = readline(&lt;span class="instance-variable"&gt;@prompt&lt;/span&gt;, &lt;span class="predefined-constant"&gt;false&lt;/span&gt;)
&lt;span class="line-numbers"&gt;&lt;a href="#n14" name="n14"&gt;14&lt;/a&gt;&lt;/span&gt;      &lt;span class="constant"&gt;HISTORY&lt;/span&gt;.push(l) &lt;span class="keyword"&gt;if&lt;/span&gt; !l.empty?
&lt;span class="line-numbers"&gt;&lt;a href="#n15" name="n15"&gt;15&lt;/a&gt;&lt;/span&gt;      &lt;span class="instance-variable"&gt;@line&lt;/span&gt;[&lt;span class="instance-variable"&gt;@line_no&lt;/span&gt; += &lt;span class="integer"&gt;1&lt;/span&gt;] = l + &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="char"&gt;\n&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n16" name="n16"&gt;16&lt;/a&gt;&lt;/span&gt;    &lt;span class="keyword"&gt;else&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n17" name="n17"&gt;17&lt;/a&gt;&lt;/span&gt;      &lt;span class="instance-variable"&gt;@eof&lt;/span&gt; = &lt;span class="predefined-constant"&gt;true&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n18" name="n18"&gt;18&lt;/a&gt;&lt;/span&gt;      l
&lt;span class="line-numbers"&gt;&lt;a href="#n19" name="n19"&gt;19&lt;/a&gt;&lt;/span&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;strong&gt;&lt;a href="#n20" name="n20"&gt;20&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n21" name="n21"&gt;21&lt;/a&gt;&lt;/span&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n22" name="n22"&gt;22&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n23" name="n23"&gt;23&lt;/a&gt;&lt;/span&gt;&lt;span class="keyword"&gt;module&lt;/span&gt; &lt;span class="class"&gt;IRB&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n24" name="n24"&gt;24&lt;/a&gt;&lt;/span&gt;  &lt;span class="instance-variable"&gt;@CONF&lt;/span&gt;[&lt;span class="symbol"&gt;:SCRIPT&lt;/span&gt;] = &lt;span class="constant"&gt;RawlineInputMethod&lt;/span&gt;.new
&lt;span class="line-numbers"&gt;&lt;a href="#n25" name="n25"&gt;25&lt;/a&gt;&lt;/span&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n26" name="n26"&gt;26&lt;/a&gt;&lt;/span&gt;&lt;span class="constant"&gt;IRB&lt;/span&gt;.start
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;In this case, Rawline is included in the &lt;code&gt;RawlineInputMethod&lt;/code&gt; class, derived from the original &lt;code&gt;ReadlineInputMethod&lt;/code&gt; class, i.e. the class &lt;span class="caps"&gt;IRB&lt;/span&gt; uses to define (guess&amp;#8230;) how to input characters.&lt;br /&gt;
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.&lt;/p&gt;
&lt;p&gt;It works as expected (only with inline completion, of course): typing &lt;code&gt;"test".ma&amp;lt;TAB&amp;gt;&lt;/code&gt; will give you &lt;code&gt;"test".map&lt;/code&gt;, &lt;code&gt;"test".match&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;You also get all Rawline key mappings for free (&lt;span class="caps"&gt;CTRL&lt;/span&gt;-K to clear the line, &lt;span class="caps"&gt;CTRL&lt;/span&gt;-U and &lt;span class="caps"&gt;CTRL&lt;/span&gt;-R to undo and redo, etc.), and you can define your own.&lt;/p&gt;</description>
      <pubDate>Fri, 06 Mar 2009 20:54:00 -0700</pubDate>
      <guid>http://www.h3rald.com/articles/real-world-rawline-usage/</guid>
      <link>http://www.h3rald.com/articles/real-world-rawline-usage/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/real-world-rawline-usage/#comments</comments>
      <category>ruby</category>
      <category>rawline</category>
    </item>
    <item>
      <title>RawLine 0.3.0 released &#8212; now with Readline emulation</title>
      <description>&lt;p&gt;&lt;a href="/rawline"&gt;RawLine&lt;/a&gt; 0.3.0 has been &lt;a href="http://rubyforge.org/projects/rawline"&gt;released&lt;/a&gt;. This new milestones fixes some minor bugs and adds some new functionalities, must notably:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Ruby 1.9 support&lt;/li&gt;
	&lt;li&gt;A filename completion function&lt;/li&gt;
	&lt;li&gt;A new &lt;span class="caps"&gt;API&lt;/span&gt; very similar to the one exposed by the Ruby wrapper for &lt;span class="caps"&gt;GNU&lt;/span&gt; Readline&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;RawLine&lt;/code&gt; module (you can spell it &amp;#8220;Rawline&amp;#8221; as well, if you wish) now behaves like &lt;code&gt;Readline&lt;/code&gt;. This means that you can now use RawLine like this (taken from examples/readline_emulation.rb):&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt; &lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;include &lt;span class="constant"&gt;Rawline&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n2" name="n2"&gt;2&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n3" name="n3"&gt;3&lt;/a&gt;&lt;/span&gt;puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;*** Readline Emulation Test Shell ***&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n4" name="n4"&gt;4&lt;/a&gt;&lt;/span&gt;puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt; * Press CTRL+X to exit&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n5" name="n5"&gt;5&lt;/a&gt;&lt;/span&gt;puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt; * Press &amp;lt;TAB&amp;gt; for file completion&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n6" name="n6"&gt;6&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n7" name="n7"&gt;7&lt;/a&gt;&lt;/span&gt;&lt;span class="constant"&gt;Rawline&lt;/span&gt;.editor.bind(&lt;span class="symbol"&gt;:ctrl_x&lt;/span&gt;) { puts; puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;Exiting...&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;; exit }
&lt;span class="line-numbers"&gt; &lt;a href="#n8" name="n8"&gt;8&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n9" name="n9"&gt;9&lt;/a&gt;&lt;/span&gt;&lt;span class="constant"&gt;Dir&lt;/span&gt;.chdir &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;..&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;strong&gt;&lt;a href="#n10" name="n10"&gt;10&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n11" name="n11"&gt;11&lt;/a&gt;&lt;/span&gt;loop &lt;span class="keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n12" name="n12"&gt;12&lt;/a&gt;&lt;/span&gt;  puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;You typed: [&lt;/span&gt;&lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;#{&lt;/span&gt;readline(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;=&amp;gt; &lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="predefined-constant"&gt;true&lt;/span&gt;).chomp!&lt;span class="inline-delimiter"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="content"&gt;]&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n13" name="n13"&gt;13&lt;/a&gt;&lt;/span&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Basically you get a &lt;code&gt;readline&lt;/code&gt; method, a &lt;code&gt;HISTORY&lt;/code&gt; constant like the one exposed by Readline (Rawline&amp;#8217;s is a RawLine::HistoryBuffer object though &amp;mdash; much more manageable), and a &lt;code&gt;FILENAME_COMPLETION_PROC&lt;/code&gt; constant, which provides basic filename completion. Here it is:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt; &lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function"&gt;filename_completion_proc&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n2" name="n2"&gt;2&lt;/a&gt;&lt;/span&gt;      lambda &lt;span class="keyword"&gt;do&lt;/span&gt; |word|
&lt;span class="line-numbers"&gt; &lt;a href="#n3" name="n3"&gt;3&lt;/a&gt;&lt;/span&gt;        dirs = &lt;span class="instance-variable"&gt;@line&lt;/span&gt;.text.split(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;/&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt; &lt;a href="#n4" name="n4"&gt;4&lt;/a&gt;&lt;/span&gt;          path = &lt;span class="instance-variable"&gt;@line&lt;/span&gt;.text.match(&lt;span class="regexp"&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="content"&gt;^&lt;/span&gt;&lt;span class="char"&gt;\/&lt;/span&gt;&lt;span class="content"&gt;|[a-zA-Z]:&lt;/span&gt;&lt;span class="char"&gt;\/&lt;/span&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;/span&gt;) ? &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;/&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; : &lt;span class="constant"&gt;Dir&lt;/span&gt;.pwd+&lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;/&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n5" name="n5"&gt;5&lt;/a&gt;&lt;/span&gt;        &lt;span class="keyword"&gt;if&lt;/span&gt; dirs.length == &lt;span class="integer"&gt;0&lt;/span&gt; &lt;span class="keyword"&gt;then&lt;/span&gt; &lt;span class="comment"&gt;# starting directory&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n6" name="n6"&gt;6&lt;/a&gt;&lt;/span&gt;          dir = path
&lt;span class="line-numbers"&gt; &lt;a href="#n7" name="n7"&gt;7&lt;/a&gt;&lt;/span&gt;        &lt;span class="keyword"&gt;else&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n8" name="n8"&gt;8&lt;/a&gt;&lt;/span&gt;          dirs.delete(dirs.last) &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;.directory?(path+dirs.join(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;/&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;))
&lt;span class="line-numbers"&gt; &lt;a href="#n9" name="n9"&gt;9&lt;/a&gt;&lt;/span&gt;          dir = path+dirs.join(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;/&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="line-numbers"&gt;&lt;strong&gt;&lt;a href="#n10" name="n10"&gt;10&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;        &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n11" name="n11"&gt;11&lt;/a&gt;&lt;/span&gt;        &lt;span class="constant"&gt;Dir&lt;/span&gt;.entries(dir).select { |e| (e =~ &lt;span class="regexp"&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="content"&gt;^&lt;/span&gt;&lt;span class="char"&gt;\.&lt;/span&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class="instance-variable"&gt;@match_hidden_files&lt;/span&gt; &amp;amp;&amp;amp; word == &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;) || (e =~ &lt;span class="regexp"&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="content"&gt;^&lt;/span&gt;&lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;#{&lt;/span&gt;word&lt;span class="inline-delimiter"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;/span&gt; &amp;amp;&amp;amp; e !~ &lt;span class="regexp"&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="content"&gt;^&lt;/span&gt;&lt;span class="char"&gt;\.&lt;/span&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;/span&gt;) }
&lt;span class="line-numbers"&gt;&lt;a href="#n12" name="n12"&gt;12&lt;/a&gt;&lt;/span&gt;      &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n13" name="n13"&gt;13&lt;/a&gt;&lt;/span&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;You can find this function as part of the &lt;code&gt;RawLine::Editor&lt;/code&gt; 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 &amp;mdash; which is one of Readline&amp;#8217;s completion modes anyway.&lt;/p&gt;
&lt;p&gt;A few methods of the &lt;code&gt;RawLine::Editor&lt;/code&gt; class can now be accessed directly from the &lt;code&gt;RawLine&lt;/code&gt; module, like with Readline:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;Rawline.completion_proc&lt;/code&gt; &amp;mdash; the Proc object used for &lt;span class="caps"&gt;TAB&lt;/span&gt; completion (defaults to FILENAME_COMPLETION_PROC).&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.completion_matches&lt;/code&gt; &amp;mdash; an array of completion matches.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.completion_append_char&lt;/code&gt; &amp;mdash; a character to append after a successful completion.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.basic_word_break_characters&lt;/code&gt; &amp;mdash; a String listing all the characters used as word separators.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.completer_word_break_characters&lt;/code&gt; &amp;mdash; same as above.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.library_version&lt;/code&gt; &amp;mdash; the current version of the Rawline library.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.clear_history&lt;/code&gt; &amp;mdash; to clear the current history.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.match_hidden_files&lt;/code&gt; &amp;mdash; whether FILENAME_COMPLETION_PROC matches hidden files and folders or not.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I bet you didn&amp;#8217;t know these methods were even in the Readline wrapper, did you? Probably because of lack of documentation.&lt;br /&gt;
Anyhow, another very important difference beween Rawline and Readline is &lt;code&gt;Rawline.editor&lt;/code&gt;, i.e. the default instance of RawLine::Editor used by the Rawline module itself.&lt;/p&gt;
&lt;p&gt;This makes things easier if you want more control over the line which is being edited and the previously-edited lines. Sure, &lt;code&gt;Readline#completion_proc&lt;/code&gt; exposes the current &lt;em&gt;word&lt;/em&gt; being typed before hitting tab, and so does &lt;code&gt;Rawline#completion_proc&lt;/code&gt; the difference is that if you access &lt;code&gt;Rawline.editor.line&lt;/code&gt; you get a &lt;code&gt;RawLine::Line&lt;/code&gt; 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. &lt;br /&gt;
Now you can imagine why it took me a few minutes to write the &lt;code&gt;filename_completion_proc&lt;/code&gt; 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 &lt;em&gt;and previous&lt;/em&gt; lines (through &lt;code&gt;Rawline.editor.history&lt;/code&gt; or just &lt;code&gt;Rawline::HISTORY&lt;/code&gt;)!&lt;/p&gt;
&lt;p&gt;It must be said, as usual, that Rawline is &lt;em&gt;not&lt;/em&gt; a complete replacement for the Readline library yet (and it will probably never be, as Readline is huge!), but it&amp;#8217;s a good cross-platform, more Ruby-esque alternative to what&amp;#8217;s currently available by the Readline wrapper for Ruby.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not as fast, of course, especially when completing long words, but it&amp;#8217;s quite usable. The following libraries are not required but recommended:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;win32console&lt;/code&gt; (on Windows)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;termios&lt;/code&gt; (on *nix)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They basically make Rawline faster. If you don&amp;#8217;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 &lt;span class="caps"&gt;ASCII&lt;/span&gt; escape codes).&lt;/p&gt;
&lt;p&gt;Unfortunately, there&amp;#8217;s no &lt;code&gt;vi_editing_mode&lt;/code&gt; or &lt;code&gt;emacs_editing_mode&lt;/code&gt; yet (for time constraints: they &lt;em&gt;can&lt;/em&gt; be implemented!) but patches are very welcome. Also, if you need more features, all you have to do is ask :-)&lt;/p&gt;
&lt;p&gt;P.S.: Check out the new &lt;a href="/rawline"&gt;Project Page&lt;/a&gt; and especially its Resources section!&lt;/p&gt;</description>
      <pubDate>Sat, 28 Feb 2009 23:47:00 -0700</pubDate>
      <guid>http://www.h3rald.com/articles/rawline-030/</guid>
      <link>http://www.h3rald.com/articles/rawline-030/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/rawline-030/#comments</comments>
      <category>ruby</category>
      <category>opensource</category>
      <category>rawline</category>
    </item>
    <item>
      <title>New Release: RawLine 0.2.0</title>
      <description>&lt;p&gt;&lt;del&gt;InLine&lt;/del&gt; RawLine 0.2.0 is out!&lt;/p&gt;
&lt;p&gt;*Raw*Line is the new name for InLine, in case you didn&amp;#8217;t guess. The name was changed to avoid name collision problems with the RubyInline project.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s what&amp;#8217;s new:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Added /examples and /test directory to gem.&lt;/li&gt;
	&lt;li&gt;Escape codes can now be used in prompt.&lt;/li&gt;
	&lt;li&gt;It is now possible to use bind(key, &amp;amp;block) with a String as key, even if the corresponding escape sequence is not defined.&lt;/li&gt;
	&lt;li&gt;Added Editor#write_line(string) to print a any string (and &amp;#8220;hit return&amp;#8221;).&lt;/li&gt;
	&lt;li&gt;Library name changed to &amp;#8220;RawLine&amp;#8221; to avoid name collision issues (Bug &lt;a href="http://rubyforge.org/tracker/?func=detail&amp;amp;aid=18879&amp;amp;group_id=5622&amp;amp;atid=21788"&gt;18879&lt;/a&gt;).&lt;/li&gt;
	&lt;li&gt;Provided alternative implementation for left and right arrows if terminal&lt;br /&gt;
supports escape sequences (on Windows, it requires the Win32Console gem).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In particular, I decided to provide an &amp;#8220;optimized implementation&amp;#8221; for the left and right arrows using escape sequences rather than shameful hacks. This is now possible because the Win32Console gem now enables &lt;span class="caps"&gt;ANSI&lt;/span&gt; escape sequences on Windows as well (weehee!).&lt;/p&gt;
&lt;p&gt;So:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;If you&amp;#8217;re on *nix all good, your terminal is smart and can understand escape sequences =&amp;gt; the new implementation will be used.&lt;/li&gt;
	&lt;li&gt;If you&amp;#8217;re on Windows and you installed Win32Console, your termnal is smart and can understand escape sequences =&amp;gt; the new implementation will be used.&lt;/li&gt;
	&lt;li&gt;If you&amp;#8217;re on Windows and you didn&amp;#8217;t install Win32Console, then your terminal is stupid and it doesn&amp;#8217;t understand escape sequences, so the old implementation will be used.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The new implementation is significantly faster than the old one, on Windows at least, and the cursor now blinks properly when left or right arrows are pressed.&lt;/p&gt;
&lt;p&gt;I re-emplemented only cursor movement because I&amp;#8217;m still having some problems in getting the delete/insert escapes to work properly (or better: how I want them to work!).&lt;/p&gt;</description>
      <pubDate>Tue, 01 Apr 2008 21:33:00 -0600</pubDate>
      <guid>http://www.h3rald.com/articles/rawline-020/</guid>
      <link>http://www.h3rald.com/articles/rawline-020/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/rawline-020/#comments</comments>
      <category>ruby</category>
      <category>programming</category>
      <category>opensource</category>
      <category>rawline</category>
    </item>
    <item>
      <title>InLine name change: what's your opinion?</title>
      <description>&lt;p&gt;I&amp;#8217;ve been kindly asked by the lead developer of &lt;a href="http://www.zenspider.com/ZSS/Products/RubyInline/"&gt;RubyInLine&lt;/a&gt; to change the name of my &lt;a href="http://rubyforge.org/projects/inline/"&gt;InLine&lt;/a&gt; project, due to potential confusion and conflicts.&lt;/p&gt;
&lt;p&gt;This makes sense, and I&amp;#8217;m ready to change the name of my project, although I&amp;#8217;m not that good at choosing original and &lt;em&gt;smart&lt;/em&gt; names, so well, any suggestion is more than welcome!&lt;/p&gt;
&lt;p&gt;I was thinking of something like:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;RawLine&lt;/li&gt;
	&lt;li&gt;EditLine&lt;/li&gt;
	&lt;li&gt;RawInput&lt;/li&gt;
	&lt;li&gt;RubyInput&lt;/li&gt;
	&lt;li&gt;RubyLine&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I personally think that &lt;strong&gt;RawLine&lt;/strong&gt; is probably the best option, but please, if have any better idea just speak up!&lt;/p&gt;
&lt;p&gt;P.S.: &amp;#8220;RedLine&amp;#8221; is taken, unfortunately, otherwise it would have been my first choice since the beginning.&lt;/p&gt;</description>
      <pubDate>Wed, 26 Mar 2008 23:30:00 -0600</pubDate>
      <guid>http://www.h3rald.com/articles/inline-name-change/</guid>
      <link>http://www.h3rald.com/articles/inline-name-change/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/inline-name-change/#comments</comments>
      <category>ruby</category>
      <category>programming</category>
      <category>opensource</category>
      <category>rawline</category>
    </item>
    <item>
      <title>RawLine - a 100% Ruby solution for console inline editing</title>
      <description>&lt;p&gt;One of the many things I like about Ruby is its cross-platform nature: as a general rule, Ruby code runs on everything which supports Ruby, regardless of its architecture and platform (yes, there are quite a few exceptions, but let&amp;#8217;s accept this generalization for now).&lt;/p&gt;
&lt;p&gt;More specifically, I liked the fact that I could use the &lt;a href="http://tiswww.case.edu/php/chet/readline/rltop.html"&gt;&lt;span class="caps"&gt;GNU&lt;/span&gt; Readline library&lt;/a&gt; with Ruby seamlessly on both Windows and Linux.&lt;br /&gt;
Readline offers quite a lot of features which are useful for those people like me who enjoy creating command-line scripts, in a nutshell, it provides:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;File/Word completion&lt;/li&gt;
	&lt;li&gt;History support&lt;/li&gt;
	&lt;li&gt;Custom key bindings which can be modified via .inputrc&lt;/li&gt;
	&lt;li&gt;Emacs and Vi edit modes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Basically it makes your command-line interface fast and powerful, and that&amp;#8217;s not an overstatement. Ruby&amp;#8217;s own &lt;span class="caps"&gt;IRB&lt;/span&gt; can be enhanced by enabling readline and completion, and it works great &amp;#8212; at least on *nix systems.&lt;/p&gt;
&lt;p&gt;For some weird reason, some people had problems with Readline on Windows: in particular, things get nasty when you start editing long lines. Text gets garbled, the cursor goes up one or two lines and doesn&amp;#8217;t come back, and other similar leprechaun&amp;#8217;s tricks, which are not that funny after a while.&lt;/p&gt;
&lt;p&gt;Apparently there&amp;#8217;s no alternative to Readline in the Ruby world. If you wan&amp;#8217;t tab completion that&amp;#8217;s it, you&amp;#8217;re stuck. Would it be difficult to implement &lt;em&gt;some&lt;/em&gt; of Readline functionality natively in Ruby? Maybe, but the problem is that for some reason the Ruby Standard Library doesn&amp;#8217;t have low level methods to operate on keystrokes&amp;#8230;&lt;/p&gt;
&lt;p&gt;&amp;#8230;but luckily, the &lt;a href="http://highline.rubyforge.org/"&gt;HighLine&lt;/a&gt; gem does! James Edward Gray II keeps pointing out here and here that HighLine&amp;#8217;s own &lt;code&gt;get_character&lt;/code&gt; method does just that: it returns the corresponding character code(s) right when a key is pressed, unlike &lt;code&gt;IO#gets()&lt;/code&gt; which waits for the user to press &lt;span class="caps"&gt;ENTER&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Believe it or not, that tiny method can do wonders&amp;#8230;h2. Reverse-engineering escape codes&lt;/p&gt;
&lt;p&gt;So here&amp;#8217;s a little script which uses &lt;code&gt;get_character()&lt;/code&gt; in an endless loop, diligently printing the character codes corresponding to a keystroke:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt; &lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;&lt;span class="doctype"&gt;#!/usr/local/bin/ruby -w&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n2" name="n2"&gt;2&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n3" name="n3"&gt;3&lt;/a&gt;&lt;/span&gt;require &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rubygems&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n4" name="n4"&gt;4&lt;/a&gt;&lt;/span&gt;require &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;highline/system_extensions&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n5" name="n5"&gt;5&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n6" name="n6"&gt;6&lt;/a&gt;&lt;/span&gt;include &lt;span class="constant"&gt;HighLine&lt;/span&gt;::&lt;span class="constant"&gt;SystemExtensions&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n7" name="n7"&gt;7&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n8" name="n8"&gt;8&lt;/a&gt;&lt;/span&gt;puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;Press a key to view the corresponding ASCII code(s) (or CTRL-X to exit).&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n9" name="n9"&gt;9&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;strong&gt;&lt;a href="#n10" name="n10"&gt;10&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;loop &lt;span class="keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n11" name="n11"&gt;11&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n12" name="n12"&gt;12&lt;/a&gt;&lt;/span&gt;  print &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;=&amp;gt; &lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n13" name="n13"&gt;13&lt;/a&gt;&lt;/span&gt;  char = get_character
&lt;span class="line-numbers"&gt;&lt;a href="#n14" name="n14"&gt;14&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;case&lt;/span&gt; char
&lt;span class="line-numbers"&gt;&lt;a href="#n15" name="n15"&gt;15&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;when&lt;/span&gt; &lt;span class="integer"&gt;?\C-x&lt;/span&gt;: print &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;Exiting...&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;; exit;
&lt;span class="line-numbers"&gt;&lt;a href="#n16" name="n16"&gt;16&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;else&lt;/span&gt; puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;#{&lt;/span&gt;char.chr&lt;span class="inline-delimiter"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="content"&gt; [&lt;/span&gt;&lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;#{&lt;/span&gt;char&lt;span class="inline-delimiter"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="content"&gt;] (hex: &lt;/span&gt;&lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;#{&lt;/span&gt;char.to_s(&lt;span class="integer"&gt;16&lt;/span&gt;)&lt;span class="inline-delimiter"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="content"&gt;)&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;
&lt;span class="line-numbers"&gt;&lt;a href="#n17" name="n17"&gt;17&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n18" name="n18"&gt;18&lt;/a&gt;&lt;/span&gt;  
&lt;span class="line-numbers"&gt;&lt;a href="#n19" name="n19"&gt;19&lt;/a&gt;&lt;/span&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;A pretty harmless little thing. Try to run it and press some keys, and see what you get:&lt;/p&gt;
&lt;div style="font-family: Monospace"&gt;
&lt;p&gt;Press a key to view the corresponding &lt;span class="caps"&gt;ASCII&lt;/span&gt; code(s) (or &lt;span class="caps"&gt;CTRL&lt;/span&gt;-X to exit).&lt;/p&gt;
&lt;p&gt;=&amp;gt; a &lt;sup class="footnote" id="fnr96"&gt;&lt;a href="#fn96"&gt;96&lt;/a&gt;&lt;/sup&gt; (hex: 61)&lt;/p&gt;
&lt;p&gt;=&amp;gt; 1 &lt;sup class="footnote" id="fnr49"&gt;&lt;a href="#fn49"&gt;49&lt;/a&gt;&lt;/sup&gt; (hex: 31)&lt;/p&gt;
&lt;p&gt;=&amp;gt; Q &lt;sup class="footnote" id="fnr81"&gt;&lt;a href="#fn81"&gt;81&lt;/a&gt;&lt;/sup&gt; (hex: 51)&lt;/p&gt;
&lt;p&gt;=&amp;gt; &amp;alpha; &lt;sup class="footnote" id="fnr224"&gt;&lt;a href="#fn224"&gt;224&lt;/a&gt;&lt;/sup&gt; (hex: e0)&lt;/p&gt;
&lt;p&gt;=&amp;gt; K &lt;sup class="footnote" id="fnr75"&gt;&lt;a href="#fn75"&gt;75&lt;/a&gt;&lt;/sup&gt; (hex: 4b)&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Hang on, what are the last two codes? &lt;em&gt;A left arrow key on Windows&lt;/em&gt;, apparently.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Welcome to the wonderful world of input escape sequences!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To cut a long story short, both Windows and *nix system &amp;#8220;terminals&amp;#8221; translate special keystrokes into sequences of two or more codes. This applies to things like &lt;span class="caps"&gt;DEL&lt;/span&gt;, &lt;span class="caps"&gt;INSERT&lt;/span&gt;, arrows, etc. etc.&lt;br /&gt;
For some ideas, check out:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.microsoft.com/whdc/device/input/Scancode.mspx"&gt;Windows Scancodes&lt;/a&gt; (Thanks &lt;a href="http://64.223.189.234/node/92"&gt;Huff&lt;/a&gt;)&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.connectrf.com/Documents/vt220.html"&gt;VT220 Terminal Input Sequences&lt;/a&gt; (Thanks &lt;a href="http://www.grayproductions.net/"&gt;James&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#8217;s now assume that we&amp;#8217;re smart and we can write a program which can parse keystroke properly, including handling different input escape sequences according to the OS, what can it be used for?&lt;br /&gt;
Well:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;For normal characters, just print them back to the screen (&lt;code&gt;get_character&lt;/code&gt; doesn&amp;#8217;t print anything, it &amp;#8220;steals&amp;#8221; the keystroke)&lt;/li&gt;
	&lt;li&gt;For special characters, do something nice!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We could setup &lt;span class="caps"&gt;TAB&lt;/span&gt; to auto-complete the current word according to an array of matches, or bind the up arrow to load the last line typed in by the user, for example, that&amp;#8217;s basically something Readline does, right?&lt;/p&gt;
&lt;h2&gt;RawLine: how it works and what it does&lt;/h2&gt;
&lt;p&gt;I created a small project on RubyForge called &lt;a href="http://rubyforge.org/projects/rawline/"&gt;RawLine&lt;/a&gt; (not to be confused with RubyInline, a completely different thing altogether, sorry about that) to play around with the possibilities offered by the &lt;code&gt;get_character&lt;/code&gt; method. The library is just a preview of things which can be done, but it&amp;#8217;s already usable, provided that you&amp;#8217;re brave enough to try it out, that is.&lt;/p&gt;
&lt;p&gt;The basic idea behind RawLine is to be able to parse keystrokes properly on different platforms and re-bind them to a set of predefined, cross-platform actions or a user-defined code block.&lt;/p&gt;
&lt;h3&gt;Basic line-editing operations&lt;/h3&gt;
&lt;p&gt;The first challenge was to re-invent the wheel, i.e. re-bind keystrokes to their typical actions: a left arrow moves the cursor left, a backspace deletes the character at the left of the cursor and so on. Yes, because &lt;code&gt;get_characters&lt;/code&gt; gives you the right character codes at the price of &lt;em&gt;cancelling their normal effects&lt;/em&gt;, which is a great thing, as you&amp;#8217;ll soon find out.&lt;/p&gt;
&lt;p&gt;Printing a character on the screen was one of the easiest tasks (at first). &lt;code&gt;IO#putc&lt;/code&gt; does the job pretty well: it prints a character out.&lt;br /&gt;
What about moving left? Easy: print a non-descructive backspace (\b) and hope it is really not destructive. I did some tests and it seems to do as it&amp;#8217;s told and move the cursor back by one position.&lt;/p&gt;
&lt;p&gt;Moving right was a little trickier: the easiest thing I found was to re-print the character under the cursor, which will then move the cursor forward (as naive as it may seem, it does the job!). If there&amp;#8217;s nothing under the cursor, then we must be at the end of the line and it shouldn&amp;#8217;t move anywhere, so there we go.&lt;/p&gt;
&lt;p&gt;What if I move left a bit and then start typing normal characters? Well, everything is rewritten of course: this will be our &amp;#8220;character replace mode&amp;#8221;. Unfortunately users don&amp;#8217;t like this behavior that much, so what I did was this:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Copy all characters from the one at the left of the cursor till the end of the line&lt;/li&gt;
	&lt;li&gt;Print the character to be inserted&lt;/li&gt;
	&lt;li&gt;Re-print the previously-copied characters&lt;/li&gt;
	&lt;li&gt;Move the cursor back at the right place&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Again, a primitive solution which works seamlessly on all platforms, and yes, it&amp;#8217;s fast enough that you don&amp;#8217;t notice the difference.&lt;/p&gt;
&lt;p&gt;As you may have guessed, this of course means that I always had to keep track of:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;The cursor position within the line&lt;/li&gt;
	&lt;li&gt;The text currently printed to the screen&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Backspace and delete were implemented in a similar way, you can figure it out yourself or look at the source code: I won&amp;#8217;t bore you any further!&lt;/p&gt;
&lt;h3&gt;History management&lt;/h3&gt;
&lt;p&gt;The next step was to implement a history for both the characters inputted by the user (to allow undoing and redoing operations) and for the whole lines. This was just an ordinary programming exercise: a simple buffer with some extra controls here and there, nothing too scary.&lt;/p&gt;
&lt;p&gt;So every &amp;#8220;modification&amp;#8221; to the current line being typed is saved in a line history buffer and all the lines entered are saved in another history buffer. All is left is to allow users to navigate through these buffers back and forth. &lt;br /&gt;
Nothing impossible: all I had to do was keeping track of the current element of the history being retrieved and then overwrite the current line with a new line stored in the buffer? How&amp;#8217;s this line overwriting done? Same old:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Move the cursor to the beginnig of the line&lt;/li&gt;
	&lt;li&gt;Print X spaces, where X is the line length, so that the characters are no longer displayed in the console&lt;/li&gt;
	&lt;li&gt;Move the cursor back to the beginning of the line&lt;/li&gt;
	&lt;li&gt;Print the new line.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Easy and naive, as usual. But again, it works well enough.&lt;/p&gt;
&lt;h3&gt;Word completion&lt;/h3&gt;
&lt;p&gt;The other challange was word completion. The current implementation can be summarized as follows:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;If &lt;span class="caps"&gt;TAB&lt;/span&gt; (or another character, if you wish) is pressed, call a user-defined &lt;code&gt;completion_proc&lt;/code&gt; method which returns an array and show the first element of the array (in this case I actually used a cyclic RawLine::HistoryBuffer, not an array)&lt;/li&gt;
	&lt;li&gt;If the user presses &lt;span class="caps"&gt;TAB&lt;/span&gt; again, show another match, and so &lt;em&gt;ad infinitum&lt;/em&gt; if the user keeps pressing &lt;span class="caps"&gt;TAB&lt;/span&gt;.&lt;/li&gt;
	&lt;li&gt;If the user presses another key, accept the default completion and move on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Obviously this means that:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;RawLine has to keep track of the current &amp;#8220;word&amp;#8221;. A word is everything separated by a user defined &lt;code&gt;word_separator&lt;/code&gt;, which can obviously modified at runtime, with care.&lt;/li&gt;
	&lt;li&gt;Regarding the &lt;code&gt;completion_proc&lt;/code&gt;, typically you may want to return only the elements matching the word which is currently being written, so that&amp;#8217;s given as default parameter for your proc. Exactly like with ReadLine, the only difference is that you can access other things like &lt;em&gt;the whole line&lt;/em&gt; and &lt;em&gt;the whole history&lt;/em&gt; in real time, which can be really handy at times!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#8217;s a simple example:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt;&lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;editor.completion_proc = lambda &lt;span class="keyword"&gt;do&lt;/span&gt; |word|
&lt;span class="line-numbers"&gt;&lt;a href="#n2" name="n2"&gt;2&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;if&lt;/span&gt; word
&lt;span class="line-numbers"&gt;&lt;a href="#n3" name="n3"&gt;3&lt;/a&gt;&lt;/span&gt;    [&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;select&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;update&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;delete&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;debug&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;destroy&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;].find_all  { |e| e.match(&lt;span class="regexp"&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="content"&gt;^&lt;/span&gt;&lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;#{&lt;/span&gt;&lt;span class="constant"&gt;Regexp&lt;/span&gt;.escape(word)&lt;span class="inline-delimiter"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;/span&gt;) }
&lt;span class="line-numbers"&gt;&lt;a href="#n4" name="n4"&gt;4&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n5" name="n5"&gt;5&lt;/a&gt;&lt;/span&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;Custom key bindings&lt;/h3&gt;
&lt;p&gt;All these pretty things are obviously bound to some keystrokes. If the key corresponds to only one code, everything is fine, but because special keys typically aren&amp;#8217;t so it was necessary to implement a mechanism to track an escape key (e.g. 0xE0 and 0 on Windows and \e on Linux) and listen to further characters, in case a known sequence is found. Anyhow, the final result of the method used for character binding is the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bind(key, &amp;amp;block)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Where key can be:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;A &lt;code&gt;Fixnum&lt;/code&gt; corresponding to a single character code&lt;/li&gt;
	&lt;li&gt;An &lt;code&gt;Array&lt;/code&gt; of one or more character codes&lt;/li&gt;
	&lt;li&gt;A &lt;code&gt;String&lt;/code&gt; corresponding to an escape sequence&lt;/li&gt;
	&lt;li&gt;A &lt;code&gt;Symbol&lt;/code&gt; corresponding to a known escape sequence or key&lt;/li&gt;
	&lt;li&gt;A &lt;code&gt;Hash&lt;/code&gt; to define a new key or escape sequences&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, in the end you can do things like this:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt;&lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;editor.bind(&lt;span class="symbol"&gt;:left_arrow&lt;/span&gt;) { editor.move_left }
&lt;span class="line-numbers"&gt;&lt;a href="#n2" name="n2"&gt;2&lt;/a&gt;&lt;/span&gt;editor.bind(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="char"&gt;\e&lt;/span&gt;&lt;span class="content"&gt;test&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) { editor.overwrite_line(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;Test!!&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) }
&lt;span class="line-numbers"&gt;&lt;a href="#n3" name="n3"&gt;3&lt;/a&gt;&lt;/span&gt;editor.bind(&lt;span class="integer"&gt;?\C-z&lt;/span&gt;) { editor.undo }
&lt;span class="line-numbers"&gt;&lt;a href="#n4" name="n4"&gt;4&lt;/a&gt;&lt;/span&gt;editor.bind([&lt;span class="integer"&gt;24&lt;/span&gt;]) { exit }
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Which, for Rubyists, it&amp;#8217;s far sexier and more flexible than editing an .inputrc file.&lt;/p&gt;
&lt;h3&gt;How do I use it, anyway?&lt;/h3&gt;
&lt;p&gt;A code example is better than a thousand words, right? So here you are:&lt;/p&gt;
&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="line-numbers"&gt; &lt;a href="#n1" name="n1"&gt;1&lt;/a&gt;&lt;/span&gt;&lt;span class="doctype"&gt;#!/usr/local/bin/ruby -w&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n2" name="n2"&gt;2&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n3" name="n3"&gt;3&lt;/a&gt;&lt;/span&gt;require &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rubygems&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n4" name="n4"&gt;4&lt;/a&gt;&lt;/span&gt;require &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rawline&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n5" name="n5"&gt;5&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n6" name="n6"&gt;6&lt;/a&gt;&lt;/span&gt;puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;*** Inline Editor Test Shell ***&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n7" name="n7"&gt;7&lt;/a&gt;&lt;/span&gt;puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt; * Press CTRL+X to exit&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n8" name="n8"&gt;8&lt;/a&gt;&lt;/span&gt;puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt; * Press CTRL+C to clear command history&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt; &lt;a href="#n9" name="n9"&gt;9&lt;/a&gt;&lt;/span&gt;puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt; * Press CTRL+D for line-related information&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;strong&gt;&lt;a href="#n10" name="n10"&gt;10&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt; * Press CTRL+E to view command history&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n11" name="n11"&gt;11&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n12" name="n12"&gt;12&lt;/a&gt;&lt;/span&gt;editor = &lt;span class="constant"&gt;RawLine&lt;/span&gt;::&lt;span class="constant"&gt;Editor&lt;/span&gt;.new
&lt;span class="line-numbers"&gt;&lt;a href="#n13" name="n13"&gt;13&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n14" name="n14"&gt;14&lt;/a&gt;&lt;/span&gt;editor.bind(&lt;span class="symbol"&gt;:ctrl_c&lt;/span&gt;) { editor.clear_history }
&lt;span class="line-numbers"&gt;&lt;a href="#n15" name="n15"&gt;15&lt;/a&gt;&lt;/span&gt;editor.bind(&lt;span class="symbol"&gt;:ctrl_d&lt;/span&gt;) { editor.debug_line }
&lt;span class="line-numbers"&gt;&lt;a href="#n16" name="n16"&gt;16&lt;/a&gt;&lt;/span&gt;editor.bind(&lt;span class="symbol"&gt;:ctrl_e&lt;/span&gt;) { editor.show_history }
&lt;span class="line-numbers"&gt;&lt;a href="#n17" name="n17"&gt;17&lt;/a&gt;&lt;/span&gt;editor.bind(&lt;span class="symbol"&gt;:ctrl_x&lt;/span&gt;) { puts; puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;Exiting...&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;; exit }
&lt;span class="line-numbers"&gt;&lt;a href="#n18" name="n18"&gt;18&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n19" name="n19"&gt;19&lt;/a&gt;&lt;/span&gt;editor.completion_proc = lambda &lt;span class="keyword"&gt;do&lt;/span&gt; |word|
&lt;span class="line-numbers"&gt;&lt;strong&gt;&lt;a href="#n20" name="n20"&gt;20&lt;/a&gt;&lt;/strong&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;if&lt;/span&gt; word
&lt;span class="line-numbers"&gt;&lt;a href="#n21" name="n21"&gt;21&lt;/a&gt;&lt;/span&gt;    [&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;select&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;update&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;delete&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;debug&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;destroy&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;].find_all  { |e| e.match(&lt;span class="regexp"&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="content"&gt;^&lt;/span&gt;&lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;#{&lt;/span&gt;&lt;span class="constant"&gt;Regexp&lt;/span&gt;.escape(word)&lt;span class="inline-delimiter"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;/span&gt;) }
&lt;span class="line-numbers"&gt;&lt;a href="#n22" name="n22"&gt;22&lt;/a&gt;&lt;/span&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n23" name="n23"&gt;23&lt;/a&gt;&lt;/span&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n24" name="n24"&gt;24&lt;/a&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n25" name="n25"&gt;25&lt;/a&gt;&lt;/span&gt;loop &lt;span class="keyword"&gt;do&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n26" name="n26"&gt;26&lt;/a&gt;&lt;/span&gt;  puts &lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;You typed: [&lt;/span&gt;&lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;#{&lt;/span&gt;editor.read(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;=&amp;gt; &lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).chomp!&lt;span class="inline-delimiter"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="content"&gt;]&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="line-numbers"&gt;&lt;a href="#n27" name="n27"&gt;27&lt;/a&gt;&lt;/span&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;This example can be found in examples/rawline_shell.rb within the RawLine source code or gem package.&lt;/p&gt;
&lt;h2&gt;Current status and availability&lt;/h2&gt;
&lt;p&gt;I currently &lt;a href="http://rubyforge.org/forum/forum.php?forum_id=22543"&gt;released&lt;/a&gt; RawLine 0.1.0 on &lt;a href="http://rubyforge.org/projects/rawline"&gt;SourceForge&lt;/a&gt;, and it can be installed via:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gem install -r rawline&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The RDoc documentation is available &lt;a href="http://rawline.rubyforge.org/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Feel free to try it out. First of all try the &lt;code&gt;rawline_shell.rb&lt;/code&gt; example, and see if it works on your machine. If it doesn&amp;#8217;t than maybe you try re-binding some keys (use &lt;code&gt;key_tester.rb&lt;/code&gt; to &amp;#8220;reverse-engineer&amp;#8221; your terminal&amp;#8217;s input escape sequences), and let me know!&lt;/p&gt;
&lt;p&gt;Status information and limitations:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;It has been tested on Windows (XP, using the usual command prompt) and on Linux (ZenWalk, using &lt;span class="caps"&gt;XFCE&lt;/span&gt; Terminal).&lt;/li&gt;
	&lt;li&gt;It can handle lines no longer than the maximum terminal width &amp;#8211; 2. This is to ensure that the cursor never &amp;#8220;falls down&amp;#8221; to the next line.&lt;/li&gt;
	&lt;li&gt;On Windows, the cursor doesn&amp;#8217;t blink immedialy when moving left, but it moves, don&amp;#8217;t worry.&lt;/li&gt;
	&lt;li&gt;On Linux, you should really consider installing the &lt;a href="http://raa.ruby-lang.org/project/ruby-termios/"&gt;Termios&lt;/a&gt; library for a faster experience (otherwise &lt;code&gt;get_character&lt;/code&gt; won&amp;#8217;t parse characters correctly if you press and hold a key, and that, trust me, is a real mess!).&lt;/li&gt;
	&lt;li&gt;RawLine is very far from being a complete replacement for the ReadLine library, and it is currently in alpha stage.&lt;/li&gt;
	&lt;li&gt;Release 0.1.0 has been created after 2 weeks of sporadic coding during lunch breaks and week-ends.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For any ideas on where to go from here, comments and feedback, just reply below or send an email to my usual email address.&lt;/p&gt;</description>
      <pubDate>Sun, 09 Mar 2008 23:59:00 -0600</pubDate>
      <guid>http://www.h3rald.com/articles/inline-introduction/</guid>
      <link>http://www.h3rald.com/articles/inline-introduction/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/inline-introduction/#comments</comments>
      <category>ruby</category>
      <category>programming</category>
      <category>opensource</category>
      <category>rawline</category>
    </item>
  </channel>
</rss>

