diff --git a/README.md b/README.md index 6d79886..7c37aa9 100644 --- a/README.md +++ b/README.md @@ -226,9 +226,14 @@ If you want the exact delta configuration I'm using - [it can be found here](htt | i | Cycle icon style | | o | Open file in $EDITOR | | s | Toggle side-by-side/unified view | +| v | Visual select mode (release mouse for native text selection / copy) | | Tab | Switch focus between the panes | | q | Quit | +While mouse capture is on, your terminal can't do its native click-and-drag selection. Press v to enter visual select mode — this releases the mouse so you can select and copy lines from the diff (the footer shows `visual select`); press v again to restore mouse scroll/click. Tip: in side-by-side mode the selection spans both columns — switch to unified with s first, or use your terminal's block-select modifier (Option+drag in iTerm2 / Terminal.app, Alt+drag in many Linux terminals). + +Most terminals (iTerm2, Terminal.app, Alacritty, kitty, WezTerm, GNOME Terminal) also let you hold Shift while dragging to bypass mouse capture without toggling. + ## Discord Have questions? Join our [Discord community](https://discord.gg/SXNXp9NctV)! diff --git a/pkg/ui/keys.go b/pkg/ui/keys.go index 32bb9be..77183a9 100644 --- a/pkg/ui/keys.go +++ b/pkg/ui/keys.go @@ -24,6 +24,7 @@ type KeyMap struct { ToggleIconStyle key.Binding ToggleHelp key.Binding ToggleMessage key.Binding + ToggleMouse key.Binding } var keys = &KeyMap{ @@ -111,6 +112,10 @@ var keys = &KeyMap{ key.WithKeys("m"), key.WithHelp("m", "commit info"), ), + ToggleMouse: key.NewBinding( + key.WithKeys("v"), + key.WithHelp("v", "visual select"), + ), } func KeyGroups() [][]key.Binding { @@ -133,6 +138,7 @@ func KeyGroups() [][]key.Binding { keys.ToggleIconStyle, }, { keys.ToggleMessage, + keys.ToggleMouse, keys.ToggleHelp, keys.Quit, }} diff --git a/pkg/ui/tui.go b/pkg/ui/tui.go index feb7bda..ea35993 100644 --- a/pkg/ui/tui.go +++ b/pkg/ui/tui.go @@ -95,6 +95,7 @@ type mainModel struct { pendingCursorPath string watchInFlight bool repoRoot string + mouseDisabled bool } func New(input string, cfg config.Config) mainModel { @@ -255,6 +256,10 @@ func (m mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.search.SetWidth(m.searchWidth()) dfCmd := m.diffViewer.SetSize(m.width-sidebarWidth, h) cmds = append(cmds, dfCmd) + case key.Matches(msg, keys.ToggleMouse): + m.mouseDisabled = !m.mouseDisabled + m.draggingSidebar = false + return m, tea.Batch(cmds...) case key.Matches(msg, keys.ToggleIconStyle): m.cycleIconStyle() case key.Matches(msg, keys.ToggleDiffView): @@ -488,7 +493,11 @@ func (m mainModel) searchUpdate(msg tea.Msg) (mainModel, []tea.Cmd) { func (m mainModel) View() tea.View { var view tea.View view.AltScreen = true - view.MouseMode = tea.MouseModeAllMotion + if m.mouseDisabled { + view.MouseMode = tea.MouseModeNone + } else { + view.MouseMode = tea.MouseModeAllMotion + } view.KeyboardEnhancements.ReportEventTypes = true // Determine colors based on active panel. @@ -826,6 +835,12 @@ func (m mainModel) footerView() string { usedWidth += lipgloss.Width(sep) + lipgloss.Width(watchLabel) } + if m.mouseDisabled { + mouseLabel := base.Foreground(lipgloss.Yellow).Render("visual select") + parts = append(parts, sep, mouseLabel) + usedWidth += lipgloss.Width(sep) + lipgloss.Width(mouseLabel) + } + spacing := base.Render(strings.Repeat(" ", max(0, m.width-usedWidth))) parts = append(parts, spacing, help) return base.