In bash, you can use M-f and M-b to move the cursor one word forward and backwards, but is there a way to move one argument forward or backwards? If not out of the box, perhaps by some configuration?
In other words, I would like to cursor to go navigate between the marked positions below.
cp "foo bar.txt" "/tmp/directory with space"
^ ^ ^
| | |
Best Answer
I know you are using bash, and I am not confident that what you ask is possible in bash. What I will show you is how to implement the requested feature in ZSH. (ZSH is a bit like an improved bash - if you switch then you should still remain proficient).
In ZSH there is the ZSH Line Editor (zle for short). This provides all of the movement keys as bindable commands, much like bash. Where it goes further is the ability to define custom commands. A custom command is any shell function that has been turned into a widget.
These functions can execute other commands, and they also get access to several variables that are of interest for your problem. The ones I will talk about are:
There are also others available, like:
Now it happens that ZSH is not only capable of providing custom keybinds, it also has a far more comprehensive set of operations that you can perform on variables. One of the ones that is interesting for this problem is:
You can assign the expanded $BUFFER directly to a variable, like so:
(line is now an array, but annoyingly this array starts at index 1, unlike bash!)
This will not perform any expansion of globbing characters, so it will return an array of the actual arguments in your current line. Once you have this, you are then interested in the position of the start point of each word in the buffer. Unfortunately you may well have multiple spaces between any two words, as well as repeated words. The best thing I can think of at this point is to remove each word being considered from the current buffer as you consider it. Something like:
We are almost there now! What is needed is a way to see which word is the last word before the cursor, and which word is the beginning of the next word after the cursor.
So far I have shown how you might derive the appropriate index for the cursor to move to. But I have not shown you how to move the cursor, or how to bind these functions to keys.
The $CURSOR variable is able to be updated, and if you do so then you can move the current insert point. Pretty easy!
Binding functions to keys involves an intermediate step of binding to a widget first:
You can then bind the widget to a key. You will probably have to look up the specific key identifiers but I usually just bind to Ctrl-LETTER, which is easy enough:
Lets put all of this together and fix your problem:
As far as my own testing goes, this seems to do the job. You will probably want to change the keys that it binds to. For reference, I tested it with the line:
and it navigated between the carets. It does not wrap.