Writing essays in VIM and Latex

I’m only taking one humanities course this semester, so I don’t have that many essays to write. But for the few assignments in that course, I’m planning to use VIM and Latex to write my essays. I have Pages.app installed on my laptop, and I already use Google Docs for stuff, but I’m still more comfortable writing in VIM, even if I’m not writing code.

Smart quotes

Latex handles smart quotes like you’d expect it to. If there are single-quotes or double-quotes in the text section of your document, they’ll get turned into left and right quotes in the final PDF.

Spell checking

I just use VIM’s built-in spell-checking feature. Make sure you use it with MacVIm/GVIM, or else it looks terrible. Apparently there’s a way to bring up the correction suggestions list too, if you look for it.

Rich formatting

You can do bold and italics and lists in Latex. I like it even better than the WYSIWYG editors, since you can do line manipulation and fancy macro stuff in VIM too.

Instant feedback

You can mix inotify-tools and your Latex compiler to get you basically instant feedback. Every time you save the file, you can get it to re-compile your Latex and Preview.app will reload it. I’m just sharing my home folder through VirtualBox shared folders (configured in Vagrant), so I can work with files directly on the VM.

MongoDB power usage on laptop

I’m setting up a Chef-based Ubuntu VM on my laptop, so I can get sandboxing and all the usual Ubuntu tools. Most things work on OS X too, but it’s a second-class citizen compared to poster child Ubuntu. I have Mongo and a few services set up there, for school stuff, and I noticed that Mongo regularly uses a significant amount of CPU time, even when it’s not handling any requests.

I attached strace to it with strace -f -p 1056, and here’s what I saw:

[pid 1118] select(12, [11], NULL, NULL, {0, 10000} <unfinished ...>
[pid 1056] select(11, [9 10], NULL, NULL, {0, 10000} <unfinished ...>
[pid 1118] <... select resumed> ) = 0 (Timeout)
[pid 1056] <... select resumed> ) = 0 (Timeout)
[pid 1118] select(12, [11], NULL, NULL, {0, 10000} <unfinished ...>
[pid 1056] select(11, [9 10], NULL, NULL, {0, 10000} <unfinished ...>
[pid 1112] <... nanosleep resumed> 0x7fd3895319a0) = 0
[pid 1112] nanosleep({0, 34000000}, <unfinished ...>
[pid 1118] <... select resumed> ) = 0 (Timeout)
[pid 1056] <... select resumed> ) = 0 (Timeout)
[pid 1118] select(12, [11], NULL, NULL, {0, 10000} <unfinished ...>
[pid 1056] select(11, [9 10], NULL, NULL, {0, 10000} <unfinished ...>
[pid 1118] <... select resumed> ) = 0 (Timeout)
[pid 1056] <... select resumed> ) = 0 (Timeout)
[pid 1118] select(12, [11], NULL, NULL, {0, 10000} <unfinished ...>
[pid 1056] select(11, [9 10], NULL, NULL, {0, 10000} <unfinished ...>
[pid 1118] <... select resumed> ) = 0 (Timeout)
[pid 1056] <... select resumed> ) = 0 (Timeout)
[pid 1118] select(12, [11], NULL, NULL, {0, 10000} <unfinished ...>
[pid 1056] select(11, [9 10], NULL, NULL, {0, 10000} <unfinished ...>
[pid 1112] <... nanosleep resumed> 0x7fd3895319a0) = 0

I looked online for an explanation, and I found this bug about MongoDB power usage. Apparently, it uses select() as a way to do timekeeping for all the ways Mongo uses wall time. Somebody proposed that alternative methods be used instead, which don’t require this kind of tight looping, but it looks like the Mongo team is busy with other stuff right now and won’t consider the patch.

So I added a clause in my Chef config to disable the MongoDB service from starting automatically on boot. I needed to specify the Upstart service provider explicitly in the configuration, since the mongodb package installs both a SysV script and Upstart manifest.

Comma mode for vim

Most keyboards have a Control and Meta key. Macs also have the Command key. Even with all the combinations of Control and Meta and Command with the letters and numbers, it’s sometimes hard to have enough space for keyboard shortcuts that don’t conflict and override each other. This is especially important in vim, where keyboard shortcuts are everything. Most of the good ones are taken already.

My keybindings

I adapted an idea from tinymode.vim and created another key modifier: the comma. Here are some of the keybindings I’ve set:

  • ,v creates a vertical split
  • ,t opens a new tab
  • ,1 toggles line wrapping
  • ,2 opens NERDTree
  • ,0 enables spellcheck and textwidth
  • ,q quits the current buffer
  • ,b opens CtrlP in buffer mode
  • ,c opens the cd prompt
  • ,f opens the filetype prompt
  • ,U toggles line numbers

The comma works just like Control or Meta. You can hold it down and press multiple keyboard shortcuts. For example, multiple q’s can be chained to close multiple buffers in succession. Or t and v can be chained to create a new 2-pane tab.

Configuration

These six lines form the core of comma mode:

nmap , :set timeoutlen=86400000<CR><SID>ldr
vmap , :set timeoutlen=86400000<CR><SID>ldr
nn <script> <SID>ldr, <SID>ldr
vn <script> <SID>ldr, <SID>ldr
nmap <SID>ldr :set timeoutlen=1000<CR>
vmap <SID>ldr :set timeoutlen=1000<CR>

Pressing the comma key will 1) set the key combination delay to an absurdly long time, and 2) set up the <SID>ldr keyword for the following comma command. Vim provides <SID> as a script-local unique identifier to help you avoid naming conflicts.

