WIP Add config pagerForStaging

Problems:
- sometimes the wrapping is off; I suspect Decolorize is missing some cases
- in the patch building panel, only shows the formatted diff as long as nothing
  has been staged, because then it wants to color the line starts of the
  included lines
- with delta, selection is almost invisible because we are only changing the
  background color, but delta colors the background too (diff-so-fancy doesn't)
This commit is contained in:
Stefan Haller 2025-02-08 21:08:28 +01:00
parent 4e38a941de
commit 6fbd99a127
6 changed files with 74 additions and 5 deletions

View file

@ -280,6 +280,11 @@ git:
# ydiff -p cat -s --wrap --width={{columnWidth}}
pager: ""
# e.g.
# delta --dark --paging=never --color-only
# diff-so-fancy --patch
pagerForStaging: ""
# If true, Lazygit will use whatever pager is specified in `$GIT_PAGER`, `$PAGER`, or your *git config*. If the pager ends with something like ` | less` we will strip that part out, because less doesn't play nice with our rendering approach. If the custom pager uses less under the hood, that will also break rendering (hence the `--paging=never` flag for the `delta` pager).
useConfig: false

View file

@ -284,6 +284,15 @@ func (PagerType) JSONSchemaExtend(schema *jsonschema.Schema) {
}
}
type PagerForStagingType string
func (PagerForStagingType) JSONSchemaExtend(schema *jsonschema.Schema) {
schema.Examples = []any{
"delta --dark --paging=never --color-only",
"diff-so-fancy --patch",
}
}
type PagingConfig struct {
// Value of the --color arg in the git diff command. Some pagers want this to be set to 'always' and some want it set to 'never'
ColorArg string `yaml:"colorArg" jsonschema:"enum=always,enum=never"`
@ -292,6 +301,10 @@ type PagingConfig struct {
// delta --dark --paging=never
// ydiff -p cat -s --wrap --width={{columnWidth}}
Pager PagerType `yaml:"pager"`
// e.g.
// delta --dark --paging=never --color-only
// diff-so-fancy --patch
PagerForStaging PagerForStagingType `yaml:"pagerForStaging"`
// If true, Lazygit will use whatever pager is specified in `$GIT_PAGER`, `$PAGER`, or your *git config*. If the pager ends with something like ` | less` we will strip that part out, because less doesn't play nice with our rendering approach. If the custom pager uses less under the hood, that will also break rendering (hence the `--paging=never` flag for the `delta` pager).
UseConfig bool `yaml:"useConfig"`
// e.g. 'difft --color=always'

View file

@ -91,7 +91,7 @@ func (self *PatchBuildingHelper) RefreshPatchBuildingPanel(opts types.OnFocusOpt
oldState := context.GetState()
state := patch_exploring.NewState(diff, selectedLineIdx, context.GetView(), oldState)
state := patch_exploring.NewState(diff, selectedLineIdx, context.GetView(), oldState, string(self.c.UserConfig().Git.Paging.PagerForStaging))
context.SetState(state)
if state == nil {
self.Escape()

View file

@ -62,12 +62,14 @@ func (self *StagingHelper) RefreshStagingPanel(focusOpts types.OnFocusOpts) {
mainContext.GetMutex().Lock()
secondaryContext.GetMutex().Lock()
pagerCommand := string(self.c.UserConfig().Git.Paging.PagerForStaging)
mainContext.SetState(
patch_exploring.NewState(mainDiff, mainSelectedLineIdx, mainContext.GetView(), mainContext.GetState()),
patch_exploring.NewState(mainDiff, mainSelectedLineIdx, mainContext.GetView(), mainContext.GetState(), pagerCommand),
)
secondaryContext.SetState(
patch_exploring.NewState(secondaryDiff, secondarySelectedLineIdx, secondaryContext.GetView(), secondaryContext.GetState()),
patch_exploring.NewState(secondaryDiff, secondarySelectedLineIdx, secondaryContext.GetView(), secondaryContext.GetState(), pagerCommand),
)
mainState := mainContext.GetState()

View file

@ -1,12 +1,16 @@
package patch_exploring
import (
"bytes"
"io"
"os/exec"
"strings"
"github.com/jesseduffield/generics/set"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/patch"
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/mgutz/str"
)
// State represents the current state of the patch explorer context i.e. when
@ -20,6 +24,7 @@ type State struct {
// Otherwise, we cancel the range when we move up or down.
rangeIsSticky bool
diff string
diffFromPager string
patch *patch.Patch
selectMode selectMode
@ -38,7 +43,7 @@ const (
HUNK
)
func NewState(diff string, selectedLineIdx int, view *gocui.View, oldState *State) *State {
func NewState(diff string, selectedLineIdx int, view *gocui.View, oldState *State, pagerCommand string) *State {
if oldState != nil && diff == oldState.diff && selectedLineIdx == -1 {
// if we're here then we can return the old state. If selectedLineIdx was not -1
// then that would mean we were trying to click and potentially drag a range, which
@ -52,7 +57,13 @@ func NewState(diff string, selectedLineIdx int, view *gocui.View, oldState *Stat
return nil
}
viewLineIndices, patchLineIndices := wrapPatchLines(diff, view)
diffFromPager := formatDiffForStaging(diff, pagerCommand)
diffToWrap := diff
if len(diffFromPager) > 0 {
diffToWrap = utils.Decolorise(diffFromPager)
}
viewLineIndices, patchLineIndices := wrapPatchLines(diffToWrap, view)
rangeStartLineIdx := 0
if oldState != nil {
@ -85,11 +96,37 @@ func NewState(diff string, selectedLineIdx int, view *gocui.View, oldState *Stat
rangeStartLineIdx: rangeStartLineIdx,
rangeIsSticky: false,
diff: diff,
diffFromPager: diffFromPager,
viewLineIndices: viewLineIndices,
patchLineIndices: patchLineIndices,
}
}
func formatDiffForStaging(diff string, pagerCommand string) string {
if len(pagerCommand) == 0 {
return ""
}
args := str.ToArgv(pagerCommand)
cmd := exec.Command(args[0], args[1:]...)
var stdout bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = io.Discard
cmd.Stdin = strings.NewReader(diff)
err := cmd.Run()
if err != nil {
// TODO report error somehow
return ""
}
diffFromPager := stdout.String()
if len(strings.Split(diffFromPager, "\n")) != len(strings.Split(diff, "\n")) {
// TODO report error somehow
return ""
}
return diffFromPager
}
func (s *State) OnViewWidthChanged(view *gocui.View) {
if !view.Wrap {
return
@ -294,6 +331,9 @@ func (s *State) AdjustSelectedLineIdx(change int) {
}
func (s *State) RenderForLineIndices(includedLineIndices []int) string {
if includedLineIndices == nil && len(s.diffFromPager) > 0 {
return s.diffFromPager
}
includedLineIndicesSet := set.NewFromSlice(includedLineIndices)
return s.patch.FormatView(patch.FormatViewOpts{
IncLineIndices: includedLineIndicesSet,

View file

@ -1548,6 +1548,15 @@
"ydiff -p cat -s --wrap --width={{columnWidth}}"
]
},
"pagerForStaging": {
"type": "string",
"description": "e.g.\ndelta --dark --paging=never --color-only\ndiff-so-fancy --patch",
"default": "",
"examples": [
"delta --dark --paging=never --color-only",
"diff-so-fancy --patch"
]
},
"useConfig": {
"type": "boolean",
"description": "If true, Lazygit will use whatever pager is specified in `$GIT_PAGER`, `$PAGER`, or your *git config*. If the pager ends with something like ` | less` we will strip that part out, because less doesn't play nice with our rendering approach. If the custom pager uses less under the hood, that will also break rendering (hence the `--paging=never` flag for the `delta` pager).",