3

I have a common situation in the shell when a command is attempted

command "/some/complex/and terrible/path" -vf --various --flags --and -- things --config-file="/some other/annoyingly/large/path/to/somewhere"

and it turns out that I'm mostly there but need to move some stuff around. Suppose I have to move the last argument all the way to the front to attempt this next.

command --config-file="/some other/annoyingly/large/path/to/somewhere" "/some/complex/and terrible/path" -vf --various --flags --and -- things

Trying to take a keystroke golf look at this, it's a dire situation. This is actually a nightmare shell command entry scenario where you kind of have to re-type (or copy&paste) almost half the command. The best hope of sanity might be to use an external editor [like this].

Even still, Vim isn't smart enough to do arg parsing (so there is no quick way to slurp out the last arg there using e.g. daW, though it should be possible to complete the job within 8 keystrokes or so.)

I think that this can be a decent workaround, because I do bring a lot of software to bear on editing text in my terminal text editor.

But what I want is if Zsh (or even Bash!) line editor could be programmed somehow to let me have a zle bind that can shove an arg around. Kind of like this: https://github.com/AndrewRadev/sideways.vim But of course, this plugin won't work on space delimited shell arguments either.

I'd be happy with either a directional hop (so that I can put my cursor somewhere on the --config-file arg and then mash HopLeft to hop the arg to the left) or a yank & paste (so i can put my cursor somewhere on the --config-file arg, yank it out, hit home to go to the front and paste it after it).

This way we can rapidly recompose shell arguments by navigating the args as a unit rather than navigating individual characters as a unit.

If we are to take the idea further this would be implemented as an editor mode, let's call it Argument Edit Mode, where the cursor moves across args instead of characters and a more developed set of actions can be performed on args as a unit.

Let's come back down to earth now. The question is this: can I programmatically cause zsh to delete the shell arg that i'm currently on? And then paste it back in? Can I bind a key to let me hop based on actual args instead of just hopping words?

There doesn't seem to be ready-to-use binds for use with bindkey, but it feels like there might be a way to do it if i can programmatically control the position of the cursor. I do use a plugin that can live syntax highlight my command after all. https://github.com/zsh-users/zsh-syntax-highlighting

  • Not quite what you're asking for, but I tend to take a word-designated command history approach to these situations. While a 'word' in ZLE is (based on my usage w/ vim keybindings, at least) simplistic and jumps between spaces, word designations in history expansion understand quotes. Your example of 'run the last command, but as command --last-arg --all-other-args' can be typed as !!:0 !!:$ !!:1-, and tab-completion will fill it in so you can verify what you're about to execute (and/or tweak with ZLE). – brhfl Jan 16 '18 at 21:14
  • Yeah! That's a feature that definitely is arg-aware that i hadn't thought about leveraging, but the issues therein are related to: the mental overload of !!:1- (mostly remembering what 1- means and how it works) and the fact that once I tab-complete something like !!:-3 I can't go back and adjust it to be !!:-2 without back-deleting it and typing it out again. Stuff like that. It is a workable thing to do, yes. But It's just not quite there from a user experience perspective. – Steven Lu Jan 16 '18 at 21:37
  • Here is another thing that is common that is extremely impractical to use, I want to grab the third-from-last arg from the last command I ran. !!:-3 doesnt provide me that, it actually provides me the command and first 3 args. I am having a hard time finding docs that go over this stuff and I do not know if it is possible to fetch an nth-from-last arg. At the end of the day, the point is that my brain works by pointing a cursor at an arg to refer to it, not by scanning the entire command to count which arg i'm looking at to type it in. – Steven Lu Jan 16 '18 at 21:43
  • Understood, that's why I didn't consider offering it as an actual answer, though I think it's worth keeping in mind as a different approach to the problem. I agree that !!:-3 reads as though it should be third-from-last; instead that dash means 'do a range' and with no beginning index, 0 is implied. The ZLE command undo will, in fact, revert tab-completion. I think this is bound to ctrl-_ in emacs bindings; I'm unsure what the vi command binding u points to since it sure doesn't work. – brhfl Jan 16 '18 at 22:00
1

You may be looking for the select-word-style framework and in particular its shell word style. See

info zsh select-word-style

For instance, add to your ~/.zshrc:

autoload -U select-word-style
zle -N select-word-style
bindkey '\ez' select-word-style

Then (assuming you use the emacs mode)

  • press Alt+Z to invoke select-word-style
  • you'll get a menu where you can select the word style. Press S for the shell word style.
  • then Ctrl+W will delete the previous word as a full argument (a shell word).
  • Ctrl+A or Home to go to the beginning of the line
  • Alt+F to move one word to the right
  • Ctrl+Y to yank the previously killed word.
  • Alt+ZN if you want to go back to the normal word style.
  • I’m pretty sure that this isn’t what I’m looking for per se, but this is definitely a step in the right direction, and a feature I did not know about. It does seem like maybe if this could be scripted then I could implement what I want on top of it... – Steven Lu Jan 19 '18 at 15:38
  • This does not seem to work. The Alt+z bind appears to produce a menu that lets me choose stuff, but the ctrl+w works the same exact way whichever choice is made. zsh 5.3.1 – Steven Lu Jan 19 '18 at 23:26
  • I can not find any documentation on select-word-style. – Steven Lu Jan 19 '18 at 23:32
  • I think the reason this doesn't work is that prezto (which I use my own fork of) sets $WORDCHARS to mimic bash's behavior, thus making the normal mode work just like bash mode for this. – Steven Lu Jan 20 '18 at 0:05
  • If you know the documentation of this stuff, please do post it. Does "shell" mode set a different $WORDCHARS? – Steven Lu Jan 20 '18 at 0:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.