login

Disable All The Caps

If you’re like me and absolutely abhor the Caps Lock key, you’ve probably figured out some way to replace it with a more suitable function. I myself have settled on the following command to make it a duplicate Ctrl key:

$ setxkbmap -option ctrl:nocaps

This works great when placed in ~/.xinitrc and run as X starts, but what about USB keyboards which are plugged in later? Perhaps your pair-programming, or moving your laptop between work and home. This happens frequently enough that I thought it’d be nice to use a udev rule to trigger the command auto-magically whenever a keyboard is plugged in.

The setup is fairly simple in the end, but I found enough minor traps that I thought it was appropriate to document things once I got it working.

Script

You can’t just place the setxkbmap command directly in a udev rule (that’d be too easy!) since you’ll need enough decoration that a one-liner gets a bit cumbersome. Instead, create a simple script to add this decoration; then we can call it from the udev rule.

Create the file wherever you like, just note the full path since it will be needed later:

~/.bin/fix-caps

#!/bin/bash
(
  sleep 1
  DISPLAY=:0.0 setxkbmap -option ctrl:nocaps
) &

And make it executable:

$ chmod +x ~/.bin/fix-caps

Important things to note:

  1. We sleep 1 in order to give time for udev to finish initializing the keyboard before we attempt to tweak things.
  2. We set the DISPLAY environment variable since the context in which the udev rule will trigger has no knowledge of X (also, the :0.0 value is an assumption, you may need to tweak it).
  3. We background the whole command with & so that the script returns control back to udev immediately while we (wait a second and) do our thing in the background.

Rule

Now that we have a single callable script, we just need to run it (as our normal user) when a particular event occurs.

/etc/udev/rules.d/99-usb-keyboards.rule

SUBSYSTEM=="input", ACTION=="add", RUN+="/bin/su patrick -c /home/patrick/.bin/fix-caps"

Be sure to change the places I’m using my username (patrick) to yours. I had considered putting the su in the script itself, but eventually decided I might use it outside of udev when I’m already a normal user. The additional line-noise in the udev rule is the better trade-off to me.

And again, a few things to note:

  1. I don’t get any more specific than the subsystem and action. I don’t care that this runs more often then actually needed.
  2. We need to use the full path to su, since udev has no $PATH.

Testing

There’s no need to reload anything (that happens automatically). To execute a dry run via udevadm test, you’ll need the path to an input device. This can be copied out of dmesg from when one was connected or you could take an educated guess.

Once that’s known, execute:

# udevadm test --action=add /dev/path/to/whatever/input0
...
...
run: '/bin/su patrick -c /home/patrick/.bin/fix-caps'
...

As long as you see the run bit towards the bottom, you should be all set. At this point, you could unplug and re-plug your keyboard, or tell udev to re-process events for currently plugged in devices:

# udevadm trigger

This command doesn’t need a device path (though I think you can give it one); without it, it triggers events for all devices.

published 2 weeks ago, tagged with arch, linux, udev

Aurget v4

Aurget was one of the first programs I ever wrote. It’s seen decent adoption as far as AUR helpers go and it’s gradually increased its feature set over the past number of years.

The codebase had gotten a bit krufty and hard to follow. I decided to refactor to more isolated functions which didn’t rely on so many global variables. This directed refactor has improved things greatly: pretty much any function can be reasoned about in isolation and the logic flows more understandably during program execution.

Unintentionally, this push to simplify and clarify actually resulted in a number of user-facing and developer-facing improvements. Go figure.

Listen – I get it. I’m a minimalist too. Why do we need 400 lines to do essentially this?

Funny thing is, no matter hard I tried to chip aurget down closer to those essential curl | tar | makepkg parts, I would inevitably end up with sprawling, spaghetti code after the very first feature beyond what the above script provides. Available upgrades? Bloat. Dependency resolution? Bloat.

So after trying and giving up a number of times, I’ve decided aurget is actually a fairly simple and straight forward implementation of the features it currently provides, despite being so big.

In my opinion, it can’t get much simpler without dropping features, and I actually like the features. Oh well, back to the post…

Stupid Networking

In so many places, aurget would hit the RPC in a per-package way. Refactoring the networking made it obvious when I could use the multiinfo endpoint to query for many packages at once. This made many actions way faster.

Speaking of networking, it’s now consolidated into a single get function. This means I can more easily play with curl options, error handling or even caching.

Pass the Buck

