neogit icon indicating copy to clipboard operation
neogit copied to clipboard

Add support for custom pagers, e.g. *Delta*

Open stevenxxiu opened this issue 1 year ago • 17 comments

This PR resolves #97, to support custom pagers. I made it configurable and tested it with Delta.

For Delta, an example config is:

log_pager = { 'delta', '--width', '117' }

I used baleia to colorize text with ANSI escape sequences.

It's recommended to set disable_context_highlighting = true, otherwise when the cursor is in the hunk, we lose background highlighting.

To set a Delta theme, set the environment variables e.g.

vim.env.BAT_THEME = 'Catppuccin Latte'
vim.env.DELTA_FEATURES = '+catppuccin-latte'

stevenxxiu avatar Dec 08 '24 15:12 stevenxxiu

Very cool work - I didn't think it would be this straightforward.

CKolkey avatar Dec 09 '24 11:12 CKolkey

Do you have a recommended set of flags to use with delta to provide a good output? This is... a bit rough around the edges.

Screenshot 2024-12-13 at 16 29 57

CKolkey avatar Dec 13 '24 15:12 CKolkey

Hm I'm not sure where the strange colors come from. These minimal settings should hopefully work:

I set these options:

  • disable_context_highlighting = true,
  • log_pager = { 'delta', '--width', '117' },

In Git settings:

[delta]
    side-by-side = true

See if that makes it display properly.

stevenxxiu avatar Dec 13 '24 15:12 stevenxxiu

Ok I made a minimal config that's 100% reproducible with Docker. Maybe it's cause you didn't install Bat.

Create this Dockerfile:

# syntax = docker/dockerfile:1.2
FROM alpine:3.21.0

# Install packages
RUN apk add \
    bat \
    delta \
    git \
    neovim

Build and run it:

$ docker build --tag nvim_image .
$ docker container run --detach --rm --interactive --name nvim_container --mount 'type=bind,source=/tmp/nvim/,target=/tmp/nvim/' nvim_image
$ docker container exec --interactive --tty --workdir /tmp/nvim/ nvim_container /bin/sh -l

Create /tmp/nvim/init.lua with the contents:

-- Bootstrap lazy.nvim
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
if not (vim.uv or vim.loop).fs_stat(lazypath) then
  local lazyrepo = 'https://github.com/folke/lazy.nvim.git'
  local out = vim.fn.system({ 'git', 'clone', '--filter=blob:none', '--branch=stable', lazyrepo, lazypath })
  if vim.v.shell_error ~= 0 then
    vim.api.nvim_echo({
      { 'Failed to clone lazy.nvim:\n', 'ErrorMsg' },
      { out, 'WarningMsg' },
      { '\nPress any key to exit...' },
    }, true, {})
    vim.fn.getchar()
    os.exit(1)
  end
end
vim.opt.rtp:prepend(lazypath)

vim.g.mapleader = ' '
vim.g.maplocalleader = '\\'

vim.env.DELTA_FEATURES = '+side-by-side'

-- Setup lazy.nvim
require('lazy').setup({
  spec = {
    {
      dir = '/tmp/nvim/neogit/',
      dependencies = {
        'nvim-lua/plenary.nvim',
        'sindrets/diffview.nvim',
        'm00qek/baleia.nvim',
        'nvim-telescope/telescope.nvim',
      },
      opts = {
        disable_context_highlighting = true,
        graph_style = 'kitty',
        log_pager = { 'delta', '--width', '120' },
        commit_editor = {
          staged_diff_split_kind = 'vsplit_left',
        },
      },
    },
    {
      'm00qek/baleia.nvim',
      version = '*',
      config = function() vim.g.baleia = require('baleia').setup({}) end,
    },
  },
})

vim.cmd('Neogit cwd=/tmp/nvim/neogit/')

In the container run:

$ git clone -b feat/custom-pager --single-branch https://github.com/stevenxxiu/neogit.git
$ nvim -u init.lua

