January 1, 2024·5 min read·engineeringfishhistorycompletionterminals

fish 3.7 makes remembered commands easier to recover

fish 3.7 adds subsequence fallback to its history pager and preserves more context while searching. Completion changes reduce redundant filesystem work and clarify which files suggestions may include.

Remembering the structure of a command is often easier than remembering its exact text. A long Git invocation may remain recognizable by the command name and part of a branch name, even when everything between them has been forgotten. fish 3.7 improves its history pager for that case by trying subsequence matches when its ordinary search finds no result.

The 3.7.0 release notes, dated 1 January, describe history and completion improvements. The changelog at the release tag is the fixed historical reference for this version. It also explicitly states that the ongoing Rust port is absent from this release and that the 3.7 series remains C++.

I like the emphasis on making ordinary terminal interaction useful without extensive configuration. History recovery is a good example because the shell already has the information. The design problem is how to let a person find it with the incomplete recollection they actually have.

The pager preserves the contiguous search first

The history search patch in pull request 9476 adds a search mode for subsequences. A substring requires adjacent characters. A subsequence preserves their order while allowing other characters between them. The change therefore permits a shorter recollection to identify a longer command.

The patch first attempts the existing contains search. If it finds no match, it starts a subsequence search with the same search string and history position. This is more specific than describing the pager as an unrestricted fuzzy-search interface. The implementation preserves the ordinary matching attempt before falling back to the broader relationship.

The release notes illustrate the difference with a Git log command whose revision argument contains an integration branch name. Searching for the command name followed by a fragment of that branch can succeed even though those pieces are separated in the stored command. The user does not need to type every intervening flag or revision character.

This fallback has a practical consequence for ambiguity. A contiguous remembered fragment can still select commands through the original search. Broader matching helps when that attempt fails, but a very short subsequence can describe many unrelated lines. The pager provides the place to inspect those candidates before placing one on the command line.

Nothing about this feature changes the syntax of the command ultimately executed. Search text is a query over recorded command lines. The recovered command remains available for inspection and editing, which is necessary when an old invocation contains arguments that should not be reused unchanged.

Search transitions retain the current work

The release also improves movement between history interfaces. Opening the pager while already searching now initializes its search field with the existing query. An incremental search can become a full pager search without requiring the user to reconstruct the text just entered.

That continuity matters because a person may discover only after starting a search that several similar commands exist. The initial interface was enough to begin, but the larger result view becomes useful for comparing candidates. Retaining the query lets the change of view preserve the same task.

When Enter closes the history pager with no match, fish now copies the search text to the command line. That text may already be the beginning of a useful command, even though it did not identify a historical one. Keeping it available for editing avoids discarding work merely because the search failed.

The release includes a dedicated history-pager deletion function, bound by default to Shift and Delete. Deletion belongs to the same retrieval experience because a stale or unwanted entry can repeatedly appear among useful candidates. The changelog separately notes persistence fixes for exact history deletion, distinguishing removal from the current display from saving the deletion.

I consider these transitions as relevant as the new matching rule. A history interface should retain useful input as the person changes approach. fish 3.7 handles the search query as work already performed, even when it produces no matching command.

Completion should not repeat filesystem checks

The tagged changelog also records completion and globbing performance improvements, particularly on slow filesystems such as NFS where the operating system supports the relevant optimizations. One concrete change appears in pull request 9931, which removes a repeated executability check while generating completion descriptions.

The completion path had already checked access when selecting executable candidates. The description function could then check access again to decide whether to label the file executable. Its correction passes the already established fact into the description operation, allowing it to skip that second check.

This is a useful performance mechanism to identify because it does not depend on a new cache lifetime or a guess about permissions. The caller has just established the property needed by the description. Reusing that result removes duplicate work inside one completion operation.

The source comments also explain why a general executability check cannot rely only on mode bits. Group and other permission arrangements make actual access more complicated. The optimization preserves the access check where it is needed, then avoids repeating it when the caller already knows the answer.

Another visible completion change concerns leading periods. Command-specific completion functions may now offer results beginning with a period, including files suggested for Git operations. Default file completion still hides those names unless the token itself begins with a period. The distinction allows command knowledge to affect suggestions without globally exposing every hidden file.

Key sequences have a bounded wait

fish 3.7 introduces fish_sequence_key_delay_ms for multi-key sequences. The changelog describes the prior behavior as waiting indefinitely for completion of such a sequence. A configured timeout permits bindings such as a two-character vi-mode escape sequence without leaving an unfinished prefix unresolved indefinitely.

This setting concerns a sequence of keys, so its usefulness depends on how a binding interprets ordinary typed characters. A timeout lets the shell decide when the expected continuation has not arrived. It gives a custom multi-key binding a defined waiting policy instead of requiring the user to complete it eventually.

The release improves these interactive behaviors within the existing C++ implementation. The Rust port remains separate work as of this date. fish 3.7's practical changes are available now in history matching, query continuity and completion processing, including a reduction in repeated access checks when describing executable candidates.