Package installation is now handled by simply passing --install to makepkg. This has a number of positive consequences: Goodbye sudo, and so long to any configuration around the pacman command. Split packages are also handled predictably and you’ll never have a successful build error with “package not found”.

Moar Options

Aurget will now pass any unknown options directly to makepkg (with a warning). This means anything makepkg supports, aurget supports too.

  • Run as root
  • Install a subset of a split package
  • Package signing

Etc…

Zomg DEBUG

One of the most frustrating aspects of working with aurget as its maintainer was troubleshooting. It was always both difficult and annoying to figure out what aurget was doing.

With the code now refactored such that the runtime behavior was more linear and understandable, a useful --debug flag could also be added.

I love this so much:

ossvol screenshot

Bring on the bugs!

Seriously though, there may be some. I changed a whole lot and didn’t test exhaustively… Enjoy!

published 4 weeks ago, tagged with bash, arch, aur

Chromebook

I’ve heard rumors that a Google Chromebook can make a surprisingly sweet machine for a developer. As someone that works exclusively in the console, it’s easy enough to SSH into a server to do the actual work. Since my apps are either command line tools or web sites, I can easily test them remotely as well. I only need something with a terminal and browser… And reliable internet.

This workflow is very attractive to me: you get a conveniently portable device with great battery life on which to work, it’s cheap and essentially disposable should anything happen to it, and the machine where you actually develop can be specialized to the task. I already have such a machine available, but you could also get a fairly affordable linode or even spin up an EC2 instance.

Right out of the box, things work quite well. The Secure Shell browser extension can give you an xterm-compliant terminal directly in a browser tab. You could effectively be writing web pages in a web page. Crazy.

I decided to go a bit further and enable what’s called “Developer mode” this gives you a real bash shell and a real ssh command. I found the actual terminal to be a bit stabler, especially port forwarding.

Enabling Developer Mode

On older versions this is a physical toggle, but in the version I have it’s a software switch:

This process is effectively a factory reset. Though, if you have data on there you’re worried about, you’re Doing It Wrong.
  1. Hold Escape and Refresh, then press Power
  2. At the blank screen, press Ctrl-D
  3. Follow the prompts and enter into “Unverified” mode

The machine will eventually reboot and run some process before presenting you again with the initial setup screen.

You’re going to see a warning each time the machine boots about being in this mode. I was hoping to only see it the first boot after enabling it, but that doesn’t seem to be the case. The warning times out after 30 seconds or you can press Ctrl-D to dismiss it immediately. Note that you need to use the real Ctrl key for this. For example, I’ve mapped the Search key to Ctrl, but it’s not recognized as such for this functionality.

Getting Shell

The quasi-terminal is accessed by pressing Alt-Ctrl-t. From here, type shell to start a bash shell. This is an environment any linux user should be used to, with only a few surprises.

Be sure to install the Crosh Window browser extension. It allows you to pull the browser-tab terminal out into its own window. Without it, many important key bindings will be swallowed by the browser.

The shell opens in / but you do have a proper ~/ at /home/chronos/user. Let’s cd there and setup a few niceties.

The bundled vim is built with only the “tiny” featureset and is not very fun to use. I might even go so far as to recommend catting the content into these files.

First, setup an ~/.ssh/config:

Host example.com # your dev box in the cloud
  User username  # so you don't need user@example.com
  SendEnv TERM   # we'll get to this in a second

The actual TERM is reported as linux and that leads to a pretty bad experience on the remote machine. We’ll set a custom one and send it via SendEnv. We don’t want to just export it, or the actual chrome shell acts funny, we’ll just set it on the commandline when invoking ssh.

That leads me to ~/.bashrc where we define a connect function for getting into our dev box:

# add to the bottom of the file:
connect() {
  TERM=xterm-256color ssh -L 3000:localhost:3000 example.com
}

We set that custom TERM variable and use the -L option to forward port 3000. This means that when I start up the web application I’m developing on “in the cloud”, I can access it from the chromebook’s browser at http://localhost:3000/.

SSH Keys

I don’t allow just password access to my machine(s), and prefer to use RSA keys pairs. Setting this up for the Chromebook was also super easy:

  1. Generate a key pair, etc
  2. Upload the private key to Google Drive
  3. Move it from Drive to Downloads on the Chromebook
  4. Move it from ~/Downloads to ~/.ssh/id_rsa in the shell

