<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>sixohthree.com &#187; compgen</title>
	<atom:link href="http://sixohthree.com/tag/compgen/feed" rel="self" type="application/rss+xml" />
	<link>http://sixohthree.com</link>
	<description>The Weblog of Adam Backstrom</description>
	<lastBuildDate>Sat, 04 Feb 2012 12:27:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Bash Completion</title>
		<link>http://sixohthree.com/867/bash-completion</link>
		<comments>http://sixohthree.com/867/bash-completion#comments</comments>
		<pubDate>Fri, 05 Jun 2009 00:54:42 +0000</pubDate>
		<dc:creator>Adam Backstrom</dc:creator>
				<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Bash]]></category>
		<category><![CDATA[compgen]]></category>
		<category><![CDATA[complete]]></category>
		<category><![CDATA[productivity]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://sixohthree.com/?p=867</guid>
		<description><![CDATA[It would be difficult to <em>not</em> like bash's programmable completion. It's too bad I've had such a hard time wrapping my head around the programmable completion toolkit.]]></description>
			<content:encoded><![CDATA[<p>It would be difficult to <em>not</em> like bash&#8217;s <a href="http://www.gnu.org/software/bash/manual/bashref.html#Programmable-Completion">programmable completion</a>. Tab completion is addictive, and expanding it past files and folders into usernames, hostnames, and, well, anything you can dream up and put in a function, has incredible potential.</p>
<p>It&#8217;s too bad I&#8217;ve had such a hard time wrapping my head around the programmable completion toolkit, <code>complete</code> and <code>compgen</code>.</p>
<h3 id="867_getting-there_1">Getting There</h3>
<p>I have a function that works like <code>cd</code>, but prepends a specific directory. Our web files are stored in <code>/some/dir/webapp</code>, and I want that directory at my fingertips at all times. Here&#8217;s the function:</p>
<pre><code>wa() { cd /web/pscpages/webapp/$1 ; }</code></pre>
<p>With this function, <code>wa</code> brings me to <code>webapp</code>; <code>wa project1</code> brings me to <code>webapp/project1</code>; and so on. I just provide the full sub-path from <code>webapp</code>. Ideally, I would be able to tab-complete directories in <code>webapp</code>.</p>
<p><code>complete</code> can pull a list of possible completions from a number of sources: &#8220;actions&#8221; (like files, directories, commands, shell keywords), command output, a wordlist separated by some whitespace, or the output of a bash function, to name a few. What you&#8217;ve typed so far (the &#8220;current word&#8221;) will be used to filter all the possible completions returned by that source. Say you&#8217;ve typed &#8220;pro&#8221; and then hit tab to autocomplete. The returned completions need to match &#8220;pro&#8221; at the start of the string, meaning you can&#8217;t match against absolute paths like <code>/some/dir/webapp/project1</code>.</p>
<p><code>compgen</code> can be used to generate a list of possible completions. Matches will be output one per line, and can be piped around for transformations just like any other shell command.</p>
<p>Between these two tools, we have everything we need to autocomplete paths starting in a certain directory. Here&#8217;s a <code>compgen</code> that gives us directories matching a specified string:</p>
<pre><code>compgen -d /some/dir/webapp/</code></pre>
<p>Sample output:</p>
<pre><code>/some/dir/webapp/.svn
/some/dir/webapp/project1
/some/dir/webapp/templates
/some/dir/webapp/images</code></pre>
<p>We need to trim leading directories so &#8220;pro&#8221; matches &#8220;project1.&#8221; We should also append <code>/</code> to the pathnames, since we&#8217;re always matching directories:</p>
<pre><code>compgen -S/ -d /some/dir/webapp/ | cut -b 18-</code></pre>
<p>Playing around with <code>compgen</code>&#8216;s arguments, we can further filter the completion list by appending to our string, sort of an implied glob. Use <code>/some/dir/webapp/p</code>, and subdirectories starting with &#8220;p&#8221; will be returned. This is exactly what we want: <code>compgen</code> takes care of all the filtering for us. We have access to a couple special variables to examine the word the user is expanding. For now, it&#8217;s enough just to grab <var>${COMP_WORDS[COMP_CWORD]}</var> and append it to our path.</p>
<p>When completions are generated by a function, they&#8217;re passed back to <code>complete</code> by the <var>$COMPREPLY</var> environment variable. Pulling this all together, we can now create our completion function:</p>
<pre><code>_webapp() {
    local cur
    cur=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=( $( compgen -S/ -d /some/dir/webapp/$cur | cut -b 18- ) )
}</code></pre>
<p>All that&#8217;s left is to tell bash to use this function to complete our argument to <code>wa</code>.</p>
<pre><code>complete -o nospace -F _webapp wa</code></pre>
<h3 id="867_the-fruits_1">The Fruits</h3>
<p>So, that does it. Our original wrapper to <code>cd</code>, combined with our autocomplete functionality, looks like this:</p>
<pre><code>wa() { cd /some/dir/webapp/$1 ; }
_webapp() {
    local cur
    cur=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=( $( compgen -S/ -d /some/dir/webapp/$cur | cut -b 18- ) )
}
complete -o nospace -F _webapp wa</code></pre>
<p>Voila. Tab completion in a directory that&#8217;s not <var>$PWD</var>, and it even works with subdirectories. I hope this makes autocompletion a little clearer for others.</p>
]]></content:encoded>
			<wfw:commentRss>http://sixohthree.com/867/bash-completion/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

