fish 4.4 adds counted Vi editing through operator mode
fish 4.4 adds counts for Vi movement and deletion and revises word motions. Its operator mode explains how a sequence such as d3w becomes a composed edit.
The fish issue linked to counted Vi editing began with a short report in July 2015. A count before substitution behaved as if the count were always one. Issue 2192 is now associated with fish 4.4, whose February 3 release adds counts for movement and deletion. The interesting change is the operator mode that makes multi-key editing sequences possible.
The release notes use d3w and 3l as examples. A number can qualify an editing operation instead of being ignored as a separate keystroke. The same release brings Vi word motions closer to Vim, with an explicit exception for underscores. Counts and word boundaries work together because repeating the wrong movement would still produce an unexpected edit.
Fish won me over as a personal shell after years with Bash and Zsh. Its appeal is the quality of everyday interaction without extensive configuration. Supporting familiar editor operations fits that preference, even though my affection for fish does not depend on claiming that its command-line editor implements all of Vim.
An operator waits for its motion
The 4.4.0 binding implementation shows how the sequence works. A helper accumulates typed digits into a count. Starting an operator stores the operator and the current count, then changes fish_bind_mode to operator. The following input can supply the motion and another count before the edit executes.
The motion executor consumes the count saved before the operator and the count entered afterwards. It multiplies them to obtain the total. If a count is empty, the count helper supplies one. This means that an omitted count preserves the ordinary single-motion operation while explicit counts can compose with the operator.
The implementation also clears a count after consuming it. That detail prevents a completed operation from accidentally changing the next command. Cancellation clears the stored operator and count values, returns to the default mode, and repaints the mode indicator. Pending editing state therefore has both an execution path and a cancellation path.
A counted edit requires more than binding a digit to repetition. The shell has to remember which operation is pending, distinguish its count from the motion's count, and decide when to return to normal command interpretation. The new mode gives those decisions an explicit place in the binding system.
Deletion and change share motion handling
The motion executor handles deletion, change, and yank with common motion logic. Depending on the operation, it uses a selection or a grouped edit. Change operations switch into insert mode after modifying the text. That reflects the difference between deleting a span and preparing to replace that span with newly typed text.
Word-forward motions receive special treatment. For deletion and related operations, the implementation can substitute a corresponding kill operation for the movement. This avoids assuming that every motion should be implemented by creating a selection and then deleting it. The binding layer chooses an operation that matches the intended editing semantics.
Line-wise operations have a separate path. They repeat whole-line or inner-line editing functions according to the total count. The source also contains branches with more limited support, so the release should not be read as a claim that every editor command now accepts every count. Its documented promise concerns counted movement and deletion through the new mode.
These details explain why Vi compatibility is a collection of behaviors. A shell can recognize the letters of a command and still differ in the region it changes, the mode it enters afterwards, or how undo groups the edit. The implementation has to preserve those relationships for a composed operation to be useful at the prompt.
The distinction between a selection and an undo group is visible in the source. Some motions begin a selection and finish by ending it. Others begin an undo group and close that group after the repeated operation. That keeps the implementation of a counted command tied to its editing behavior, instead of treating it as unrelated key presses that happen to repeat.
A word is an editing decision
Fish 4.4 changes w, W, e, and E to behave largely like their Vim counterparts. The release notes explicitly retain underscores as word separators. That exception matters for command lines containing identifiers and paths with underscores. A familiar movement key does not imply identical boundaries for every string.
The release adds named input functions for Vi word movement and deletion, including separate big-word operations and inner-word handling. Distinct functions let the binding layer express those choices without making every key sequence implement its own text scan. They also give custom bindings a defined editing operation to invoke.
The versioned interactive documentation describes how to enable Vi bindings:
fish_vi_key_bindings
That starts with insert mode active, and Escape enters command mode. The documentation also makes the boundary clear. Fish includes many popular editor shortcuts, but its bindings are not a complete editor implementation. The command line can still be opened in an external editor when the task needs that editor's full behavior.
I prefer that explicit boundary. Better compatibility for common command-line edits reduces the amount of shell-specific behavior a user must remember. Keeping the documented exceptions visible is more useful than describing the result as complete Vim compatibility.
Binding inspection now includes every mode
Fish 4.4 also changes bind so that omitting --mode lists mappings from all modes. That becomes more useful when an editing operation crosses mode boundaries. Looking only at the normal command-mode mapping would not explain what happens after an operator starts waiting for a motion.
Mode-specific customization remains a different concern from the shell's scripting syntax. Adding Vi counts changes the interpretation of interactive editing keys. It does not make fish a POSIX-compatible shell or let an existing Bash script run unchanged. For someone choosing fish for its interactive behavior, the improvement is a more consistent way to edit the command before execution.