diff --git a/docs/Config.md b/docs/Config.md index 96c96a410..925ceb1b3 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -116,6 +116,9 @@ gui: # paragraphs of markdown text. wrapLinesInStagingView: true + # If true, hunk selection mode will be enabled by default when entering the staging view. + useHunkModeInStagingView: false + # One of 'auto' (default) | 'en' | 'zh-CN' | 'zh-TW' | 'pl' | 'nl' | 'ja' | 'ko' | 'ru' language: auto diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 8e940b6fa..d490e3e10 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -107,6 +107,8 @@ type GuiConfig struct { // makes it much easier to work with diffs that have long lines, e.g. // paragraphs of markdown text. WrapLinesInStagingView bool `yaml:"wrapLinesInStagingView"` + // If true, hunk selection mode will be enabled by default when entering the staging view. + UseHunkModeInStagingView bool `yaml:"useHunkModeInStagingView"` // One of 'auto' (default) | 'en' | 'zh-CN' | 'zh-TW' | 'pl' | 'nl' | 'ja' | 'ko' | 'ru' Language string `yaml:"language" jsonschema:"enum=auto,enum=en,enum=zh-TW,enum=zh-CN,enum=pl,enum=nl,enum=ja,enum=ko,enum=ru"` // Format used when displaying time e.g. commit time. @@ -745,6 +747,7 @@ func GetDefaultConfig() *UserConfig { MainPanelSplitMode: "flexible", EnlargedSideViewLocation: "left", WrapLinesInStagingView: true, + UseHunkModeInStagingView: false, Language: "auto", TimeFormat: "02 Jan 06", ShortTimeFormat: time.Kitchen, diff --git a/pkg/gui/controllers/helpers/patch_building_helper.go b/pkg/gui/controllers/helpers/patch_building_helper.go index 116e8b293..c69435954 100644 --- a/pkg/gui/controllers/helpers/patch_building_helper.go +++ b/pkg/gui/controllers/helpers/patch_building_helper.go @@ -84,7 +84,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, self.c.UserConfig().Gui.UseHunkModeInStagingView) 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 3d9762541..55b9c133b 100644 --- a/pkg/gui/controllers/helpers/staging_helper.go +++ b/pkg/gui/controllers/helpers/staging_helper.go @@ -62,12 +62,13 @@ func (self *StagingHelper) RefreshStagingPanel(focusOpts types.OnFocusOpts) { mainContext.GetMutex().Lock() secondaryContext.GetMutex().Lock() + hunkMode := self.c.UserConfig().Gui.UseHunkModeInStagingView mainContext.SetState( - patch_exploring.NewState(mainDiff, mainSelectedLineIdx, mainContext.GetView(), mainContext.GetState()), + patch_exploring.NewState(mainDiff, mainSelectedLineIdx, mainContext.GetView(), mainContext.GetState(), hunkMode), ) secondaryContext.SetState( - patch_exploring.NewState(secondaryDiff, secondarySelectedLineIdx, secondaryContext.GetView(), secondaryContext.GetState()), + patch_exploring.NewState(secondaryDiff, secondarySelectedLineIdx, secondaryContext.GetView(), secondaryContext.GetState(), hunkMode), ) mainState := mainContext.GetState() diff --git a/pkg/gui/controllers/patch_building_controller.go b/pkg/gui/controllers/patch_building_controller.go index faddbd5f8..166cc4a2b 100644 --- a/pkg/gui/controllers/patch_building_controller.go +++ b/pkg/gui/controllers/patch_building_controller.go @@ -134,7 +134,7 @@ func (self *PatchBuildingController) toggleSelection() error { state := self.context().GetState() // Get added/deleted lines in the selected patch range - lineIndicesToToggle := state.ChangeLinesInSelectedPatchRange() + lineIndicesToToggle := state.LineIndicesOfAddedOrDeletedLinesInSelectedPatchRange() if len(lineIndicesToToggle) == 0 { // Only context lines or header lines selected, so nothing to do return nil @@ -170,7 +170,7 @@ func (self *PatchBuildingController) Escape() error { context := self.c.Contexts().CustomPatchBuilder state := context.GetState() - if state.SelectingRange() || state.SelectingHunk() { + if state.SelectingRange() || state.SelectingHunkEnabledByUser() { state.SetLineSelectMode() self.c.PostRefreshUpdate(context) return nil diff --git a/pkg/gui/controllers/staging_controller.go b/pkg/gui/controllers/staging_controller.go index 6b251883b..44bcffb19 100644 --- a/pkg/gui/controllers/staging_controller.go +++ b/pkg/gui/controllers/staging_controller.go @@ -168,7 +168,7 @@ func (self *StagingController) EditFile() error { } func (self *StagingController) Escape() error { - if self.context.GetState().SelectingRange() || self.context.GetState().SelectingHunk() { + if self.context.GetState().SelectingRange() || self.context.GetState().SelectingHunkEnabledByUser() { self.context.GetState().SetLineSelectMode() self.c.PostRefreshUpdate(self.context) return nil diff --git a/pkg/gui/patch_exploring/state.go b/pkg/gui/patch_exploring/state.go index acf2b0ef2..6223a9979 100644 --- a/pkg/gui/patch_exploring/state.go +++ b/pkg/gui/patch_exploring/state.go @@ -28,6 +28,12 @@ type State struct { viewLineIndices []int // Array of indices of the original patch lines indexed by a wrapped view line index patchLineIndices []int + + // whether the user has switched to hunk mode manually; if hunk mode is on + // but this is false, then hunk mode was enabled because the config makes it + // on by default. + // this makes a difference for whether we want to escape out of hunk mode + userEnabledHunkMode bool } // these represent what select mode we're in @@ -39,7 +45,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, useHunkModeByDefault bool) *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 @@ -61,6 +67,15 @@ func NewState(diff string, selectedLineIdx int, view *gocui.View, oldState *Stat } selectMode := LINE + if useHunkModeByDefault { + selectMode = HUNK + } + + userEnabledHunkMode := false + if oldState != nil { + userEnabledHunkMode = oldState.userEnabledHunkMode + } + // if we have clicked from the outside to focus the main view we'll pass in a non-negative line index so that we can instantly select that line if selectedLineIdx >= 0 { // Clamp to the number of wrapped view lines; index might be out of @@ -70,9 +85,9 @@ func NewState(diff string, selectedLineIdx int, view *gocui.View, oldState *Stat selectMode = RANGE rangeStartLineIdx = selectedLineIdx } else if oldState != nil { - // if we previously had a selectMode of RANGE, we want that to now be line again - if oldState.selectMode == HUNK { - selectMode = HUNK + // if we previously had a selectMode of RANGE, we want that to now be line again (or hunk, if that's the default) + if oldState.selectMode != RANGE { + selectMode = oldState.selectMode } selectedLineIdx = viewLineIndices[patch.GetNextChangeIdx(oldState.patchLineIndices[oldState.selectedLineIdx])] } else { @@ -80,14 +95,15 @@ func NewState(diff string, selectedLineIdx int, view *gocui.View, oldState *Stat } return &State{ - patch: patch, - selectedLineIdx: selectedLineIdx, - selectMode: selectMode, - rangeStartLineIdx: rangeStartLineIdx, - rangeIsSticky: false, - diff: diff, - viewLineIndices: viewLineIndices, - patchLineIndices: patchLineIndices, + patch: patch, + selectedLineIdx: selectedLineIdx, + selectMode: selectMode, + rangeStartLineIdx: rangeStartLineIdx, + rangeIsSticky: false, + diff: diff, + viewLineIndices: viewLineIndices, + patchLineIndices: patchLineIndices, + userEnabledHunkMode: userEnabledHunkMode, } } @@ -125,6 +141,7 @@ func (s *State) ToggleSelectHunk() { s.selectMode = LINE } else { s.selectMode = HUNK + s.userEnabledHunkMode = true // If we are not currently on a change line, select the next one (or the // previous one if there is no next one): @@ -155,6 +172,10 @@ func (s *State) SelectingHunk() bool { return s.selectMode == HUNK } +func (s *State) SelectingHunkEnabledByUser() bool { + return s.selectMode == HUNK && s.userEnabledHunkMode +} + func (s *State) SelectingRange() bool { return s.selectMode == RANGE && (s.rangeIsSticky || s.rangeStartLineIdx != s.selectedLineIdx) } @@ -335,7 +356,7 @@ func (s *State) SelectedPatchRange() (int, int) { } // Returns the line indices of the selected patch range that are changes (i.e. additions or deletions) -func (s *State) ChangeLinesInSelectedPatchRange() []int { +func (s *State) LineIndicesOfAddedOrDeletedLinesInSelectedPatchRange() []int { viewStart, viewEnd := s.SelectedViewRange() patchStart, patchEnd := s.patchLineIndices[viewStart], s.patchLineIndices[viewEnd] lines := s.patch.Lines() diff --git a/schema/config.json b/schema/config.json index 4e63e6087..520f2e0c6 100644 --- a/schema/config.json +++ b/schema/config.json @@ -530,6 +530,11 @@ "description": "If true, wrap lines in the staging view to the width of the view. This\nmakes it much easier to work with diffs that have long lines, e.g.\nparagraphs of markdown text.", "default": true }, + "useHunkModeInStagingView": { + "type": "boolean", + "description": "If true, hunk selection mode will be enabled by default when entering the staging view.", + "default": false + }, "language": { "type": "string", "enum": [