stevenxxiu avatar Dec 14 '24 09:12 stevenxxiu

Any luck on getting this to show properly on your end? I hope my Docker example helps. I can provide a screenshot if needed.

stevenxxiu avatar Dec 15 '24 16:12 stevenxxiu

The docker example is 10/10, but it still looks off to me. Could you show me a screenshot of how it looks for you?

Screenshot 2024-12-15 at 22 12 19

CKolkey avatar Dec 15 '24 21:12 CKolkey

Hi,

I am trying your repository @stevenxxiu (thanks for the pull request!).

It works great with "side-by-side", but without it, I have ^[[0K at the end of lines.

neogit2

misaflo avatar Dec 17 '24 09:12 misaflo

@misaflo I'm guessing baleia doesn't handle this ANSI control sequence. I removed that part of the line now.

stevenxxiu avatar Dec 18 '24 08:12 stevenxxiu

@CKolkey I finally figured the issue out. Turns out for baleia, I used version = "*" in init.lua, so the latest commit wasn't fetched. I'm guessing you did the same.

The following should work now.

Create this Dockerfile. I realize now less is enough. bat isn't required.

# syntax = docker/dockerfile:1.2
FROM alpine:3.21.0

# Install packages
RUN apk add \
    less \
    delta \
    git \
    neovim

Build and run it:

$ docker build --tag nvim_image .
$ docker container run --detach --rm --interactive --name nvim_container --mount 'type=bind,source=/tmp/nvim/,target=/tmp/nvim/' nvim_image
$ docker container exec --interactive --tty --workdir /tmp/nvim/ nvim_container /bin/sh -l

Create /tmp/nvim/init.lua with the contents:

-- Bootstrap lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
  local lazyrepo = "https://github.com/folke/lazy.nvim.git"
  local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
  if vim.v.shell_error ~= 0 then
    vim.api.nvim_echo({
      { "Failed to clone lazy.nvim:\n", "ErrorMsg" },
      { out, "WarningMsg" },
      { "\nPress any key to exit..." },
    }, true, {})
    vim.fn.getchar()
    os.exit(1)
  end
end
vim.opt.rtp:prepend(lazypath)

vim.g.mapleader = " "
vim.g.maplocalleader = "\\"

vim.env.DELTA_FEATURES = "+side-by-side"

-- Setup lazy.nvim
require("lazy").setup({
  spec = {
    {
      dir = "/tmp/nvim/neogit/",
      dependencies = {
        "nvim-lua/plenary.nvim",
        "sindrets/diffview.nvim",
        "m00qek/baleia.nvim",
        "nvim-telescope/telescope.nvim",
      },
      opts = {
        disable_context_highlighting = true,
        graph_style = "kitty",
        log_pager = { "delta", "--width", "119" },
        commit_editor = {
          staged_diff_split_kind = "vsplit_left",
        },
      },
    },
    {
      "m00qek/baleia.nvim",
      config = function()
        vim.g.baleia = require("baleia").setup({})
      end,
    },
  },
})

vim.cmd("Neogit cwd=/tmp/nvim/neogit/")

In the container run:

$ git clone -b feat/custom-pager --single-branch https://github.com/stevenxxiu/neogit.git
$ nvim -u init.lua

stevenxxiu avatar Dec 18 '24 14:12 stevenxxiu

@misaflo I'm guessing baleia doesn't handle this ANSI control sequence. I removed that part of the line now.

It fixes the issue, but introduces an other: it highlights (greeen or red) an extra line, where there is no diff.

misaflo avatar Dec 18 '24 16:12 misaflo

Ok I took a more detailed look. Now it shouldn't affect the next line, but it won't color the rest of the line's background either, like it should in the terminal. That requires baleia to properly support this ANSI escape sequence.

stevenxxiu avatar Dec 18 '24 17:12 stevenxxiu

Oh and here's some screenshots from the Docker config above:

Side by side:

Not side by side:

stevenxxiu avatar Dec 19 '24 08:12 stevenxxiu

I rebased and got unit tests to pass.

stevenxxiu avatar Dec 20 '24 08:12 stevenxxiu

I'll try to do a good review soon as I can. I have some newborns (twin boys) at home right now so bear with me ;)

CKolkey avatar Dec 20 '24 11:12 CKolkey

Congrats on having 2 twin boys! Take your time.

stevenxxiu avatar Dec 20 '24 12:12 stevenxxiu

This is a great work! Looking forward to the merger.

Daydreamer-riri avatar Dec 25 '24 02:12 Daydreamer-riri

When is this going to get merged?

moeabdol avatar Feb 25 '25 14:02 moeabdol

@CKolkey have you had time yet? This still works fine. I rebased pretty much every time there was an update on master.

stevenxxiu avatar Aug 17 '25 10:08 stevenxxiu

@stevenxxiu if this is merged, it will be a replacement for Diffview, right?

tienlonghungson avatar Aug 20 '25 04:08 tienlonghungson

@tienlonghungson Not entirely. I use both. diffview lets me copy text easily from the previous commit's files. This is more a visual tool.

stevenxxiu avatar Aug 20 '25 04:08 stevenxxiu

@stevenxxiu thank you very much for your work here. I've gotten it working perfectly with no rendering issues for previous commit diffs. When I do neogit diff and select unstaged for unstaged commits however, it still uses diffview.nvim

But if i just use :Neogit and look at the unstaged files, it uses delta. Do you know how to make it use delta for unstaged diffs inside the diff menu?

08e4ccee avatar Aug 28 '25 23:08 08e4ccee

Do you know how to make it use delta for unstaged diffs inside the diff menu?

For me that's a way to go explore the diff more deeply, so I prefer using diffview for that.

stevenxxiu avatar Aug 31 '25 08:08 stevenxxiu

@CKolkey any shot to get this merged? would really like to use it.

@stevenxxiu has done a great job and the PR looks quite clean

jorgemmsilva avatar Sep 25 '25 12:09 jorgemmsilva

Hi @stevenxxiu, I encountered an issue: when my cursor is outside the changes block, everything displays correctly. But once I move the cursor into it, the background color for the "Diff" disappears. Syntax highlighting still works, but I can no longer see which line has changed. Could this be a problem with my configuration?

image image

Daydreamer-riri avatar Nov 03 '25 05:11 Daydreamer-riri

@Daydreamer-riri I'm not sure. I don't have this issue with my config. Perhaps create some minimal init.lua that reproduces the issue.

stevenxxiu avatar Nov 03 '25 06:11 stevenxxiu

image image

When I'm using LazyVim's default configuration, only the cursor line is highlighted correctly — and even then, only the foreground color appears as expected, while the background color is off. Could this be related to the highlight group settings?

Daydreamer-riri avatar Nov 03 '25 06:11 Daydreamer-riri

@Daydreamer-riri I can only look into this issue if you give me a minimal init.lua, with only neogit and any dependencies in it, including from this PR.

stevenxxiu avatar Nov 03 '25 06:11 stevenxxiu

Sorry, I didn’t enable disable_context_highlighting — I missed the note about it in the documentation. Everything works fine now.

Daydreamer-riri avatar Nov 03 '25 06:11 Daydreamer-riri

Do I see it correctly that staging particular sections of the diff does no longer work with this?

What I mean is, when I (within a hunk) Select a specific line using Visual (Line) mode, and I hit s, the whole file gets staged. Tested with my normal setup as well as with this minimal docker example

Wikiwix avatar Nov 11 '25 16:11 Wikiwix

What I mean is, when I (within a hunk) Select a specific line using Visual (Line) mode, and I hit s, the whole file gets staged.

That's right. I don't see a way to implement this, as I have to parse the output of the pager.

stevenxxiu avatar Nov 12 '25 03:11 stevenxxiu