zsh: stop backward-kill-word on directory delimiter - zsh

In zsh, how can I set up the line editor such that backward-kill-word stops on a directory separator? Currently in my bash setup, if I type
cd ~/devel/sandbox
and then hit C-w point will be right after devel/. In my zsh setup, point would be after cd . I'd like to set up zsh so it behaves similarly to bash.

For recent versions of zsh, you can simply add:
autoload -U select-word-style
select-word-style bash
to your zshrc as described in the zsh manual (also man zshcontrib).

Another option is to set WORDCHARS (non-alphanumeric chars treated as part of a word) to something that doesn't include /.
You can also tweak this if you'd prefer ^w to break on dot, underscore, etc. In ~/.zshrc I have:
WORDCHARS='*?_-.[]~=&;!#$%^(){}<>'

Here's what worked for me. unspecified word-style was required otherwise zsh didn't seem to respect the WORDCHARS.enter code here
WORDCHARS=' *?_-.[]~=&;!#$%^(){}<>/'
autoload -Uz select-word-style
select-word-style normal
zstyle ':zle:*' word-style unspecified
Here's more info on why this works.

A quick google reveals:
Backward Kill
Or, perhaps a better fix:
Bash Style Backward Kill

Related

What does it mean !{0}, !{1}, !{2} ... on zsh in Ubuntu?

Recently, I accidentally typed !{0}. I think it is some kind of special zsh function because it showed one of my previous commands while I execute it.
What does it mean on zsh?
$ !{0}
Note: I'm using zsh on Ubuntu.
If you're "using zsh on ubuntu" then you are not using bash. bash and zsh are two different shells, which have slightly different behaviours.
In both shells, ! introduces a history expansion, which replaces the ! and following word with something taken from the command history.
In zsh, !{0} will be replaced with the previous command you typed which started with 0; the same as !0. In bash, the braces are treated literally, so !{0} will be replaced with the previous command which started with {0}. In both shells, !1 will be replaced with the first command in the history (if it is still remembered); in zsh, !{1} will also be replaced with the first command in the history, while in bash it will be replaced by a command starting with {1}

How to make zsh search configuration in $XDG_CONFIG_HOME

Looking to make my ~ a cleaner place, I would like to move as much user configuration files into $XDG_CONFIG_HOME, which is ~/.config by default. So I would like to store all my zsh user files in $XDG_CONFIG_HOME/zsh/. So far already have this:
% ls $XDG_CONFIG_HOME/zsh/
histfile zsh_cache zshrc
Easy, you just have to fill your ~/.zshrc. Now the trickiest part seems to make zsh read directly $XDG_CONFIG_HOME/zsh/zshrc without sourcing it from ~/.zshrc. How would you proceed?
One may edit /etc/zsh/zshenv to set $XDG_CONFIG_HOME directories and $ZDOTDIR. This require write privilegies on this files though.
So provided that $HOME is defined when zsh read it (I don't know if it's the case), you may add to your /etc/zsh/zshenv:
if [[ -z "$XDG_CONFIG_HOME" ]]
then
export XDG_CONFIG_HOME="$HOME/.config/"
fi
if [[ -d "$XDG_CONFIG_HOME/zsh" ]]
then
export ZDOTDIR="$XDG_CONFIG_HOME/zsh/"
fi
It is good practice to not put a / at the end of any variable holding a certain path.
For example, $XDG_CONFIG_HOME/zsh translates to "$HOME/.config//zsh" and the / repeats because XDG_CONFIG_HOME ends with a /.
So I think your answer should be -
if [[ -z "$XDG_CONFIG_HOME" ]]
then
export XDG_CONFIG_HOME="$HOME/.config"
fi
if [[ -d "$XDG_CONFIG_HOME/zsh" ]]
then
export ZDOTDIR="$XDG_CONFIG_HOME/zsh"
fi
Variation to psychoslave's answer which uses ${HOME}/.zshenv to initiate the environment. No root access needed.
export XDG_CONFIG_HOME=${XDG_CONFIG_HOME:=${HOME}/.config}
export ZDOTDIR=${ZDOTDIR:=${XDG_CONFIG_HOME}/zsh}
source $ZDOTDIR/.zshenv
This was discussed on this thread on the zsh-users mailing list.
You may want to consider saving history in XDG_DATA_HOME. Specifications can be found at XDG Base Directory Specification.
Write a wrapper for zsh that executes zsh after setting the environment variable ZDOTDIR to where you want zsh to look for the config files.
See: http://zsh.sourceforge.net/Intro/intro_3.html

