<?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>Death of a Gremmie &#187; Programming</title>
	<atom:link href="http://deathofagremmie.com/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://deathofagremmie.com</link>
	<description>by Brian Neal</description>
	<lastBuildDate>Wed, 14 Jul 2010 02:31:19 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Django Middleware Gotcha</title>
		<link>http://deathofagremmie.com/2010/07/13/django-middleware-gotcha/</link>
		<comments>http://deathofagremmie.com/2010/07/13/django-middleware-gotcha/#comments</comments>
		<pubDate>Wed, 14 Jul 2010 02:31:19 +0000</pubDate>
		<dc:creator>gremmie</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[middleware]]></category>

		<guid isPermaLink="false">http://deathofagremmie.com/?p=361</guid>
		<description><![CDATA[Here&#8217;s a quick explanation of a gotcha I ran into while writing my own Django process_response middleware. I had written some middleware to perform a &#8220;who&#8217;s online&#8221; type function some time ago. The middleware checks to see if a cookie is present. If not, it updates the database with a timestamp for the user, and [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a quick explanation of a gotcha I ran into while writing my own Django <a href="http://docs.djangoproject.com/en/1.2/topics/http/middleware/#process-response">process_response middleware</a>. I had written some middleware to perform a &#8220;who&#8217;s online&#8221; type function some time ago. The middleware checks to see if a cookie is present. If not, it updates the database with a timestamp for the user, and then sets a cookie with a lifespan of 10 minutes. In this way I only have to update the database with &#8220;last seen&#8221; information about every 10 minutes, per user. Because I need to set a cookie, this processing had to be done in a process_response middleware. I had tested and debugged this middleware and I thought everything was fine.</p>
<p>But then yesterday I was checking various links on my site, and one link in particular generated a traceback from my middleware: &#8220;AttributeError: &#8216;WSGIRequest&#8217; object has no attribute &#8216;user&#8217;.&#8221; What? Why was this happening on this one particular view and only this view?</p>
<p>One of the first things I do in my process_response function is check to see if the user is authenticated:</p>
<pre>
<pre class="brush: python">
if request.user.is_authenticated():
    ...
</pre>
</pre>
<p>After putting a breakpoint in this code with <a href="http://docs.python.org/library/pdb.html">pdb</a>, I observed that indeed the request object my middleware received had no &#8220;user&#8221; attribute. This had me stupified until I suddenly realized that the link I had clicked on was of the form /xxx/yyy instead of /xxx/yyy/ due to a typo in my template. I forgotten the trailing slash. Aha, this was a clue, but I still couldn&#8217;t piece it together, and I had to get some sleep. I don&#8217;t know about you, but I hate going to sleep when you have a nagging unsolved problem.</p>
<p>Tonight I tackled the problem again. I remembered I have the <a href="http://docs.djangoproject.com/en/1.2/ref/settings/#append-slash">APPEND_SLASH setting</a> in my settings.py file set to True. This normalizes all my URLs such that they should all end in a trailing slash. This is implemented itself via a piece of middleware, the so called <a href="http://docs.djangoproject.com/en/1.2/ref/middleware/#module-django.middleware.common">&#8220;Common&#8221; middleware</a> which is baked into Django itself. I knew that there was some interaction going on between the CommonMiddleware and my own middleware. After reviewing the <a href="http://docs.djangoproject.com/en/1.2/topics/http/middleware/#topics-http-middleware">middleware docs</a> to refresh my memory on how all this works, I turned my attention to my <a href="http://docs.djangoproject.com/en/1.2/ref/settings/#middleware-classes">MIDDLEWARE_CLASSES setting</a>:</p>
<pre>
<pre class="brush: python">
MIDDLEWARE_CLASSES = (
    &#039;django.middleware.common.CommonMiddleware&#039;,
    &#039;django.middleware.csrf.CsrfViewMiddleware&#039;,
    &#039;django.contrib.sessions.middleware.SessionMiddleware&#039;,
    &#039;django.contrib.messages.middleware.MessageMiddleware&#039;,
    &#039;debug_toolbar.middleware.DebugToolbarMiddleware&#039;,
    &#039;django.contrib.auth.middleware.AuthenticationMiddleware&#039;,
    &#039;gpp.core.middleware.InactiveUserMiddleware&#039;,
    &#039;gpp.core.middleware.WhosOnline&#039;,
    &#039;django.contrib.flatpages.middleware.FlatpageFallbackMiddleware&#039;,
)
</pre>
</pre>
<p>Because of the order above, the first piece of middleware to process a request is the CommonMiddleware. When it observed the lack of a trailing slash, it returned a HttpResponseRedirect object to redirect the user to the correct URL with a trailing slash. This immediately killed the the process_request chain of middleware processing. Thus, the AuthenticationMiddleware never got to run, and this is the middleware that attaches the user object to the request. Furthermore, since the request processing ended, we now start the process_response processing. This works through the above middleware list backwards. So when my WhosOnline middleware gets called, it is suddenly presented with a request object that has no user attribute. And bam, I hit my bug.</p>
<p>To fix this problem, one could reorder the list of middleware. But finding a middleware ordering that will satisfy all of your installed middleware is a kind of a maddening process that requires flipping through many doc pages. It just appeared to be too brittle of a solution. I&#8217;ll probably add some middleware in the future and completely upset the apple cart again. In the end, I decided to just guard against the case of not having a user attribute on the request object and just bail out early. In this use case, it isn&#8217;t important to see every single response. I can simply make it up on the next one. So I modified my code to look like this:</p>
<pre>
<pre class="brush: python">
def process_response(self, request, response):
    &quot;&quot;&quot;
    Keep track of who is online.
    &quot;&quot;&quot;
    # Note that some requests may not have a user attribute
    # as these may have been redirected in the middleware chain before
    # the auth middleware got a chance to run. If this is the case, just
    # bail out. We also ignore AJAX requests.
    if not hasattr(request, &#039;user&#039;) or request.is_ajax():
        return response
    if request.user.is_authenticated():
        ...
</pre>
</pre>
<p>This was a difficult and unexpected bug. However it produced one of those rare, genuine &#8220;light bulb&#8221; moments as it forced me to take a hard look at Django&#8217;s middleware processing in detail and finally learn it front to back.</p>
]]></content:encoded>
			<wfw:commentRss>http://deathofagremmie.com/2010/07/13/django-middleware-gotcha/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery UI Autocomplete Widget &amp; Caching</title>
		<link>http://deathofagremmie.com/2010/04/03/jquery-ui-autocomplete-widget-caching/</link>
		<comments>http://deathofagremmie.com/2010/04/03/jquery-ui-autocomplete-widget-caching/#comments</comments>
		<pubDate>Sat, 03 Apr 2010 21:30:54 +0000</pubDate>
		<dc:creator>gremmie</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[autocomplete]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[jquery-ui]]></category>
		<category><![CDATA[plugins]]></category>

		<guid isPermaLink="false">http://deathofagremmie.com/?p=349</guid>
		<description><![CDATA[I upgraded to the awesome new 1.4 version of jQuery recently in preparation for deploying another beta version of my site. Unfortunately the jquery-autocomplete plugin by Jörn Zaefferer doesn&#8217;t work with this new version. However, the equally awesome jQuery user interface library, jQuery UI, now has a new autocomplete widget that is based upon Jörn&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>I upgraded to the awesome new 1.4 version of <a href="http://jquery.com/">jQuery</a> recently in preparation for deploying another beta version of my site. Unfortunately the <a href="http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/">jquery-autocomplete plugin by Jörn Zaefferer</a> doesn&#8217;t work with this new version. However, the equally awesome jQuery user interface library, <a href="http://jqueryui.com/">jQuery UI</a>, now has a new <a href="http://jqueryui.com/demos/autocomplete/">autocomplete widget</a> that is based upon Jörn&#8217;s design. The API isn&#8217;t quite the same, but after some reading you&#8217;ll find that most of the functionality is still there. However the new UI widget does not support caching requests, leaving that to the user to implement. This kind of surprised me, as I would think that would be a commonly requested feature. But perhaps the UI folks felt that everyone would have different caching requirements. There is <a href="http://jqueryui.com/demos/autocomplete/#remote-with-cache">one example on the UI site of how to cache</a>, but curiously it only caches the last request, which doesn&#8217;t seem all that useful to me.</p>
<p>In any event, after reading the documentation, it wasn&#8217;t hard to implement caching for my purposes. The following code simply caches the last 16 requests. Once the cache is full, it is flushed completely and ready to be filled again. Simple, crude, but hopefully somewhat effective.  I&#8217;m not a Javascript expert, but this will work for me. I hope someone else finds it useful and can use it as a starting point for their use-case.</p>
<pre>
<pre class="brush: javascript">
$(function() {
    var cache = {};
    var cacheSize = 0;
    $(&quot;#id_of_your_text_box&quot;).autocomplete({
        delay: 400,
        minLength: 2,
        source: function(request, response) {
            if (cache[request.term]) {
               response(cache[request.term]);
               return;
            }
            $.ajax({
                url: &quot;/your/url/goes/here/&quot;,
                type: &quot;GET&quot;,
                data: {
                    q: request.term,
                    limit: 10
                },
                dataType: &quot;json&quot;,
                success: function(data, textStatus) {
                    if (cacheSize &gt;= 16) {
                       cache = {};
                       cacheSize = 0;
                    }
                    cache[request.term] = data;
                    ++cacheSize;
                    response(data);
                },
                error: function(xhr, textStatus, ex) {
                    alert(&#039;Oops, an error occurred. &#039; + xhr.statusText + &#039; - &#039; +
                      xhr.responseText);
                }
            });
        }
    });
});
</pre>
</pre>
<p>The key to making this to work is to provide your own source function to the autocomplete widget. The widget will call this function when it needs data. Inside the function we simply check to see if request.term is already in our cache. If it is, then we simply return the cached result via the response callback function. If not, we have to make an ajax call to the server to retrieve the data.  When the ajax call completes, we store the result in our cache and then return it to the widget.</p>
<p>Again, this code simply stores the last 16 requests. When we run out of room we simply empty the cache and start over. A more sophisticated algorithm could use a different strategy like removing only the first item put in the cache or even the &#8220;least recently used&#8221; cache item. Break out your college computer science textbook on caching strategies and go nuts here.</p>
<p>The other feature this code doesn&#8217;t do is provide matching capabilities. For example, if the user has typed &#8220;foo&#8221; in the input box, this code will not return results for &#8220;bar foo&#8221;. If you need this, I suggest looking at the caching example on the UI site, or even at Jörn Zaefferer&#8217;s source code.</p>
]]></content:encoded>
			<wfw:commentRss>http://deathofagremmie.com/2010/04/03/jquery-ui-autocomplete-widget-caching/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Testing Your First Django App</title>
		<link>http://deathofagremmie.com/2010/01/22/testing-your-first-django-app/</link>
		<comments>http://deathofagremmie.com/2010/01/22/testing-your-first-django-app/#comments</comments>
		<pubDate>Sat, 23 Jan 2010 01:16:22 +0000</pubDate>
		<dc:creator>gremmie</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[unittest]]></category>

		<guid isPermaLink="false">http://deathofagremmie.com/?p=337</guid>
		<description><![CDATA[Dougal Matthews wrote a great blog post entitled &#8220;Testing Your First Django App&#8220;. This is something that I have been meaning to do for a long time now, but didn&#8217;t know how to get started. Much to my surprise (I guess I shouldn&#8217;t be), Python supports the xUnit style of testing via the standard library [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://dougalmatthews.com/">Dougal Matthews</a> wrote a great blog post entitled &#8220;<a href="http://dougalmatthews.com/articles/2010/jan/20/testing-your-first-django-app/">Testing Your First Django App</a>&#8220;. This is something that I have been meaning to do for a long time now, but didn&#8217;t know how to get started. Much to my surprise (I guess I shouldn&#8217;t be), Python supports the <a href="http://en.wikipedia.org/wiki/XUnit">xUnit</a> style of testing via the standard library package <a href="http://docs.python.org/library/unittest.html">unittest</a>. Since we are now using <a href="http://cxxtest.tigris.org/">CxxTest</a> at work, this is quite familiar to me now. Dougal&#8217;s blog entry shows some nice ways of testing Django web applications without using a server by mocking up requests and examining responses from your view functions. Very cool!</p>
]]></content:encoded>
			<wfw:commentRss>http://deathofagremmie.com/2010/01/22/testing-your-first-django-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python and SSH</title>
		<link>http://deathofagremmie.com/2009/12/31/python-and-ssh/</link>
		<comments>http://deathofagremmie.com/2009/12/31/python-and-ssh/#comments</comments>
		<pubDate>Fri, 01 Jan 2010 04:26:15 +0000</pubDate>
		<dc:creator>gremmie</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[cygwin]]></category>
		<category><![CDATA[paramiko]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[sftp]]></category>
		<category><![CDATA[ssh]]></category>
		<category><![CDATA[webcam]]></category>

		<guid isPermaLink="false">http://deathofagremmie.com/?p=332</guid>
		<description><![CDATA[I was fooling around with my webcam, and I got to wondering if I could write a small Python script to upload a snapshot to my webserver periodically. Since I was planning on uploading a new snapshot every ten minutes or so, I&#8217;d rather use SFTP to avoid sending my login and password unencrypted so [...]]]></description>
			<content:encoded><![CDATA[<p>I was fooling around with my webcam, and I got to wondering if I could write a small Python script to upload a snapshot to my webserver periodically. Since I was planning on uploading a new snapshot every ten minutes or so, I&#8217;d rather use <a href="http://en.wikipedia.org/wiki/SSH_file_transfer_protocol">SFTP</a> to avoid sending my login and password unencrypted so frequently. I had already <a href="http://deathofagremmie.com/tag/ftplib/">used FTP in Python</a> before in a backup script, but I didn&#8217;t know if the Python standard library had a solution for SSH. After a bit of Googling, I discovered the 3<sup>rd</sup> party Python module <a href="http://www.lag.net/paramiko/">Paramiko</a> (the name is a combination of the Esperanto words for    &#8220;paranoid&#8221; and &#8220;friend&#8221; &#8212; I love that), which allows you to do all kinds of SSH2 operations, including SFTP. Paramiko is extremely <a href="http://www.lag.net/paramiko/docs/">well documented</a> (thank-you!) and I had no problems at all using it to accomplish my task. I also found this <a href="http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/">great introductory article</a> by Python core developer <a href="http://jessenoller.com/">Jesse Noller</a> that was helpful in getting up to speed on it quickly.</p>
<p>Since I was using my webcam from Windows XP, I decided to write my script under the new 1.7.1 version of <a href="http://cygwin.com">Cygwin</a> that came out recently. You&#8217;ll need to get both the Paramiko package and the python-crypto package.</p>
<p>Happy New Year everyone!</p>
]]></content:encoded>
			<wfw:commentRss>http://deathofagremmie.com/2009/12/31/python-and-ssh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python Subprocess Popen and Windows</title>
		<link>http://deathofagremmie.com/2009/12/13/python-subprocess-popen-and-windows/</link>
		<comments>http://deathofagremmie.com/2009/12/13/python-subprocess-popen-and-windows/#comments</comments>
		<pubDate>Sun, 13 Dec 2009 22:28:57 +0000</pubDate>
		<dc:creator>gremmie</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[subprocess]]></category>
		<category><![CDATA[svn]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://deathofagremmie.com/?p=322</guid>
		<description><![CDATA[I was writing a Python script to automate some Subversion-related tasks at work last week on Windows. The Python code was calling the Subversion command-line client applications using the Python subprocess module. I don&#8217;t know why exactly, but I had passed in the parameter shell=True to the subprocess.Popen function. I probably did this because I [...]]]></description>
			<content:encoded><![CDATA[<p>I was writing a Python script to automate some Subversion-related tasks at work last week on Windows. The Python code was calling the Subversion command-line client applications using the Python <a href="http://docs.python.org/library/subprocess.html">subprocess module</a>. I don&#8217;t know why exactly, but I had passed in the parameter shell=True to the subprocess.Popen function. I probably did this because I saw a lot of examples on the web, and you know, monkey-see, monkey-do. In hindsight, these examples were probably for Unix. It turned out that this caused a lot of problems. The Subversion clients started complaining when handed filenames that contained &#8220;special&#8221; characters like ampersands. And when they got to the files that had <strong>both</strong> ampersands and spaces, all kinds of crazy errors were produced. I was pulling my hair out, trying to escape the special characters and/or use quotes around the filename, but I could not come up with a combination that would work for all the different filenames the script encountered. Finally, as I stared at the code, I somehow got the idea to try switching that shell=True to shell=False.  Suddenly, everything worked perfectly. I undid all the escaping and quoting and everything worked as expected.</p>
<p>So I&#8217;m not sure what shell=True does on Windows, and it certainly isn&#8217;t documented. I do not recommend using it unless you know what is happening  in the implementation. Interestingly, shell=False is the default. I should have left it that way. <img src='http://deathofagremmie.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://deathofagremmie.com/2009/12/13/python-subprocess-popen-and-windows/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using the Python Shell in Vi Mode</title>
		<link>http://deathofagremmie.com/2009/11/30/using-the-python-shell-in-vi-mode/</link>
		<comments>http://deathofagremmie.com/2009/11/30/using-the-python-shell-in-vi-mode/#comments</comments>
		<pubDate>Tue, 01 Dec 2009 01:18:53 +0000</pubDate>
		<dc:creator>gremmie</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[readline]]></category>
		<category><![CDATA[vi]]></category>

		<guid isPermaLink="false">http://deathofagremmie.com/?p=319</guid>
		<description><![CDATA[The Python shell is an invaluable tool for trying things out and experimenting with the language. Wouldn&#8217;t it be great if you could use the Python shell in Vi mode? Much to my surprise, it turns out you can. Python leverages the GNU Readline Library in its shell code. The Readline library is used in [...]]]></description>
			<content:encoded><![CDATA[<p>The Python shell is an invaluable tool for trying things out and experimenting with the language. Wouldn&#8217;t it be great if you could use the Python shell in Vi mode? Much to my surprise, it turns out you can.</p>
<p>Python leverages the <a href="http://tiswww.case.edu/php/chet/readline/rltop.html">GNU Readline Library</a> in its shell code. The Readline library is used in a number of open source projects, notably the <a href="http://www.gnu.org/software/bash/bash.html">BASH shell</a>. The Readline library looks for a configuration file at startup in a number of places. On Unix-like operating systems, the configuration file can be found at <code>~/.inputrc</code> and falls back to <code>/etc/inputrc</code>.</p>
<p>One line is all you need in your <code>~/.inputrc</code> file:</p>
<pre>set editing-mode vi</pre>
<p>Unfortunately I don&#8217;t know how to make this work under Windows.</p>
]]></content:encoded>
			<wfw:commentRss>http://deathofagremmie.com/2009/11/30/using-the-python-shell-in-vi-mode/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Vim: Different Settings For Different File Types</title>
		<link>http://deathofagremmie.com/2009/11/18/vim-different-settings-for-different-file-types/</link>
		<comments>http://deathofagremmie.com/2009/11/18/vim-different-settings-for-different-file-types/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 18:56:22 +0000</pubDate>
		<dc:creator>gremmie</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://deathofagremmie.com/?p=315</guid>
		<description><![CDATA[Old habits die hard. I have been using 3 space indents for C and C++ code for as long as I have been a programmer. A little over a year ago I dove head-first into Python, and eventually discovered PEP 8. PEP 8 is basically the style guide for the Python community. I read it [...]]]></description>
			<content:encoded><![CDATA[<p>Old habits die hard. I have been using 3 space indents for C and C++ code for as long as I have been a programmer. A little over a year ago I dove head-first into Python, and eventually discovered <a title="PEP 8" href="http://www.python.org/dev/peps/pep-0008/">PEP 8</a>. PEP 8 is basically the style guide for the Python community. I read it with great interest and took just about everything to heart, except for the recommended 4-space indents. I just could not shake my old habit.</p>
<p>Eventually as I got more and more excited about Python I decided to wholly embrace the customs of the community. But how could I easily tell my favorite editor <a title="Vim" href="http://www.vim.org/">Vim</a> to use 4-space indents for just Python code? I still do a lot of C++ at work, and I still like 3-space indents in other file types.</p>
<p>My first attempt was to use a Vim modeline embedded right in my source files. At the bottom of my Python files I placed this line:</p>
<pre># vim: set sw=4 ts=4:</pre>
<p>When Vim first opens a file, it scans the first and last few lines in the file, looking for modelines, and will use the settings just for that file.</p>
<p>This obviously worked, but soon I found it ugly and distracting to have that at the bottom of each file. And sometimes I would forget to put it there, and not realize it until a bunch of code had been written.</p>
<p>It turns out there is a far easier way, but it took some digging to discover. Vim has a very elaborate system of determing file types. If you peek into your Vim installation directory, you&#8217;ll see a ftplugin directory. This directory is full of little files that get executed once the type of a file has been determined. Some people on the Web suggest that you should modify these files directly. Thus I could modify the ftplugin/python.vim file, and place my tabstop and shiftwidth settings in there. But you would be modifying a Vim file, and your changes would get lost the next time you upgrade Vim.</p>
<p>There is a much better solution. After Vim executes the python.vim file in the ftplugins directory, it looks for a file called ~/.vim/after/ftplugin/python.vim (on Unix; on Windows I&#8217;ve had luck with C:\Progam Files\Vim\vimfiles\after\ftplugin\python.vim). If this file exists, it will be executed after the &#8220;official&#8221; python.vim file.</p>
<p>Inside your personal python.vim file, the documentation says to use the &#8220;setlocal&#8221; instead of &#8220;set&#8221; command. Thus, my file looks like:</p>
<pre style="text-align: left;">setlocal tabstop=4
setlocal shiftwidth=4</pre>
<p style="text-align: left;">Although to be honest, I&#8217;ve used the regular set for some time (by accident) without seeing any strange effects.</p>
<p style="text-align: left;">Happy Vimming!</p>
]]></content:encoded>
			<wfw:commentRss>http://deathofagremmie.com/2009/11/18/vim-different-settings-for-different-file-types/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I </title>
		<link>http://deathofagremmie.com/2009/09/24/i-heart-vim/</link>
		<comments>http://deathofagremmie.com/2009/09/24/i-heart-vim/#comments</comments>
		<pubDate>Fri, 25 Sep 2009 00:15:23 +0000</pubDate>
		<dc:creator>gremmie</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://deathofagremmie.com/?p=310</guid>
		<description><![CDATA[I love the text editor Vim. I started using Vi because I really didn&#8217;t know any better around 1988 when I was first teaching myself C on my trusty Amiga 500. Not long after that I discovered Vim which sported many improvements over the venerable Vi. Sometime around 1993-1994 I started hacking Vim. I added [...]]]></description>
			<content:encoded><![CDATA[<p>I love the text editor <a href="http://vim.org">Vim</a>. I started using Vi because I really didn&#8217;t know any better around 1988 when I was first teaching myself C on my trusty Amiga 500. Not long after that I discovered Vim which sported many improvements over the venerable Vi. Sometime around 1993-1994 I started hacking Vim. I added a complete <a href="http://en.wikipedia.org/wiki/ARexx">ARexx</a> port to Vim so that you could script it. Alas, a new version of Vim came out right after I finished, and author <a href="http://www.moolenaar.net/">Bram Moolenaar</a> had changed the code so much I felt it was impossible to merge my changes into the new version. This was when I was a young pup programmer, and I was unfamiliar with revision control and difference/merging tools. I had fun doing it anyway, so I just chalked it up to experience.</p>
<p>I have used Vim on every programming task at every job I&#8217;ve had. I&#8217;m constantly learning new things about it, and the commands and keystrokes are now part of my DNA. I don&#8217;t even think how to execute commands anymore and I am often hard pressed to recall them to others learning Vim. I have to sit at a keyboard with Vim running in order to understand what my fingers are doing.</p>
<p>A while back, I discovered the auto-complete feature, where you type Ctrl-n in insert mode and Vim will attempt to complete the word you are typing based on all the words in all buffers and how frequently they occur. This is incredibly handy when programming to quickly pound out those function and variable names. I used &#8220;imap &lt;S-Tab&gt; &lt;C-n&gt;&#8221; in my .vimrc file to map this to shift-tab, which I felt was more convenient.</p>
<p>I also picked up a really handy way to <a href="http://vim.wikia.com/wiki/Cycle_through_buffers_including_hidden_buffers">cycle through all your buffers</a>.  I used the tab and shift-tab mapping mentioned in that Vim tip. Combine that with Vim&#8217;s tab feature I can very easily find the file I am looking for.</p>
<p>And finally I had another big &#8220;wow, Vim can do that?&#8221; moment just last week. Since version 7, Vim has sported an &#8220;omni-complete&#8221; framework. Basically it is an architecture for people to hang code completion routines into Vim. In fact, right out of the box, Vim 7 has support for Javascript, CSS, and yes, even Python! Python completion is only available if you are using a version of Vim that has been compiled with Python support (e.g. on Ubuntu). Imagine my shock when I was editing a CSS file and I typed &#8220;display:&#8221; and then hit Ctrl-X Ctrl-O for the first time and a drop down list of all the possible values (inline, block, none, etc) appeared! No more hunting for that w3schools website. And the Python support is just as handy. Type &#8220;os.path.&#8221; followed by Ctrl-X Ctrl-O and you can see all the entities and function in the os.path module. I had no idea!</p>
<p>So all of this reminds me it is time to once again donate to the Vim project. Thanks Bram for all your amazing work you do on this invaluable tool.</p>
<p>P.S. I have no interest in the great editor holy war. Use a tool that you find intuitive and useful and learn it, back to front. I&#8217;m sure there is nothing wrong with other popular editors. But for me, Vim is it. I can&#8217;t imagine how many hours of productivity it has given me over the years.</p>
]]></content:encoded>
			<wfw:commentRss>http://deathofagremmie.com/2009/09/24/i-heart-vim/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
