junegunn / fzf-git.sh

bash and zsh key bindings for Git objects, powered by fzf
612 stars 53 forks source link

feat: force pager #51

Closed LangLangBart closed 3 months ago

LangLangBart commented 3 months ago

Description

When you configure core.pager in your global gitconfig file, it allows you to run git commands like git show, and the assigned pager will be used automatically.

brew install diff-so-fancy
git config --global core.pager "diff-so-fancy"
git show @

The problem is that git checks if stdout is a tty[^1] and only then uses the pager; otherwise, it doesn't. Commands run in the fzf preview window fail this tty[^2] test, and thus no pager will be used.

Below the relvant source code snippet from git/git repo with the isatty(1) check.

// git/pager.c
const char *git_pager(int stdout_is_tty)
{
    const char *pager;

    if (!stdout_is_tty)
        return NULL;
    …
}

void setup_pager(void)
{
    const char *pager = git_pager(isatty(1));

    if (!pager)
        return;
    …
}

Unlike the --color=always flag, there is no environment variable or flag that can be passed to force the use of a pager.

Solution

The function __fzf_pager is designed to check whether core.pager, GIT_PAGER, or FZF_PAGER is set, thereby enabling the user to utilize their preferred highlighter, such as delta^3 or diff-so-fancy^4.

export FZF_PAGER="delta"
export FZF_PAGER="diff-so-fancy"

The function and explanation for this PR are inspired by a discussion on the git issue tracker[^5].

--- Personal gitconfig The file is provided only if there is a desire to reproduce the layout seen in the image above. ```cfg [filter "lfs"] clean = git-lfs clean -- %f smudge = git-lfs smudge -- %f process = git-lfs filter-process required = true [user] name = LangLangbart email = ??? [color] ui = auto [core] autocrlf = input editor = codium --wait excludesFile = ~/.gitignore_global pager = delta # https://blog.cuviper.com/2013/11/10/how-short-can-git-abbreviate/ abbrev = 12 [advice] detachedHead = false [interactive] diffFilter = delta --color-only [delta] # author: https://github.com/Kr1ss-XD commit-style = 232 bold italic 130 dark = true file-added-label = [+] file-copied-label = [C] file-modified-label = [M] file-removed-label = [-] file-renamed-label = [R] file-style = 255 bold 27 hunk-header-decoration-style = none hunk-header-style = syntax bold italic 237 line-numbers = true line-numbers-left-format = "{nm:>1}│" line-numbers-left-style = red line-numbers-minus-style = red italic line-numbers-plus-style = green italic line-numbers-right-format = "{np:>1}│" line-numbers-right-style = green line-numbers-zero-style = "#545474" italic minus-emph-style = syntax bold "#780000" minus-style = syntax "#400000" plus-emph-style = syntax bold "#007800" plus-style = syntax "#004000" whitespace-error-style = "#280050" reverse zero-style = syntax blame-format = "{author:<18} ({commit:>7}) ┊{timestamp:^16}┊ " blame-palette = "#101010 #200020 #002800 #000028 #202000 #280000 #002020 #002800 #202020" [diff] colorMoved = default renameLimit = 992 [pull] rebase = merges [log] date = format:%d/%b/%y decorate = auto abbrevCommit = true [init] defaultBranch = main # modify the default hooks in newly cloned or initialized repositories templatedir = ~/.dotfiles/git [push] default = simple [grep] extendedRegexp = true [url "git@github.com:"] insteadOf = https://github.com/ [branch] sort = -committerdate ``` ---

Remaining issues:

[^1]: git/pager.c · git/git [^2]: Issue #1118 · junegunn/fzf

[^5]: Force usage of pager for diff, show, etc when piping to non-TTY · lore.kernel.org

junegunn commented 3 months ago
  • Is it desirable to have such a new function at all, or should the solution be to alter fzf preview window so as to trick git into thinking it is a tty?

I like the approach of this pull request. I'm not sure if it's possible for fzf previewer to disguise itself as a TTY device, and even if it is, it may have unwanted side effects.

  • Should the FZF_PAGER environment variable be described in the README?

Yes, eventually. There are some other undocumented variables. I deliberately left them undocumented because I wasn't absolutely sure if it was a good idea.

  • For the _fzf_git_files function, the sed part was removed as it would alter the diff. A solution would be to include an if check to determine whether the __fzf_pager function returns something other than cat.

I think it's fine to remove it.

LangLangBart commented 3 months ago

I'm not sure if it's possible for fzf previewer to disguise itself as a TTY device

In the git issue tracker thread, it was mentioned, but I've never investigated whether this is even possible with fzf.

[…] There's no way to override it within Git. You'd have to trick Git by opening a pty in the calling program and pumping the data through it (which is what our test suite does; see t/test-terminal.perl).

Source: Re: Force usage of pager for diff, show, etc when piping to non-TTY - Jeff King


I had some minor success using script (I've never used it before):

brew install diff-so-fancy
git config --global core.pager "diff-so-fancy"
: | fzf --preview 'script -q /dev/null git show'

This approach seems to work as a workaround, tricking git into thinking it's outputting to a TTY.

junegunn commented 3 months ago

Yeah, but some programs might try to read user input from the keyboard when they're tricked into thinking that the standard output is a TTY device.

fzf --preview 'script -q /dev/null less {}'
junegunn commented 3 months ago

Merged, thanks!