I typically name my keys meaningfully since I use quite a few of them for various hosts. If you do the same, just add an IdentityFile clause to your ssh config.

Conclusion

I’m very happy with this setup. The Chromebook is literally filling the exact same role previously held by a Macbook Air, but for a fraction of the price and with better battery life. This terminal is certainly better than Terminal.app and might even be better than iTerm2.

chromebook shell
chromebook htop

In short, do eeeeet.

published on Apr 13, tagged with cloud, development

Chruby

Once I start my new job at thoughtbot, I’ll be working on a variety of ruby and rails projects at the same time. This, combined with the current 2.0 transition, means I once again need a ruby version management tool.

Chruby is the third (by my count) “new hotness” when it comes to these python-inspired virtualenv clones. First there was rvm which has a ton of features, then came rbenv which aimed to be simpler, finally we have chruby which is billed as the simplest of them all. So far, I’m a big fan.

For detailed instructions and usage please see the README files in the previously linked project pages. This post might gloss over some details and focuses more on my opinion of the tools than their usage. For Arch users, there are AUR PKGBUILDs for all of these.

Choices

Last time I required this feature, rbenv was just coming onto the scene, so I went with rvm. It is by far the most complex of these tools, and that is a downside itself. Overwriting cd (to allow auto-switching) is a concern for some people. The fact that it both installs and manages versions strikes others as a breach of Unix.

One feature commonly touted as the reason to use rvm is its gemsets which isolate sets of gems into groups and thus prevent gem-hell. Now that bundler is ubiquitous, this problem no longer exists.

Aside from rvm, the other major choices are rbenv and chruby. Looking at the rbenv project page, it still seems to do a number of things I don’t need or want. I’m also not a fan of it introducing a bunch of shims.

At its core, all such a manager needs to do is modify some environment variables so that the correct binary and set of libraries are loaded. Coincidentally, that’s about all chruby does.

Chruby

Paraphrasing from the project page, changing rubies via chruby will:

  1. Update $PATH so the correct ruby and any gem executables are directly available.
  2. Set a proper $GEM_HOME and $GEM_PATH so any gem related commands and tools (including bundler) will Just Work.
  3. Set some other ruby-related environment variables.
  4. Call hash -r for you (required when mucking with $PATH).

No shims, no crazy options or features bloating up the script which itself weighs in at less than 90 lines of very simple and readable shell.

If you choose, chruby can also do automatic switching. To opt in, you just have to source an additional (and equally simple) script. Once enabled, you will automatically change rubies when you enter a directory containing a .ruby-version file. This is done cleanly via a pre-prompt command and not by hijacking cd.

When auto-switching is enabled, be sure to define a “default” by dropping a .ruby-version in $HOME too.

Here are the entries in my ~/.zshenv (the same should work in bash):

if [[ -e /usr/share/chruby ]]; then
  source /usr/share/chruby/chruby.sh
  source /usr/share/chruby/auto.sh
  chruby $(cat ~/.ruby-version)
fi
The AUR PKGBUILD installs into /usr/share while the chruby README prescribes /usr/local/share. This may be a packaging bug that will eventually be fixed so be sure to verify and use the appropriate paths for your install.

So far, I’m a huge fan. The tool does what it advertises exactly and simply. The small feature-set is also exactly and only the features I need. As a bonus, setting the GEM_ variables is something I always seemed to need to do manually anyway, so it’s nice to no longer need that.

Ruby-build

Since chruby is just a “changer” you do need to install rubies via some other tool. Ruby-build makes that super easy:

$ ruby-build 1.9.3-p392 ~/.rubies/ruby-1.9.3-p392
$ ruby-build 2.0.0-p0 ~/.rubies/ruby-2.0.0-p0
Chruby will look for rubies installed in one of two places by default: /opt/rubies/ or ~/.rubies/. I prefer the latter.

Since ruby-build is actually a sub-tool of rbenv, it’s quite spartan. You’re required to type the desired version exactly (as read from ruby-build --definitions) and you need to give the full installation path, even though it could be determined easily by convention. rbenv install owns those niceties, apparently.

One last bit…

Some time ago, while still using both oh-my-zsh and rvm, I noticed that most of the prompts used yet-another rvm feature to read the currently active ruby and insert it into the prompt.

This seems a bit odd for a tool to provide this feature. There are also a great many if statements out there doing something different for rvm or rbenv. Will they all add a clause for chruby now?

