March 25, 2023·4 min read·engineeringfishabbreviationshistory

fish 3.6.1 completes the abbreviation storage transition

fish 3.6.1 removes old universal abbreviation definitions when erased and warns about obsolete persistence options. History-search fixes repair the other major interactive change from 3.6.

Removing a migrated setting from memory is insufficient if an older persistent representation can restore it later. fish's abbreviation redesign moved new definitions out of universal variables, while importing existing definitions for compatibility. fish 3.6.1, released on March 25, repairs the erasure path so it also removes the universal variables used by the earlier abbreviation function.

The release also warns when a definition still asks for the now-ineffective universal-storage option. These changes address different sides of the transition. Erasure needs to remove the old stored definition, and creation needs to stop implying that an obsolete option will preserve a new definition. Both matter when configuration spans several fish versions.

I like fish's abbreviations because the expanded command remains visible before execution. Their convenience depends on predictable configuration as well as predictable editing. A shortcut that reappears after deletion, or disappears because an ignored option did not save it, makes that configuration harder to understand.

The new engine still has to remove old definitions

The 3.6 release notes explain the persistence change. Abbreviations are no longer stored in universal variables, and new definitions should be added to config.fish. Existing universal abbreviations remain importable, which avoids making an upgrade discard users' established shortcuts.

Compatibility on load creates a corresponding obligation on delete. The 3.6.1 implementation removes the abbreviation from the current set, then computes the legacy universal-variable name and removes it from universal scope. The old variable name uses an escaped version of the abbreviation name with the historical _fish_abbr_ prefix.

That second removal prevents a persistent legacy definition from surviving the command that erased its imported form. The implementation also treats successful removal of the old variable as success. An operation intended to clean up the previous representation does not need an active modern definition to establish that it removed something.

The important user-visible property is consistency across startup. Importing an old definition preserves it for continued use, while erasing the abbreviation should remove the stored source of that imported definition. A migration that only implements the first direction leaves users with an incomplete model of what the erase command means.

Names must compose with the erase command

The version-pinned 3.6.1 notes also state that abbr --list no longer escapes abbreviation names. This makes the output usable as input to abbr --erase. The implementation prints each name followed by a newline instead of transforming it into a shell-escaped representation.

This matters for the documented command that removes all listed abbreviations. It is a destructive cleanup command, not a prerequisite for upgrading or preserving existing shortcuts.

abbr --erase (abbr --list)

The command substitution passes the listed names to the erase operation. For that composition to work, the names must describe the actual abbreviation keys. Display-oriented escaping would make the receiving operation search for a different name when escape characters become part of its argument.

For ordinary maintenance, abbr --show remains the operation that displays definitions in an importable form. Listing names for another command and printing executable definitions are different output contracts. The redesign gives abbreviations more properties than a name and literal replacement, making that distinction useful beyond this particular cleanup command.

An ignored option now produces a warning

The --universal warning patch keeps accepting the obsolete option but reports that it was removed and is ignored. That preserves recognition of older calls while making their changed effect visible. The option no longer promises persistence simply because the command accepts its spelling.

A configuration file can instead establish an abbreviation during startup with an ordinary declaration. This definition uses the supported command and can be placed in config.fish.

abbr --add gco git checkout

The web abbreviation editor is removed in the same release because it was not functional with the 3.6 redesign. Leaving an editor visible would suggest that it can manage the active system. Removing that control makes the supported configuration path clearer while the command-line definitions provide the full abbreviation behavior.

History search restores the interrupted edit

Version 3.6 introduced the searchable Control-R history pager. This patch gives it more screen space, usually half the screen, and makes Control-G close it. Escape during history search once again restores the original command line, correcting a regression from 3.6.0. A separate fix prevents crashes during case-insensitive searches involving non-ASCII codepoints.

Restoring the original line is particularly useful when history search begins in the middle of constructing a command. Abandoning the search should permit that edit to continue. The search results and the preexisting command line are separate pieces of editor state, and cancellation needs to preserve the latter.

I regard these cancellation and persistence details as part of a shell's everyday usability. They determine whether an interactive action can be reversed without reconstructing earlier work. In 3.6.1, the abbreviation erase operation reaches the legacy stored definition, while history-search cancellation restores the command line that existed before the search.