Sometimes I want a filename instead of what zsh guesses for me. For example, I have a PNG file without a proper .png suffix, which makes zsh think it isn't a picture and won't list it when I type Tab to complete arguments of display.
I am wondering if there is a key sequence that completes for a filename wherever the context is, like ^XC for _correct_filename, or how to configure zsh to do the thing?
You can add a key binding to do what you want:
zle -C complete complete-word complete-files
bindkey '^X\t' complete
complete-files () { compadd - $PREFIX* }
Edit: Added $PREFIX
You can add those lines to your ~/.zshrc file.
That makes the completion list all files when you press Ctrl-x Tab at each step instead of Tab. You could choose another keystroke combination that suits you.
Or to make ImageMagick completions always include all files, try editing (make a backup first) the file /usr/share/zsh/functions/Completion/Unix/_imagemagick (or similar) and change this to comment out the existing line that begins with _files and add the new one shown:
if (( $# )); then
# _files "$#" -g "*.(#i)(${~formats//:/|})(-.)"
_files "$#"
return
fi
Dennis' answer didn't expand tilde for me, so I would get stuff like complete-files: no matches found: ~/ma* when I tried to invoke it on foo ~/ma. I did find an alternate in the zsh FAQ that will expand them, though:
zle -C complete-file complete-word _generic
zstyle ':completion:complete-file::::' completer _files
bindkey '^xF' complete-file
Related
I noticed that tab completion for the source command in Zsh tries to complete a LOT of files. Maybe everything in $PATH? I tried using a blank .zshrc file to make sure it wasn't anything in there.
ubuntu% source d
zsh: do you wish to see all 109 possibilities (16 lines)?
I did find this file that seems to control that: /usr/share/zsh/functions/Completion/Zsh/_source
#compdef source .
if [[ CURRENT -ge 3 ]]; then
compset -n 2
_normal
else
if [[ -prefix */ && ! -o pathdirs ]]; then
_files
elif [[ $service = . ]]; then
_files -W path
else
_files -W "(. $path)"
fi
fi
If I change the line in that last "else" statement from _files -W "(. $path)" to _files, it works the way I want it to. The tab completion only looks at files & directories in the current dir.
It doesn't seem like altering this file is the best way to go. I'd rather change something in my .zshrc file. But my knowledge of Zsh completions is a bit lacking and the searching I've done thus far hasn't led me to an answer for this.
Maybe everything in $PATH?
Yes, that is correct. It offers those, because source will search your the current dir and your $PATH for any file name you pass it.
To apply your change without modifying the original file, add this to your .zshrc file after calling compinit:
compdef '
if [[ CURRENT -ge 3 ]]; then
compset -n 2
_normal
else
_files
fi
' source
This tells the completion system to use the inline function you specified for the command source (instead of the default function).
Alternatively, to see file completions for the current dir only, you can type
$ source ./<TAB>
I would like to add some additional syntax to zsh. I would like //some/path/to/file to be relative to the root of my source code tree (/src/repositories/projects). So running ls //some/path/to/directory should list files in /src/repositories/projects/some/path/to/directory.
The best way I've found to do this is with a ZLE accept-line widget which rewrites //... paths with the full UNIX path /src/repositories/projects/... and then invokes the command. This works quite well, but it expands the //... syntax inline and stores the expansion in history, which can make searches a bit more complicated. I would like to store the original //... syntax in the history while keep the /src/repositories/projects/... syntax out.
I am able to use print -s to add the original //... syntax to history, but I am having trouble keeping the expanded syntax out of history. Currently my code looks like this:
function accept-line-override() {
# Add untranslated command to history
print -s "$BUFFER"
# Translate //... paths to /src/repositories/projects/...
BUFFER=$(fix-paths "$BUFFER")
# Invoke command with new paths
zle .accept-line
}
zle -N accept-line accept-line-override
This gives me two lines of history for every invoked command:
$ echo //test
/src/repositories/projects/test
$ history | tail -n 2
10020 echo //test
10021 echo /src/repositories/projects/test
Is there a way I can prevent zle .accept-line from adding its command to history? I've seen methods involving history -d but those only seem to work for bash. I also saw somewhere to do:
function accept-line-override() {
# Add untranslated command to history
print -s "$BUFFER"
# Translate //... paths to /src/repositories/projects/...
BUFFER=$(fix-paths "$BUFFER")
# Manually invoke line so it is not added to history
echo
eval $BUFFER
echo
# Reset prompt
BUFFER=""
zle .reset-prompt
}
But this leads to a lot of undesired side-effects, from Emacs refusing to open to auto-completions not clearing before the command is executed. I'd very much like to avoid that complexity if at all possible. Any idea on getting around this?
Really quirky title, I know.
Basically, I have this:
alias vv="xclip -selection clipboard -o"
which prints out anything in my clipboard, such as a repository location in ssh-form (git#github.username/repname.git).
Now I'd like to:
git clone vv
I tried several variations of the above, such as trying various switches on the alias, or using different expansions, but with no luck.
Any suggestions?
Global alias might do it... actually it does it:
alias -g vv="$(date)" # replace 'date' with your command of choice
Notice:
it is a global alias, so it works anywhere in the command line (not just the beginning)
$(...) will do command substitution and expand it as a variable, see man zshexpn and search for $(...). By default zsh will not break the results using white-spaces.
[...]
I initially wrote a suggestion to create a (zsh) widget to insert the clipboard into the command line with a given key combination, then I realized that you would just likely hit "Ctrl-Shift-V" or something... :-S
[...]
FYI, this is how you would do this using a zsh widget:
that inserts the clipboard content on the command line, and binding it to some key, as it would allow you to see what you are doing before hitting enter. Place the following into your $fpath, inside a file called insert-clipboard (needs to be loaded with KSH_AUTOLOAD set)
#! /bin/zsh
## Inserts the output of the command into the cmd line buffer
zmodload -i zsh/parameter
insert-clipboard() {
LBUFFER+="$(date)" # REPLACE date BY YOUR COMMAND!
}
At your .zshrc
autoload insert-clipboard # as written, it needs KSH_AUTOLOAD set....
zle -N insert-clipboard
bindkey '^Xu' insert-clipboard # pick a key combination you like...
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\""
I'm wondering if it's possible to write a zsh script that will write a command to the prompt but NOT execute it, i.e. leave it there for me to edit and then execute when I'm ready. I can do something like this with keybindings by leaving off the final '\C-m'. eg:
bindkey -s "\e[1;3C" "howdy!"
... I press Alt+RightArrow and the text "howdy!" is printed at the prompt and just left there.
I can also do something like what I want by writing my command to the history file and then recalling it with the up arrow. I've tried 'echo -n sometext' but it doesn't work.
Can I write a script that would exit leaving (say) " howdy! " on the command line? In actual fact I want the script to build up a complex command based on several things, but I want the script to leave it on the CLI for final editing, so automatic execution must be prevented.
Thanks in advance.
Turns out the answer is simple:
print -z $string-to-print
If you mean a zsh function and not an external script, you can write a zle (short for zsh line editor) widget and bind it to some key.
# define to function to use
hello () {
BUFFER=hello
zle end-of-line
}
# create a zle widget, which will invoke the function.
zle -N hello
# bindkey Alt-a to that widget
bindkey "\ea" hello
You can learn more from A User's Guide to the Z-Shell, Chapter 4.