Zsh expand alias to result of function as string - zsh

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...

Related

What can I change in order that Compdef can bind my function?

I have created some console commands in PHP. I need to use autocompletion when I launch my tasks.
I used alias otra="php console.php" in my .zshrc file.
The function itself seems to work but when I type my command name 'otra', there is only folders autocompletion...which is completely irrelevant in my case.
#compdef _otra otra
function _otra {
local line
_arguments -C \
"1: :(createAction createBundle)" \
"*::arg:->args"
}
I want to only have the two words createAction and createBundle to appear when I type otra and type .
EDIT
Ok, it is what I was thinking...if I remove my alias, the completion works but I cannot remove it since otra is not a valid command...
I tried to use setopt no_complete_aliases as I see it in another Stackoverflow post but it does not work for me.
In fact, it was related to the alias but I did not have to set setopt no_complete_aliasesin my case but pretty much the contrary...
After I put setopt complete_aliases in my .zshrc file, it works :D

Zsh not recognizing alias from within function

Here's my .zshrc:
alias inst="adb install -r -d"
notify() {
start=$(date +%s)
"$#"
notify-send "\"$(echo $#)\" took $(($(date +%s) - start)) seconds to finish"
}
When I run the command notify inst app.apk, I get an error:
notify:2: command not found: inst
0.00s user 0.00s system 0% cpu 0.001 total
Can anyone shed some light on why this doesn't work, and hopefully a way to make it work?
When the shell processes commands, among other things (e.g. PATH search) it will check to see if the first token/argument (whitespace delimited) belongs to an alias loaded in the current environment. If the alias you are trying to substitute is not the first token, the substitution will not happen. If your alias happens to not be the name of an executable on the PATH or current directory, the error will propagate back up to a command not found.
Since your question is about the Z Shell, zsh actually provides a lesser-known feature called global aliasing. If an alias is declared with the -g flag, zsh will make the appropriate substitution for not only the first token, but any token, regardless of order.
alias -g inst="adb install -r -d" should do the trick.
Keep in mind that this is a zsh only feature for portability reasons, and make sure that whatever script your writing has a shebang line that invokes the zsh shell: #!/usr/bin/env zsh
I would also recommend to not use zsh global aliasing in important or production scripts. For personal use, it is perfectly fine.
Don't use alias for scripting
First, according to the advanced bash scripting guide:
In a script, aliases have very limited usefulness.
So you may consider not using alias but a function for instance (still from the same page, 2 paragraph lower):
Almost invariably, whatever we would like an alias to do could be accomplished much more effectively with a function.
A hacky solution
If this is for a quick script for yourself using aliases you have in your .zshrc, there is still a way out.
alias foo='echo hello'
bar() {
`alias "$#" | cut -d\' -f2`
}
bar foo # => hello
Alias replacement
from alias man page:
The first word of each simple command, if unquoted, is checked to see if it has an alias. If so, that word is replaced by the text of the alias. The alias name and the replacement text can contain any valid shell input, including shell metacharacters, with the exception that the alias name can not contain `='.
The first word of the replacement text is tested for aliases, but a word that is identical to an alias being expanded is not expanded a second time. This means that one can alias ls to "ls -F", for instance, and Bash does not try to recursively expand the replacement text.
Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt .
The rules concerning the definition and use of aliases are somewhat confusing. Bash always reads at least one complete line of input before executing any of the commands on that line. Aliases are expanded when a command is read, not when it is executed. Therefore, an alias definition appearing on the same line as another command does not take effect until the next line of input is read. The commands following the alias definition on that line are not affected by the new alias. This behavior is also an issue when functions are executed. Aliases are expanded when a function definition is read, not when the function is executed, because a function definition is itself a compound command. As a consequence, aliases defined in a function are not available until after that function is executed. To be safe, always put alias definitions on a separate line, and do not use alias in compound commands.

Reload aliases on change automatically without closing the shell window

I have my aliases stored in ~/.zsh_aliases and sourced in ~/.zshrc:
# Access custom aliases in the shell
[ -e "${HOME}/.zsh_aliases" ] && source "${HOME}/.zsh_aliases"
However, when changing the name of an alias, I have to always close the current shell window and open a new one for the change to become active.
Can Zsh automatically reload aliases on change to make them available without having to close the shell window?
You do not actually need to close and reopen your terminal for that, just running source ~/.zsh_aliases (loads the new and changed aliases) or maybe exec zsh (replaces the current shell with a new one) would work, too.
If you really want to re-source ~/.zsh_aliases whenever it is modified, I would suggest adding the following to your ~/.zshrc:
# File containing aliases;
ALIAS_FILE="${HOME}/.zsh_aliases
reload_aliases () {
# do nothing if there is no $ALIAS_FILE
[[ -e ALIAS_FILE ]] || return 1
# check if $ALIAS_FILE has been modified since last reload
# the modifier `(:A)` resolves any symbolic links
if [[ $LAST_ALIAS_RELOAD < $(stat -c %Y ${ALIAS_FILE}(:A)) ]]; then
# remove all aliases; optional!
# only do this if all of your aliases are defined in $ALIAS_FILE
# also affects aliases defined on the command line
unalias -m '*'
# load aliases
source $ALIAS_FILE
# update date of last reload
LAST_ALIAS_RELOAD=$(date +%s)
fi
}
# make reload_aliases to be run before each prompt
autoload -Uz add-zsh-hook
add-zsh-hook precmd reload_aliases
Note, that any changes will only be available on a new prompt. That means, if you modify ~/.zsh_aliases, you need to press at least Enter once in the all terminals for the changes to take effect.
I use an alias, thusly: -
alias vialias='vi ~/.oh-my-zsh/custom/alias.zsh ; source ~/.oh-my-zsh/custom/alias.zsh'
When I run vialias, I edit my aliases, then when I leave vi, the change(s) take effect.
To simplify the accepted answer add:
source ~/.zsh_aliases
in the ~/.zshrc below the plugins section.
Then add an alias inside the ~/.zsh_aliases like so:
alias f="exec zsh"
To refresh zsh & aliases type f

Get the `pwd` in an `alias`?

Is there a way I can get the pwd in an alias in my .zshrc file? I'm trying to do something like the following:
alias cleanup="rm -Rf `pwd`/{foo,bar,baz}"
This worked fine in bash; pwd is always the directory I've cd'd into, however in zsh it seems that it's evaluated when the .zshrc file is first loaded and always stays as my home directory. I've tested using with a really simple alias setup, but it never changes.
How can I have this change, so that calling the alias from a subdirectory always evaluates as that subdir?
EDIT: not sure if this will help, but I'm using zsh via oh-my-zsh on the mac.
When your .zshrc is loaded, the alias command is evaluated. The command consists of two words: a command name (the builtin alias), and one argument, which is the result of expanding cleanup="rm -Rf `pwd`/{foo,bar,baz}". Since backquotes are interpolated between double quotes, this argument expands to cleanup=rm -Rf /home/unpluggd/{foo,bar,baz} (that's a single shell word) where /home/unpluggd is the current directory at that time.
If you want to avoid interpolation at the time the command is defined, use single quotes instead. This is almost always what you want for aliases.
alias cleanup='rm -Rf `pwd`/{foo,bar,baz}'
However this is needlessly complicated. You don't need `pwd/` in front of file names! Just write
alias cleanup='rm -Rf -- {foo,bar,baz}'
(the -- is needed if foo might begin with a -, to avoid its being parsed as an option to rm), which can be simplified since the braces are no longer needed:
alias cleanup='rm -Rf -- foo bar baz'

bind key to complete filename wherever the context is in Zsh

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

Resources