2

I have git aliased to g. Sometimes I use g, and sometimes I don't.

I might run git add file1 and later g add file2.

When I want to add file1 again, I might type g add in the zsh prompt, and then press the up arrow a few times. I won't get to git add file1. So I have to try git add and then the up arrow.

Likewise, git add will never find g add file2.

This feels like it should be solvable. Is there a way to make up arrow history search detect aliases?

  • You tagged bash, but asked about zsh; is bash in the scope of this question? – Jeff Schaller Jun 19 '18 at 13:18
  • I'm not sure what parts of history and searching are bash. Also, the solution might be sourcing a bash script that does the same thing in bash. – Riley Martine Jun 19 '18 at 14:07
  • 2
    If you're using zsh, then bash is not involved and cannot help. If you're using bash, zsh is not involved and cannot help. – Gilles Jun 19 '18 at 22:21
  • Okay, thanks for letting me know and fixing the tags! – Riley Martine Jun 20 '18 at 14:01
2

This would be complicated to implement in the reverse search phase

alias g=grep
g foo /etc/passwd
alias g=git
g status

as the reverse search would need to know that the alias had changed, information that unlike the above example will not be available if the alias was invisibly (to the history search function) changed via a configuration file edit and shell restart.

Instead, it may be more suitable (but still somewhat complicated) to record canonical information into the shell history, so the shell history of the above would instead be expanded out to git or grep depending on the alias in favor at the time the command was run. Downside: you need to manage the history yourself, and you have to search by the command name, not the alias:

function zshaddhistory() {
  local -a cmd
  local i
  # split using shell parse, see zshexpn(1)
  cmd=(${(z)1})
  if (( $#cmd )); then
    # alias expand or failing that the command
    # NOTE zsh is 1-indexed, not 0-indexed
    cmd[1]=${aliases[$cmd[1]]:-$cmd[1]}
    for (( i = 2 ; i < $#cmd ; i++ )); do
      # look for ; and try to alias expand word following
      if [[ $cmd[$((i-1))] == \; ]]; then
        cmd[$i]=${aliases[$cmd[$i]]:-$cmd[$i]}
      fi
    done
    # (z) adds a trailing ; remove that
    cmd[$#cmd]=()
    # write to usual history location
    print -sr -- $cmd
  fi
  # disable the usual history handling
  return 1
}
alias g='echo wait for godot'

With this loaded:

% exec zsh -l
% ls
...
% uptime
...
% g ; g
wait for godot
wait for godot
% history
    1  ls
    2  uptime
    3  echo wait for godot ; echo wait for godot
    4  history

This does not support global aliases, which can appear not just at the beginning of the line or after ;. This code may have other oversights.

With more code you could include the original as a comment (probably with the INTERACTIVE_COMMENTS option set) though this may then require more code on the history search side of things to perhaps strip out those comments:

    ...
    # (z) adds a trailing ; remove that
    cmd[$#cmd]=()
    cmd+=(\# ${1%%$'\n'})
    ...

which at some point might require you to rewrite all the history-saving and history-searching code to suit your specific needs.

  • Thank you so much for the help! I'm going to try this, but also record the command as-typed, if it's different from the expanded command. Is there anything that I should be aware of if I try to do that? Also, do you think it would be possible to do the reverse (store commands in aliased form when typed un-aliased) by borrowing some code from the alias-tips plugin? – Riley Martine Jun 20 '18 at 13:47
  • you can make the history save and history search as complicated as you like... – thrig Jun 20 '18 at 14:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.