Well, in a bout of insane cleverness, I found the following non-obvious way to get the currently active ruby version:

$ ruby --version

If you’d like to use this in your prompt, feel free to bogart from mine.

published on Apr 7, tagged with ruby

Hard Mode

Recently, while watching Corey Haines and Aaron Patterson pair-program, I heard Mr. Haines mention vim’s “hard mode”. Apparently, this is when you disable the motion commands h, j, k, and l.

It’s absurd how great this exercise is for increasing your knowledge of vim. There are so many better ways to do everything. Just like complete novices might map the arrow keys to Nop to force learning hjkl, mapping the hjkl keys to Nop forces you to learn all these other ways to move around and edit parts of the file.

The real philosophical shift is thinking in Text Objects rather than Lines and Characters. Words are things, sentences are things, method definitions are things, and these can all be manipulated or navigated through as such.

While you probably can’t fully internalize this concept without going through the exercise yourself, I would like to share a few of the very first “better ways” I’ve been finding while restricted in this way.

Imagine my cursor is a ways down the document, and I need to change the above header in some way. I’m staring at “Search”, I know I want my cursor there. I used to just tap k or maybe a few 10ks with a j or two. What was I thinking?

?Se

And I’m there. In this case, the capital “S” made this word rare enough that I didn’t have to type very much of it. Recognizing the relative frequency of words or characters can be a useful skill for quicker navigation. Drew Neil, author of practical vim, calls this “Thinking like a scrabble player”.

Use the Ex, Luke

Another thing I didn’t realize I do a lot is move to some far away line to copy it, only to come right back to paste it. Really? I’m going to type a bunch of js only to then type the exact same number of ks?

You could use search to get to the far away line then double-backtick to jump back, or you could do this:

:2,7co .

This takes lines 2 to 7 and copies them to here. Not only is this less key-strokes (a number which grows proportional to the distance between here and there), but I’d argue it also keeps your focus better.

You can actually cut out a lot of unnecessary motion using commands like this:

:20   " go to line 20
:20d  " delete line 20
:2,7d " delete lines 2 through 7

In any of these commands . can be used to mean the current line. If you really get frustrated, you could use :.+1 and :.-1 to move like j and k – but I wouldn’t recommend it.

Finding Character

It’s times like these that I try to find a good first concept. Something that’s going to be useful enough to get me further along the habit-building path, but simple enough that I don’t have to remember too much.

First, know that 0 puts you at the start of the line. This gives you a common reference to move from so you only have to think in one direction (for now). Second, know that f and t go to a letter (so fa to go to the next “a” in the line). The difference is t goes till the character, stopping with the cursor just before it and f puts the cursor right on top. You can then use ; to repeat the last search, moving a-by-a along the line.

Once you’ve gotten the hang of this, the capital versions, F and T do the same thing but backwards. , is the key to repeat the last backwards search, but so many people (including me) map that to Leader or LocalLeader that it’s difficult to rely on. I haven’t found a good solution to this, since the only other convention I know of is the default \ which I can rarely type consistently.

There’s a bit of stategy here. It’s true of most motions, but it’s most recognizable with f. You have two choices in approach: pick the letter that you want to be at (no matter what letter it is) and use ; to repeat the last f or t until it gets you there (regardless of how many key strokes that is), or you can choose a letter that appears first in the line (knowing that it will only take one stroke to get there) but which only gets you near your goal. These are the two extremes, finding the best middle ground (lowest overall keystrokes) for any given scenario is something worth mastering.

Word-wise

In addition to finding by character we can start to think in words. Again, we’re making it easy by always starting from 0. Given that, just use w to move word by word with the cursor on the front of each word or e to move word by word but with the cursor on the end of each word. Eventually, I’ll attempt to internalize the same commands in the other direction: b and ge.

All of these have capital versions (W, B, E, gE) which have the same behavior but work on WORDS not words.

The exact rules about words vs WORDs aren’t worth memorizing. WORDs are basically just a higher level of abstraction. For example, <foo-bar> is 5 words but it’s only one WORD.

Conclusion

So far, I’ve gotten myself to consistently use a number of new vim tricks:

  1. Use search to get where you want
  2. Use Ex commands to manipulate text not near the cursor
  3. Move by word, not by character

There’s still plenty to learn, but I’ve found that just these few simple ideas make me effective enough that I’m sticking with it and not just giving up in frustration.

published on Mar 16, tagged with vim, linux