49

Bash behaviour

I've just migrated from bash to zsh. In bash, I had the following line in ~/.inputrc.

"\e\C-?": unix-filename-rubout

Hence, Alt+Backspace would delete back to the previous slash, which was useful for editing paths.

Separately, bash defaults to making Ctrl+w delete to the previous space, which is useful for deleting whole arguments (presuming they don't have spaces). Hence, there two slightly different actions performed with each key combination.

Zsh behaviour

In zsh, both Alt+Backspace and Ctrl+w do the same thing. They both delete the previous word, but they are too liberal with what constitutes a word-break, deleting up to the previous - or _. Is there a way to make zsh behave similarly to bash, with two independent actions? If it's important, I have oh-my-zsh installed.

Sparhawk
  • 19,941
  • 1
    Do you want to change zsh's definition of what constitutes a word? If so: http://unix.stackexchange.com/questions/48577/modifying-the-zsh-shell-word-split Or do you want to define a new command with a different definition of word? – Gilles 'SO- stop being evil' Jan 30 '16 at 13:22
  • @Gilles I guess a combination of both. In bash, I'd use the two distinct commands regularly: i.e. delete to the last / and delete to the last . They have different functions. – Sparhawk Jan 30 '16 at 13:24
  • 1
    @Gilles So yes, that link works for my bash-like Alt+Backspace behaviour, but I'd still like the (different) bash-like Ctrl+w behaviour, i.e. delete to last space. – Sparhawk Jan 30 '16 at 13:35

6 Answers6

50

A similar question was asked here: zsh: stop backward-kill-word on directory delimiter

and a workable solution given: add these settings to your zshrc:

autoload -U select-word-style
select-word-style bash
Thomas Dickey
  • 76,765
  • 1
    Thanks for the answer. However, none of those answers work for me. (Specifically, the one you quoted makes no change.) Possibly, it's because I have oh-my-zsh installed. In any case, this doesn't seem to address the two different functions and key bindings as per my question. (And if my question were it dupe it should be closed as a dupe. Which it is not.) – Sparhawk Jan 30 '16 at 03:15
  • 4
    You need to tweak WORDCHARS variable. In zsh it's easy vared WORDCHARS – appomsk Jan 30 '16 at 04:34
  • It would only be a duplicate if we matched it against an answered question in this forum. – Thomas Dickey Jan 30 '16 at 12:19
  • @ThomasDickey Oh yes, apologies, I didn't notice I'd swapped SE sites. – Sparhawk Jan 30 '16 at 13:24
  • 2
    @Jshura No, as per the question, I'd like two different functions, which is possible in bash. – Sparhawk Jan 30 '16 at 13:28
  • @Sparhawk it didn't work for me when I had command syntax highlighting enabled for some reason. I disabled it and now it works (anyway it makes the prompt laggy - I can live without it). – Piotr Jun 06 '20 at 16:50
  • 1
    worked great for me on my mac (bash to zsh). Key bindings can be defined in the preferences of the terminal app – Thomas Dec 24 '20 at 07:21
  • Don't forget that Terminal.app traditionally presumes that you need to use Option to get to certain common characters (like "@") - this is NOT such a big issue for modernm keyboard layouts, and I wish that its Preferences checkbox "Use Option as Meta key" was checked by default! Because now we need to ALWAYS CHECK IT instead for e.g. Alt-Backspace or Alt-arrows to work as expected. – conny Jul 19 '22 at 12:31
24

Edit: The next google result after your question was this one with same solution : zsh: make ALT+BACKSPACE stop at non-alphanumeric characters

This answer was provided by /nick FoH from #zsh on freenode.

backward-kill-dir () {
    local WORDCHARS=${WORDCHARS/\/}
    zle backward-kill-word
    zle -f kill
}
zle -N backward-kill-dir
bindkey '^[^?' backward-kill-dir

This way you can use ctrl+w for deleting a Word (in vim lingo) and alt+bkspc to delete a word

  • Brilliant! Thanks for taking the time to investigate and answer. – Sparhawk Oct 30 '16 at 10:00
  • Re Google: except I asked my question nine months ago, and they asked theirs less than a month ago. – Sparhawk Oct 30 '16 at 10:06
  • 1
    time is just a social construct man!.. but seriously, fair point. – JunkMechanic Oct 10 '19 at 13:43
  • Doesn't work for me. It seemingly makes ^w and meta-bs act in the same way. – conny Aug 27 '21 at 03:47
  • If this doesn't work for you, it may be because your WORDCHARS is empty, so perhaps you want to try setting it explicitly instead: local WORDCHARS='*?_-.[]~=&;!#$%^(){}<>' (from https://stackoverflow.com/a/11200998/4545777) – Cnly Apr 16 '22 at 10:44
10

Expanding on JunkMechanic's answer, I wanted that

  • existing zsh shortcuts (CtrlW, Ctrl and Ctrl) works as in zsh defaults
  • Alt-based shortcuts (AltW, Alt and Alt) work similarly, but "finer grained", e.g. up to the closest /

Here's what I use now:

# Alt+Backspace
backward-kill-dir () {
    local WORDCHARS=${WORDCHARS/\/}
    zle backward-kill-word
    zle -f kill  # Ensures that after repeated backward-kill-dir, Ctrl+Y will restore all of them.
}
zle -N backward-kill-dir
bindkey '^[^?' backward-kill-dir

Alt+Left

backward-word-dir () { local WORDCHARS=${WORDCHARS//} zle backward-word } zle -N backward-word-dir bindkey "^[[1;3D" backward-word-dir

Alt+Right

forward-word-dir () { local WORDCHARS=${WORDCHARS//} zle forward-word } zle -N forward-word-dir bindkey "^[[1;3C" forward-word-dir

For details on the zle -f kill, see Zsh - pasting text killed in a custom widget only works for last word, can that be fixed?

nh2
  • 1,721
  • 2
  • 14
  • 22
3

I achieved your desired result by sticking the following in $ZDOTDIR/.zshrc:

# Use bash-like word definitions for navigation and operations
autoload -Uz select-word-style
select-word-style bash

Use C-w to kill back to the previous space

zle -N backward-kill-space-word backward-kill-word-match zstyle :zle:backward-kill-space-word word-style space bindkey '^W' backward-kill-space-word

This has an advantage over other answers by not limiting the target delimiter of Alt+Backspace to /; for example, it will delete back to -, as well. Still, Ctrl+w will delete back to the previous space. This is more bash-like than other answers.

I am using zsh 5.8 on macOS, without oh-my-zsh or any other configuration framework.

Reference: http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#index-backward_002dkill_002dword_002dmatch


Bonus: The following makes zsh even more bash-like:

# Use C-u to kill to the beginning of the line
bindkey '^U' backward-kill-line

Use C-x C-e to edit the current command line in $VISUAL

autoload -Uz edit-command-line zle -N edit-command-line bindkey '^X^E' edit-command-line

eeowaa
  • 153
1

bindkey '^[^?' vi-backward-kill-word


As far as I can tell, its effect on Meta-BackSpace is the same as with the answer suggested by @thomas-dickey, and it's a oneliner rather than two ;-). However, this only affects Meta-BS. If you are looking for the full bash-like behavior with Meta-(Left/Right) navigation then select-word-style is the right way.

(Footnote: the select-word-style-thing is documented in man zshcontrib but they are all but incomprehensible to me. vi-backward-kill-word is documented in man zshzle.)

conny
  • 113
0

Just wanted to add this in nh2's answer

  • alt + left/right arrow to move
  • alt + delete/w for deleting word forward/backward

# Alt+Delete
forward-kill-dir () {
    local WORDCHARS=${WORDCHARS/\/}
    zle kill-word
}
zle -N forward-kill-dir
bindkey '^[[3;3~' forward-kill-dir

Alt+w

backward-kill-dir () { local WORDCHARS=${WORDCHARS//} zle backward-kill-word } zle -N backward-kill-dir bindkey '^[w' backward-kill-dir

Alt+Left

backward-word-dir () { local WORDCHARS=${WORDCHARS//} zle backward-word } zle -N backward-word-dir bindkey "^[[1;3D" backward-word-dir

Alt+Right

forward-word-dir () { local WORDCHARS=${WORDCHARS//} zle forward-word } zle -N forward-word-dir bindkey "^[[1;3C" forward-word-dir

Cipher
  • 1