6

Suppose I did some time ago cd /path/to/foo/bar and then evince file.pdf. Now if I want to open file.pdf again I have also to do both steps again (using history). However I would do it in a single step. I.e. I want that not evince file.pdf is written to .zsh_history but evince /path/to/foo/bar/file.pdf. How can I achieve this for example by modifying my .zshrc? evince is only an example. It should work with any command.

Should I have any drawbacks in mind with this new behavior?

N.B: Currently I am using z vor cd history and fzf for general history.

4
  • 1
    What if you write echo test $var or echo test.txt $(echo ..) from within /bin? Should it change it to /bin/echo /bin/test /bin/$var (what if $var contains an absolute path), /bin/echo /bin/test.txt / (what if /bin is a symlink to /usr/bin, should that be /usr instead for ..)? Commented Jul 7, 2023 at 7:24
  • Good point. If possible variables maybe could ignored. Symlinks should be expanded.
    – student
    Commented Jul 7, 2023 at 18:01
  • In ls -l --time-style long-iso ls, make CFLAGS=-g file.c install, man zsh, rsync foo bar:baz, env ls..., how is zsh to know which of the arguments are relative paths to files that should be made absolute? That would require knowing (and parsing the same way they do) the full syntax of all the commands available on the system. If you think about it just a few minutes, you'll see it's not realistic. Commented Jul 7, 2023 at 20:57
  • What's about specifying a closed list of commands (e.g. "evince, okular,...") for which zsh should save the complete path?
    – student
    Commented Jul 9, 2023 at 9:49

1 Answer 1

5

That's not something that could be done for arbitrary shell code as zsh has no way to know which of the words in the code are actually arguments that a command would treat as a file path let alone as a path relative to the current working directory at the time the code is stored onto the history.

For the simplest shell code such as cmd with its literal arguments and for a limited predefined set of commands, you could do something like:

commands_with_expanded_paths=(evince okular)
zshaddhistory() {
  local words=( ${(z)1%$'\n'} )
  if (( $commands_with_expanded_paths[(Ie)$words[1]] )); then
    local replaced_words=($words[1]) word
    for word in $words[2,-1]; do
      local decoded_word=${(Q)word}
      if [[ $decoded_word = [^/]* && -e $decoded_word ]]; then
        word=${(q+)decoded_word:P}
      fi
      replaced_words+=($word)
    done
    print -rs -- $replaced_words
    fc -p
  fi
}

Where if the first word is the name of a command in a given list, the remaining arguments are replaced with their absolute path if they're found to be relative paths to existing files in the text saved onto the history.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .