3

I'm trying to set the fish history pager to be bat -l fish for syntax highlighting. (i.e. set the PAGER environment variable bat -l fish just for the history command).

I tried:

# 1: alias history "PAGER='bat -l fish' history" # results in "The function “history” calls itself immediately, which would result in an infinite loop" # 2: alias history "PAGER='bat -l fish' \history" # results in the same. # 3: alias _old_history history alias history "PAGER='bat -l fish' _old_history" # results in (line 1): The call stack limit has been exceeded 

I'm aware that abbr works in this case, but this changes my history command, and this is not what I want.

2 Answers 2

5

Two things are happening here:

  1. fish's alias actually creates a function.
  2. fish ships with a default history function already.

So when you write

alias history "PAGER='bat -l fish' history" 

what you actually have is the recursive function

function history PAGER='bat -l fish' history $argv end 

Some solutions:

  1. use a different name for your alias

    alias hist 'PAGER="bat -l fish" history' 
  2. Don't alias _old_history hist, but copy it instead

    functions --copy history _old_history alias history 'PAGER="bat -l fish" _old_history' 
  3. If you don't care to keep fish's function, invoke the builtin history command in your own function

    function history builtin history $argv | bat -l fish end 

why doesn't the builtin history support pager?

I assume the fish designers didn't think that was a core part of the history functionality. I assume they put the user-facing stuff in a function that users can override.

Here's the relevant snippet from the default history function:

 case search # search the interactive command history test -z "$search_mode" and set search_mode --contains if isatty stdout set -l pager (__fish_anypager) and isatty stdout or set pager cat # If the user hasn't preconfigured less with the $LESS environment variable, # we do so to have it behave like cat if output fits on one screen. if not set -qx LESS set -x LESS --quit-if-one-screen # Also set --no-init for less < v530, see #8157. if type -q less; and test (less --version | string match -r 'less (\d+)')[2] -lt 530 2>/dev/null set -x LESS $LESS --no-init end end not set -qx LV # ask the pager lv not to strip colors and set -x LV -c builtin history search $search_mode $show_time $max_count $_flag_case_sensitive $_flag_reverse $_flag_null -- $argv | $pager else builtin history search $search_mode $show_time $max_count $_flag_case_sensitive $_flag_reverse $_flag_null -- $argv end 
1
  • Wow, I didn't know about the builtin keyword The third solution indeed seems to be the simplest. I'm curious, why doesn't the builtin history support pager? Commented Jun 13, 2024 at 12:52
1

I succeeded using functions -c to copy the built-in history function. Turns out alias was just creating an history function that calls itself, while functions -c fully copies the function.

functions -c history _old_history alias history "PAGER='bat -l fish' _old_history" 

(here is the final version I ended up using in my config:

functions -c history old_history alias history 'PAGER="bat --file-name \"fish history\" -l fish" old_history' 

)

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.