zsh-bindings: noremap on vi mode - zsh

I want to bind 'dd' in the zsh's vicmd into something like 'ddi', If i use:
bindkey -M vicmd -s dd 'ddi'
It will give me this output:
zsh: string inserting another one too many times

I found the answer already
function delete_then_insert(){
zle kill-whole-line
zle vi-insert
}
zle -N delete_then_insert
bindkey -M vicmd dd delete_then_insert

Related

zle reset-prompt not cleaning the prompt

I have a key binding to go up by one directory (very useful):
# C-M-u: up-directory
up-directory() {
builtin cd .. && zle reset-prompt
}
zle -N up-directory
bindkey '\e\C-u' up-directory
It works well, except that the prompt is not really reset.
Example, starting in a Git repo (~/.dotfiles):
After C-M-u, I get:
So, I'm well one level up (into ~), but the Git info is still there, while not valid anymore -- I'm not in a Git repo anymore…
How to fix this?
You probably need to execute the precmds before resetting the prompt.
fzf's zsh integration does this:
# Ensure `precmds` are run after `cd`
fzf-redraw-prompt() {
local precmd
for precmd in $precmd_functions; do
$precmd
done
zle reset-prompt
}
So, try something like this:
up-directory() {
builtin cd ..
if (( $? == 0 )); then
local precmd
for precmd in $precmd_functions; do
$precmd
done
zle reset-prompt
fi
}

widgets for case manipulation: `gU` in normal and `U` in visual mode

I reckon there's already a widget for the g~ action in zle. So g~iw will invert the case of a word.
I read the zshzle manual and did not find a widget that would give me the behaviour of gU (capitalize action) in vim.
for example: for the word "path_variable", with the cursor on the v, gUiW would change the world to "PATH_VARIABLE", and so on and so forth.
the widget capitalize-word does not seem to be the answer. I've tested it.
I also found that the key U in visual mode does not capitalize the visually selected text/region. I did not find a widget in the manual that would give me the desired behaviour either.
Is this a matter of writing a custom widget, or would one have to submit a patch upstream with c code changes? How can I bind gU in normal and U in visual mode to achieve the desired behaviour in zle vi-mode?
ZSH 5.3 will have pre built widgets for that. But if you can't wait, here it is:
# credits go to Oliver Kiddle <opk#zsh.org>,
# who personally shared these upper/lower widgets.
# I just corrected a small bug.
vi-lowercase() {
local save_cut="$CUTBUFFER"
local save_cur="$CURSOR"
zle .vi-change || return
zle .vi-cmd-mode
CUTBUFFER="${CUTBUFFER:l}"
if [[ $CURSOR = '0' ]]; then
zle .vi-put-before -n 1
else
zle .vi-put-after -n 1
fi
CUTBUFFER="$save_cut"
CURSOR="$save_cur"
}
vi-uppercase() {
local save_cut="$CUTBUFFER"
local save_cur="$CURSOR"
zle .vi-change || return
zle .vi-cmd-mode
CUTBUFFER="${CUTBUFFER:u}"
if [[ $CURSOR = '0' ]]; then
zle .vi-put-before -n 1
else
zle .vi-put-after -n 1
fi
CUTBUFFER="$save_cut"
CURSOR="$save_cur"
}
# can safely disable this after commit zsh commit #a73ae70 (zsh-5.2-301- ga73ae70)
zle -N vi-lowercase
zle -N vi-uppercase
bindkey -a 'gU' vi-uppercase
bindkey -a 'gu' vi-lowercase
bindkey -M visual 'u' vi-lowercase
bindkey -M visual 'U' vi-uppercase

Why doesn't incremental history search work in zsh?

I'm trying to get rid of Oh-my-zsh and currently my biggest challenge is getting incremental history search working. I've acked and grepped my way through the code and there's no clues in site. I get this error :
No such widget 'histrory-beginning-search-backward'
EDIT:
I've tried this with the absolute least possible code, it still doesn't work. here's the reduced test case:
# key bindings
bindkey -v
function zle-line-init zle-keymap-select {
RPS1="${${KEYMAP/vicmd/NORMAL}/(main|viins)/INSERT}"
RPS2=$RPS1
zle reset-prompt
}
zle -N zle-line-init
zle -N zle-keymap-select
bindkey -M vicmd '^R' histrory-beginning-search-backward
bindkey -M viins '^R' histrory-beginning-search-backward
Here's my config, taken from the zsh config wizzard, my current zshrc and oh-my-zsh:
autoload zkbd
# The following lines were added by compinstall
zstyle ':completion:*' completer _expand _complete _ignored _correct _approximate
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}' 'r:|[._-]=* r:|=*' 'l:|=* r:|=*'zstyle ':completion:*' verbose true
zstyle :compinstall filename '/home/jonathan/.zshrc'
zstyle ':completion:*' list-colors ''
zstyle ':completion::complete:*' use-cache 1
zstyle ':completion::complete:*' cache-path $HOME/.cache/zsh
#load colorstuff
autoload -Uz compinit
autoload -U colors && colors
compinit
# End of lines added by compinstall
# Lines configured by zsh-newuser-install
HISTFILE=~/.histfile
HISTSIZE=1000
SAVEHIST=1000
setopt extendedglob
unsetopt beep nomatch notify
# End of lines configured by zsh-newuser-install
setopt completealiases
# Ignore boring stuff
zstyle ':completion:*:*:*:users' ignored-patterns \
adm amanda apache at avahi avahi-autoipd beaglidx bin cacti canna \
clamav daemon dbus distcache dnsmasq dovecot fax ftp games gdm \
gkrellmd gopher hacluster haldaemon halt hsqldb ident junkbust kdm \
ldap lp mail mailman mailnull man messagebus mldonkey mysql nagios \
named netdump news nfsnobody nobody nscd ntp nut nx obsrun openvpn \
operator pcap polkitd postfix postgres privoxy pulse pvm quagga radvd \
rpc rpcuser rpm rtkit scard shutdown squid sshd statd svn sync tftp \
usbmux uucp vcsa wwwrun xfs '_*'
zstyle ':completion:*:functions' ignored-patterns '_*'
# Completion dots
expand-or-complete-with-dots() {
echo -n "\e[31m......\e[0m"
zle expand-or-complete
zle redisplay
}
zle -N expand-or-complete-with-dots
bindkey "^I" expand-or-complete-with-dots
# Prompt stuff *truncated*
# key bindings
bindkey -v
function zle-line-init zle-keymap-select {
RPS1="${${KEYMAP/vicmd/NORMAL}/(main|viins)/INSERT}"
RPS2=$RPS1
zle reset-prompt
}
zle -N zle-line-init
zle -N zle-keymap-select
bindkey -M vicmd '^R' histrory-beginning-search-backward
bindkey -M viins '^R' histrory-beginning-search-backward
function run-again {
zle up-history
zle accept-line
}
zle -N run-again
bindkey -M viins '^W' run-again
bindkey -M vicmd '^W' run-again
bindkey -M viins ' ' magic-space # [Space] - do history expansion
bindkey '^[[1;5C' forward-word # [Ctrl-RightArrow] - move forward one word
bindkey '^[[1;5D' backward-word # [Ctrl-LeftArrow] - move backward one word
if [[ "${terminfo[kcbt]}" != "" ]]; then
bindkey -M viins "${terminfo[kcbt]}" reverse-menu-complete # [Shift-Tab] - move through the completion menu backwards
fi
dirstackfile="$HOME/.cache/zsh/dirs"
if [[ -f dirstackfile ]] && [[ $#dirstack -eq 0 ]]; then
dirstack=( ${(f)"$(< $dirstackfile)"} )
[[ -d $dirstack[1] ]] && builtin cd $dirstack[1]
fi
chpwd() {
print -l $PWD ${(u)dirstack} > $dirstackfile
}
dirstacksize=20
setopt autopushd pushdsilent pushdtohome
# remove duplicate entries
setopt pushdignoredups
#revert plus and minus operators.
setopt pushdminus
#PATH info truncated
What am I doing wrong?
Whoops... I had a typo, now I feel dumb. I had it as histrory, when it should be history..

zsh preexec command modification

Is there a way to modify the command that is about to execute?
I would like to redirect the output to a file, as well as print it on the terminal.
I found that ls > file.txt | cat does the job, so I would like to add that > file.txt | cat to any command that is about to execute.
Is there a better way to redirect to file and print to terminal? I am trying to make a logger.
You can change the action that is performed when you execute a line to alter the command that will be executed. This can be done by defining a function which you then bind to the enter key.
Lets first define a function that can add the '> file.txt | cat' ending to any command:
function log_and_accept {
BUFFER="$BUFFER > file.txt | cat"
zle accept-line
}
The next part is to actually replace the default enter key behaviour with your new function. The default behaviour we are replacing is the accept-line function, and if we look at the zle documentation, you will see that accept-line is bound to ^J and ^M.
To bind this function to those letters you first need to turn it into a widget:
zle -N log_and_accept_widget log_and_accept
Then you can bind it, replacing the old behaviour:
bindkey '^J' log_and_accept_widget
bindkey '^M' log_and_accept_widget
Now you will be expanding that command for every single command you do. Every cd, ls, vim etc etc. As such I recommend that you define a couple more functions that actually turn this on and off:
function turn_on_logging {
bindkey '^J' log_and_accept_widget
bindkey '^M' log_and_accept_widget
}
function turn_off_logging {
bindkey '^J' accept-line
bindkey '^M' accept-line
}
zle -N turn_on_logging_widget turn_on_logging
zle -N turn_off_logging_widget turn_off_logging
bindkey '^P' turn_on_logging_widget
bindkey '^O' turn_off_logging_widget
I think you should be careful with this. After testing it a little, I quickly grew to dislike it.
There are several ways to do that, the 1 I like the most is this block I found here http://git.grml.org/?p=grml-etc-core.git;a=blob_plain;f=etc/zsh/zshrc;hb=HEAD
abk=(
'...' '../..'
'....' '../../..'
'BG' '& exit'
'C' '| wc -l'
'G' '|& grep '${grep_options:+"${grep_options[*]}"}
'H' '| head'
'Hl' ' --help |& less -r' #d (Display help in pager)
'L' '| less'
'LL' '|& less -r'
'M' '| most'
'N' '&>/dev/null' #d (No Output)
'R' '| tr A-z N-za-m' #d (ROT13)
'SL' '| sort | less'
'S' '| sort -u'
'T' '| tail'
'V' '|& vim -'
'co' './configure && make && sudo make install'
'fc' '> file.txt | cat'
)
zleiab() {
emulate -L zsh
setopt extendedglob
local MATCH
if (( NOABBREVIATION > 0 )) ; then
LBUFFER="${LBUFFER},."
return 0
fi
matched_chars='[.-|_a-zA-Z0-9]#'
LBUFFER=${LBUFFER%%(#m)[.-|_a-zA-Z0-9]#}
LBUFFER+=${abk[$MATCH]:-$MATCH}
}
zle -N zleiab && bindkey ",." zleiab
Also notice that I added 'fc' '> file.txt | cat' to the list abk
What this does in that that you type fc after the command and then you hit ,. (comma and period) in rapid succession and zsh will replace fc for > file.txt | cat

zsh alias expansion

Is it possible to configure zsh to expand global aliases during tab completion? For example, I have the common aliases:
alias -g '...'='../..'
alias -g '....'='../../..'
but when I type, for example, cd .../some<tab> it won't expand to cd .../something or cd ../../something. Consequently, I frequently won't use these handy aliases because they are incompatible with tab completion.
I'm a user of Mikael Magnusson's rationalise-dot. From my zshrc:
# This was written entirely by Mikael Magnusson (Mikachu)
# Basically type '...' to get '../..' with successive .'s adding /..
function rationalise-dot {
local MATCH # keep the regex match from leaking to the environment
if [[ $LBUFFER =~ '(^|/| | |'$'\n''|\||;|&)\.\.$' ]]; then
LBUFFER+=/
zle self-insert
zle self-insert
else
zle self-insert
fi
}
zle -N rationalise-dot
bindkey . rationalise-dot
# without this, typing a . aborts incremental history search
bindkey -M isearch . self-insert
Try looking up zsh abbreviations. They allow you to enter an "abbreviation" which automatically gets replaced with its full form when you hit a magic key such as space. So you can create one which changes ...<SPACE> to ../...
For example, this is what you need in your profile:
typeset -A abbrevs
abbrevs=(
"..." "../.."
"...." "../../.."
)
#create aliases for the abbrevs too
for abbr in ${(k)abbrevs}; do
alias -g $abbr="${abbrevs[$abbr]}"
done
my-expand-abbrev() {
local MATCH
LBUFFER=${LBUFFER%%(#m)[_a-zA-Z0-9]#}
LBUFFER+=${abbrevs[$MATCH]:-$MATCH}
zle self-insert
}
bindkey " " my-expand-abbrev

Resources