Tuesday, May 17

cheap shared persistent directory history in zsh

These could probably go in your .zshrc.

First, a function:

# record directory history
function chpwd {
  echo $(pwd) >> ~/.directory_history

The function gets fired every time you change directories, apparently by virtue of being called chpwd. It looks like zsh has a whole set of special functions which fire under various circumstances. It’s weird that these are just kind of out there in the namespace, but ok, they seem useful.

All it does is append the output of pwd, which some googling suggests stands for either “print working directory” or “present working directory” (this one says “print” for sure, but I’m not sure how that maps to $PWD as the environment variable for the working directory, or chpwd, which seems more likely to stand for “change present working directory” than “change print working directory”), to a .directory_history flatfile.

Second, an alias:

alias h='cd $(tail -50 ~/.directory_history | tac | dmenu_unique)'

This alias cds to the result of a subshell which grabs the last 50 directories off of the end of the list file, reverses them, and feeds them to dmenu_unique, which is this script:

#!/usr/bin/env sh
awk '!x[$0]++' < /dev/stdin | dmenu -l 15 -fn '-xos4-terminus-medium-r-*-*-32*'

Unsurprisingly, I found the awk portion of this on Stack Overflow. It’s more or less just a version of a thing I’ve done in Perl or PHP a hundred times, where you loop through input, incrementing a counter in a hash for every unique line / string. I think it passes the line through if… If, uh, it’s not already set in the hash when it hits? Yeah, that’s got to pretty much be it. I sometimes regret not learning awk sooner in life.

(Side note: I am pretty sure that running /bin/sh by way of env here is fundamentally pointless for several reasons. Correspondence to the effect that I am or am not an idiot re: this point is welcome.)

dmenu is a minimalist type-to-complete menu program for X with a couple of options, which I know from its use as part of a standard xmonad configuration. Basically, it lets you pick from a from a list of things. In this case, it looks something like:

an animation of the h alias in action

Normally, dmenu’s list display is oriented horizontally. That’s overridden by -l 15, which shows 15 lines of input vertically. The -fn ... bit tells it to use a larger font than usual. (Specifying fonts is one of those domains where X rapidly becomes horrible and inscrutable.)

It seems like this pretty much has to be in an alias, because you can’t really change the parent shell’s directory from within a child process.

Third, a rationale:

My mind is of course slowly disintegrating and I have too many terminal windows open at any one time. I lose track of things easily in the seedy, rusty-razor-edged morass of my desktop environment. Often I find myself closing a terminal in some deeply-nested or esoterically named directory, and then immediately needing to open it again. In other cases, I open a new terminal and need to quickly center it on files I already have open.

I can definitely imagine more elegant solutions to this problem, but in practice, indexing into a shared log of the places all terminals visit catches a lot of the use cases.

I spend so much of my time trying to kill accidental statefulness that I sometimes forget how useful stashing a little state can be.

This isn’t a very coherent writeup, but it’s late and I’ve had some wine.

Saturday, May 14

Adjusting default size of stuff in Mozilla Firefox, for big high-DPI monitors:

  1. Enter about:config in URL bar
  2. Search for layout.pixels.devPixelsPerPx
  3. Enter some value greater than 1.0 to make things big, and smaller than that to make them small.

On my current version, this last required double-clicking and entering the value in an alertbox.

Wednesday, May 4

Back in Colorado, the lawn needs mown and the sink is full of dishes. Last Tuesday morning’s old-computer build is still half-assembled on the kitchen floor and the kitchen counters and probably several other places.

There are a bunch of things I should be doing (like the dishes), but I was just dorking around with some pointless shell script instead.

It got me thinking about how it’s too hard to write little shell utilities. Two categories of reason for this:

First, the existing shells are bad as general-purpose programming languages.

  • The simple things you want from a language are either missing or really hard to get.
  • The syntax is hideous and everything is riddled with edge cases which will bite you or your users.
  • Patterns exist to help with some of this, and conscientious authors will be aware of them, but they are inconsistently applied, made of illegible boilerplate, and often a matter of unevenly-distributed folklore.
  • I’ve evidently been harping on this one for a while.

Second, general-purpose language environments are bad at the stuff I want when I write shell utilities.

  • Argument handling is miserable and full of boilerplate.
  • Doing things to files and directories is way harder than it should be.
  • The “correct” abstraction around a given task is often much harder to use than the corresponding shell utility would be.
  • The best available library often introduces a new (and sometimes unstable) dependency.
  • Reusing other parts of the shell environment is often fraught with hazard, or at least silliness.

I don’t want to claim these plaints are universals, exactly.

There are glue-language features in Perl which keep me coming back for little one-offs that wind up in my ~/bin/. I wrote a thing in Python the other day using docopt to handle arguments, and hey, really, not too shabby. Despite its problems, there are encouraging things about some of the patterns I see used in Node.js.

I would, however, still like to see an improved toolset for the conceptual space of “little things you use at the command line”.

I learned the other day that you can do this:

brennen@exuberance 21:45:01 /home/brennen ★ cal -3
       April                  May                   June
Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa  Su Mo Tu We Th Fr Sa
                1  2   1  2  3  4  5  6  7            1  2  3  4
 3  4  5  6  7  8  9   8  9 10 11 12 13 14   5  6  7  8  9 10 11
10 11 12 13 14 15 16  15 16 17 18 19 20 21  12 13 14 15 16 17 18
17 18 19 20 21 22 23  22 23 24 25 26 27 28  19 20 21 22 23 24 25
24 25 26 27 28 29 30  29 30 31              26 27 28 29 30

…which will show the months before and after the current one.

I don’t know how I made it this long without knowing about that option. There’s a generalized approach, too, with -B n and/or -A n for n months before and after the current month.

monday, may 2

there's a picture on the wall of kurt cobain
playing in this bar in like 1990
a good deal has happened since then
this bar doesn't even look like it did in 2004
or whenever it was i last lived in this town

hell in fact it seems like half this town looks
like a different place, on the level
of storefronts and tall buildings
they keep on building the same shit-tier
architecture, the built-environment equivalent
of flat-pack furniture, that accretes now on
every city in america with any surface
half-exposed to the money

(corrugated steel, beige and rust red, ugly glass,
carpet like the aisles of airplanes, nonfunctional
elements and facades at strange angles, rectangular cutouts
in things, the general heft and quality of a plastic vacuum cleaner
bought for $29.99 at target in 2012)

but then the streets are still wide
and the wind is still the nebraska wind
the music in here is still fuzzy and
thick with a certain kind of noise
in the grain of it, the beer is still cheap enough

and the college kids and the thin layer of
the hip, the downtown bar trade and
disaffected labor, the state government
functionaries—they're the same people,
the small town kids and the townies and
the oddball imports,
even if they aren't the same people exactly
i don't know these faces but i know these
faces pretty well

and do i miss it here?
like hell sometimes, if i'm honest
the row crops out there and the vast stupid
sky overhead, the desolation and the irrigation and
the nearness of all the mistakes that own the
configuration of the plains, the grass, the
fencelines and the cottonwoods and the
way the hills south of here roll through kansas,
ancient and riddled with fossils of forests and
seas unimaginable, the little rivers thick
with silt and the fucked-up reservoir projects
drowning the old farmhouses built themselves
on a legacy of thievery and slaughter,
and then too on broken sod and
endless work in the sun and dreaming freedom
like clean water, like some kind of transfiguration—