Chainable commands

Once comma mode is set up, you can add chainable commands. These commands can be chained together with other comma commands in succession.

nn <script> <SID>ldr1 :set wrap!<CR><SID>ldr
vn <script> <SID>ldr1 :set wrap!<CR><SID>ldr

Everything after the first <SID>ldr is the comma keybinding. In this case, just the number 1. An arbitrary command is run, and then the line ends with <SID>ldr to set up chaining for the next command.

Non-chainable commands

You can also add non-chainable commands. These are useful for comma shortcuts that open prompts, which you would never use with other comma shortcuts.

nn <script> <SID>ldrc :set timeoutlen=1000<CR>:cd 
vn <script> <SID>ldrc :set timeoutlen=1000<CR>:cd

There’s an invisible space at the end of these two lines, so the prompt is ready to accept a path. Non-chainable commands reset the timeoutlen to a default 1000. This is the same behavior as the null binding (the last two lines of the Configuration section), which runs when you run a non-existent comma command, or press ESC in comma mode.

Conclusion

Comma mode has been the #1 most productivity-boosting featured I’ve added to vim. Mapping semicolon to colon is a start, but it only takes :q from 4 keystrokes to 3 keystrokes (including the Enter key). With comma mode, this is now just 2 keystrokes — just the way keyboard shortcuts should be.

Taking advantage of cloud VM-driven development

Most people write about cloud computing as it relates to their service infrastructure. It’s exciting to hear about how Netflix and Dropbox et al. use AWS to support their operations, but all of those large-scale ideas don’t really mean much for the average developer. Most people don’t have the budget or the need for enormous computing power or highly-available SaaS data storage like S3, but it turns out that cloud-based VM’s can be highly useful for the average developer in a different way.

Sometimes, you see something like this one-liner installation script for Heroku Toolbelt, and you just get nervous:

wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh

Not only are they asking you to run a shell script downloaded over the Internet, but the script also asks for root privileges to install packages and stuff. Or, maybe you’re reading a blog post about some HA database cluster software and you want to try it out yourself, but running 3 virtual machines on your puny laptop is out of the questions.

To get around this issue, I’ve been using DigitalOcean machines for when I want to test something out but don’t want to go to the trouble of maintaining a development server or virtual machines. Virtualized cloud servers are great for this because:

  • They’re DIRT CHEAP. DO’s smallest machine costs $0.007 an hour. Even if you use it for 2 hours, it rounds down to 1 cent.
  • The internet connection is usually a lot better than whatever you’re using. Plus, most cloud providers have local mirrors for package manager stuff, which makes installing packages super fast.
  • Burstable CPU means that you can get an unfair amount of processing power for a short time at the beginning, which comes in handy for initially installing and downloading all the stuff you’ll want to have on your machine.

I use the tugboat client (a CLI ruby app) to interface with the DigitalOcean API. To try out MariaDB Galera clustering, I just opened up three terminals and had three SSH sessions going on. For source builds that have a dozen or more miscellaneous dependencies, I usually just prepare a simple build script that I can upload and run on a Cloud VM whenever I need it. When I’m done with a machine, I’ll shut it down until I need a machine again a few days later.

Running development virtual machines in the cloud might not drastically change your workflow, but it opens up a lot of opportunities for experimentation and massive computing resources when you want it. So load up a couple dollars onto a fresh DigitalOcean account and boot up some VMs!

Getting a python-like shell for Perl

When learning a new language, I find it really helpful if I can test out new syntax and language constructs without going through the trouble of creating a file and all the boilerplate along with it. Perl doesn’t have this capability built-in, as far as I know, but there’s this great CPAN module that claims to do the same thing. It’s a short little module (just about 100 SLOC), and it gives you a familiar prompt:

Perl 5.14.2 (Tue Feb  4 23:09:53 UTC 2014) [linux panlong 2.6.42-37-generic #58-ubuntu smp thu jan 24 15:28:10 utc 2013 x86_64 x86_64 x86_64 gnulinux ]
Type "help;", "copyright;", or "license;" for more information.
>>> 

It’s not very obvious how to set up the thing though. I installed the module and its dependencies via cpanm, and then created this little snippet in a file called perlthon.pl:

#!/usr/bin/perl
use 5.010;
use strict;
use warnings;

use Perl::Shell;
Perl::Shell::shell();

Then, the shell started right up.