From 6fbd99a127867cd612bc2103805576bfbab32f38 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 8 Feb 2025 21:08:28 +0100 Subject: [PATCH] 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) --- docs/Config.md | 5 +++ pkg/config/user_config.go | 13 ++++++ .../helpers/patch_building_helper.go | 2 +- pkg/gui/controllers/helpers/staging_helper.go | 6 ++- pkg/gui/patch_exploring/state.go | 44 ++++++++++++++++++- schema/config.json | 9 ++++ 6 files changed, 74 insertions(+), 5 deletions(-) diff --git a/docs/Config.md b/docs/Config.md index d27050da058..d6e0d207442 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -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 diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 116f634875c..f1f8f92b3dd 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -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' diff --git a/pkg/gui/controllers/helpers/patch_building_helper.go b/pkg/gui/controllers/helpers/patch_building_helper.go index cde561fbcf3..ee07f2f7c9a 100644 --- a/pkg/gui/controllers/helpers/patch_building_helper.go +++ b/pkg/gui/controllers/helpers/patch_building_helper.go @@ -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() diff --git a/pkg/gui/controllers/helpers/staging_helper.go b/pkg/gui/controllers/helpers/staging_helper.go index 69760a1939a..8a0c61efbd7 100644 --- a/pkg/gui/controllers/helpers/staging_helper.go +++ b/pkg/gui/controllers/helpers/staging_helper.go @@ -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() diff --git a/pkg/gui/patch_exploring/state.go b/pkg/gui/patch_exploring/state.go index 074793f8e48..dae808f208c 100644 --- a/pkg/gui/patch_exploring/state.go +++ b/pkg/gui/patch_exploring/state.go @@ -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, diff --git a/schema/config.json b/schema/config.json index cbb41866741..670f2e07d6d 100644 --- a/schema/config.json +++ b/schema/config.json @@ -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).",