ZSH auto_vim (like auto_cd)

zsh has a feature (auto_cd) where just typing the directory name will automatically go to (cd) that directory. I'm curious if there would be a way to configure zsh to do something similar with file names, automatically open files with vim if I type only a file name?
There are three possibilities I can think of. First is suffix aliases which may automatically translate
% *.ps
to
% screen -d -m okular *.ps
after you do
alias -s ps='screen -d -m okular'
. But you need to define this alias for every file suffix. It is also processed before most expansions so if
% *.p?
matches same files as *.ps it won’t open anything.
Second is command_not_found handler:
function command_not_found_handler()
{
emulate -L zsh
for file in $# ; do test -e $file && xdg-open $file:A ; done
}
. But this does not work for absolute or relative paths, only for something that does not contain forward slashes.
Third is a hack overriding accept-line widget:
function xdg-open()
{
emulate -L zsh
for arg in $# ; do
command xdg-open $arg
endfor
}
function _-accept-line()
{
emulate -L zsh
FILE="${(z)BUFFER[1]}"
whence $FILE &>/dev/null || BUFFER="xdg-open $BUFFER"
zle .accept-line
}
zle -N accept-line _-accept-line
. The above alters the history (I can show how to avoid this) and is rather hackish. Good it does not disable suffix aliases (whence '*.ps' returns the value of the alias), I used to think it does. It does disable autocd though. I can avoid this (just || test -d $FILE after whence test), but who knows how many other things are getting corrupt as well. If you are fine with the first and second solutions better to use them.
I guess you can use "fasd_cd" which has an alias v which uses viminfo file to identifi files which you have opened at least once. In my environment it works like a charm.
Fast cd has other amazing stuff you will love!
Don't forget to set this alias on vim to open the last edited file:
alias lvim="vim -c \"normal '0\""

case insensitive glob listing in zsh

I have the following code:
$ print -l backgrounds/**/*.((#i)jpg|jpeg|gif|webp|png|svg|xcf|cur|ppm|pcd)
the intention was to list some image file indifernet of the case of file termination.
But my code seems to not be functional because won't list files whit uppercase endings.
Can someone explain my error in the above code example?
Thanks in advance.
You need the #i to apply to everything, not just jpg. You can use:
$ print -l backgrounds/**/*.(#i)(jpg|jpeg|gif|webp|png|svg|xcf|cur|ppm|pcd)
Make sure you have also done:
set -o extended_glob
Note that using #i requires that EXTENDED_GLOB be set in your script/shell:
setopt EXTENDED_GLOB
See the docs, section 1.8.4 Globbing Flags, or type man zshexpn.
And you want: *.(#i)(jpg|gif|etc)

Bash alias to open Vim at last cursor position mark

The mark " in Vim takes you to your last cursor position. I want to create an alias that will open my Vim instance and jump to that mark; something which is obviously extremely useful.
This works from the command line:
$ vim -c "'\"" File.cpp
Now I want to make an alias for this:
$ alias v='vim -c "'\""'
Well that's not going to work! You need to escape the first single quote you say...
$ alias v='vim -c "\'\""'
Hmm. That didn't work either... So I try a whole lot of variations of single quoted and double quoted madness, bang my head against the table and load up stackoverflow in my browser, and here we are.
How do I properly escape this alias?
Edit
In fact there is a better way to do this :h last-position-jump.
This autocommand jumps to the last known position in a file just after opening it, if the '" mark is set:
:au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif
Your question is an example of a situation in which functions are superior to aliases:
v() { vim -c "'\"" "$#"; }
This looks completely obscure, but should work:
alias v='vim -c "'"'"'\""'
That's a single-quoted vim -c ", followed by a double-quoted ', followed by a single-quoted \""...
Another solution is GNU Screen. It let's you save one or more shell instances (where one or more could be running vim) and saves their exact contents as if your computer would be idling. In particular, it's perfect for having many tabs and files open on a remote computer.
So instead of just going to the last mark, you'd simply type screen -r mysession and you'd restore not just the last position of the cursor, but all your buffers/tabs/shell instances/other programs and what not.
But perhaps you knew that already.

Resources