detached e1760bf

refactor(input): use context-based logging pattern and reduce debug verbosity

commit
e1760bf8643eee6ffd3ee3bead538261c10b5d99
author
brice · · 2025-12-11 17:58 UTC
committer
brice · · 2025-12-11 17:25 UTC
parent
5884f49
signature
unsigned
3 files · +60 -52
M internal/ui/input/keyboard.go +2 -2
@@ -41,8 +41,8 @@ func NewKeyboardHandler(
4141 logger *zerolog.Logger,
4242 ) *KeyboardHandler {
4343 h := &KeyboardHandler{
44- shortcuts: NewShortcutSet(cfg, logger),
45- modal: NewModalState(logger),
44+ shortcuts: NewShortcutSet(ctx, cfg),
45+ modal: NewModalState(ctx),
4646 cfg: cfg,
4747 ctx: ctx,
4848 logger: logger,
@@ -41,8 +41,8 @@ func NewKeyboardHandler(
41 logger *zerolog.Logger,41 logger *zerolog.Logger,
42 ) *KeyboardHandler {42 ) *KeyboardHandler {
43 h := &KeyboardHandler{43 h := &KeyboardHandler{
44- shortcuts: NewShortcutSet(cfg, logger),44+ shortcuts: NewShortcutSet(ctx, cfg),
45- modal: NewModalState(logger),45+ modal: NewModalState(ctx),
46 cfg: cfg,46 cfg: cfg,
47 ctx: ctx,47 ctx: ctx,
48 logger: logger,48 logger: logger,
M internal/ui/input/modal.go +24 -26
@@ -1,10 +1,11 @@
11 package input
22
33 import (
4+ "context"
45 "sync"
56 "time"
67
7- "github.com/rs/zerolog"
8+ "github.com/bnema/dumber/internal/logging"
89 )
910
1011 // Mode represents the current input mode.
@@ -42,15 +43,15 @@ type ModalState struct {
4243 // Callback for mode changes (called synchronously under lock).
4344 onModeChange func(from, to Mode)
4445
45- logger *zerolog.Logger
46- mu sync.RWMutex
46+ ctx context.Context
47+ mu sync.RWMutex
4748 }
4849
4950 // NewModalState creates a new modal state manager.
50-func NewModalState(logger *zerolog.Logger) *ModalState {
51+func NewModalState(ctx context.Context) *ModalState {
5152 return &ModalState{
52- mode: ModeNormal,
53- logger: logger,
53+ mode: ModeNormal,
54+ ctx: ctx,
5455 }
5556 }
5657
@@ -64,6 +65,7 @@ func (m *ModalState) Mode() Mode {
6465 // EnterTabMode switches to tab mode with an optional timeout.
6566 // If timeout is 0, the mode stays until explicitly exited.
6667 func (m *ModalState) EnterTabMode(timeout time.Duration) {
68+ log := logging.FromContext(m.ctx)
6769 m.mu.Lock()
6870 defer m.mu.Unlock()
6971
@@ -84,13 +86,11 @@ func (m *ModalState) EnterTabMode(timeout time.Duration) {
8486 })
8587 }
8688
87- if m.logger != nil {
88- m.logger.Debug().
89- Str("from", oldMode.String()).
90- Str("to", m.mode.String()).
91- Dur("timeout", timeout).
92- Msg("entered tab mode")
93- }
89+ log.Debug().
90+ Str("from", oldMode.String()).
91+ Str("to", m.mode.String()).
92+ Dur("timeout", timeout).
93+ Msg("entered tab mode")
9494
9595 if m.onModeChange != nil {
9696 m.onModeChange(oldMode, m.mode)
@@ -100,6 +100,7 @@ func (m *ModalState) EnterTabMode(timeout time.Duration) {
100100 // EnterPaneMode switches to pane mode with an optional timeout.
101101 // If timeout is 0, the mode stays until explicitly exited.
102102 func (m *ModalState) EnterPaneMode(timeout time.Duration) {
103+ log := logging.FromContext(m.ctx)
103104 m.mu.Lock()
104105 defer m.mu.Unlock()
105106
@@ -120,13 +121,11 @@ func (m *ModalState) EnterPaneMode(timeout time.Duration) {
120121 })
121122 }
122123
123- if m.logger != nil {
124- m.logger.Debug().
125- Str("from", oldMode.String()).
126- Str("to", m.mode.String()).
127- Dur("timeout", timeout).
128- Msg("entered pane mode")
129- }
124+ log.Debug().
125+ Str("from", oldMode.String()).
126+ Str("to", m.mode.String()).
127+ Dur("timeout", timeout).
128+ Msg("entered pane mode")
130129
131130 if m.onModeChange != nil {
132131 m.onModeChange(oldMode, m.mode)
@@ -135,6 +134,7 @@ func (m *ModalState) EnterPaneMode(timeout time.Duration) {
135134
136135 // ExitMode returns to normal mode.
137136 func (m *ModalState) ExitMode() {
137+ log := logging.FromContext(m.ctx)
138138 m.mu.Lock()
139139 defer m.mu.Unlock()
140140
@@ -147,12 +147,10 @@ func (m *ModalState) ExitMode() {
147147 m.mode = ModeNormal
148148 m.timeout = 0
149149
150- if m.logger != nil {
151- m.logger.Debug().
152- Str("from", oldMode.String()).
153- Str("to", "normal").
154- Msg("exited modal mode")
155- }
150+ log.Debug().
151+ Str("from", oldMode.String()).
152+ Str("to", "normal").
153+ Msg("exited modal mode")
156154
157155 if m.onModeChange != nil {
158156 m.onModeChange(oldMode, ModeNormal)
@@ -1,10 +1,11 @@
1 package input1 package input
2 2
3 import (3 import (
4+ "context"
4 "sync"5 "sync"
5 "time"6 "time"
6 7
7- "github.com/rs/zerolog"8+ "github.com/bnema/dumber/internal/logging"
8 )9 )
9 10
10 // Mode represents the current input mode.11 // Mode represents the current input mode.
@@ -42,15 +43,15 @@ type ModalState struct {
42 // Callback for mode changes (called synchronously under lock).43 // Callback for mode changes (called synchronously under lock).
43 onModeChange func(from, to Mode)44 onModeChange func(from, to Mode)
44 45
45- logger *zerolog.Logger46+ ctx context.Context
46- mu sync.RWMutex47+ mu sync.RWMutex
47 }48 }
48 49
49 // NewModalState creates a new modal state manager.50 // NewModalState creates a new modal state manager.
50-func NewModalState(logger *zerolog.Logger) *ModalState {51+func NewModalState(ctx context.Context) *ModalState {
51 return &ModalState{52 return &ModalState{
52- mode: ModeNormal,53+ mode: ModeNormal,
53- logger: logger,54+ ctx: ctx,
54 }55 }
55 }56 }
56 57
@@ -64,6 +65,7 @@ func (m *ModalState) Mode() Mode {
64 // EnterTabMode switches to tab mode with an optional timeout.65 // EnterTabMode switches to tab mode with an optional timeout.
65 // If timeout is 0, the mode stays until explicitly exited.66 // If timeout is 0, the mode stays until explicitly exited.
66 func (m *ModalState) EnterTabMode(timeout time.Duration) {67 func (m *ModalState) EnterTabMode(timeout time.Duration) {
68+ log := logging.FromContext(m.ctx)
67 m.mu.Lock()69 m.mu.Lock()
68 defer m.mu.Unlock()70 defer m.mu.Unlock()
69 71
@@ -84,13 +86,11 @@ func (m *ModalState) EnterTabMode(timeout time.Duration) {
84 })86 })
85 }87 }
86 88
87- if m.logger != nil {89+ log.Debug().
88- m.logger.Debug().90+ Str("from", oldMode.String()).
89- Str("from", oldMode.String()).91+ Str("to", m.mode.String()).
90- Str("to", m.mode.String()).92+ Dur("timeout", timeout).
91- Dur("timeout", timeout).93+ Msg("entered tab mode")
92- Msg("entered tab mode")
93- }
94 94
95 if m.onModeChange != nil {95 if m.onModeChange != nil {
96 m.onModeChange(oldMode, m.mode)96 m.onModeChange(oldMode, m.mode)
@@ -100,6 +100,7 @@ func (m *ModalState) EnterTabMode(timeout time.Duration) {
100 // EnterPaneMode switches to pane mode with an optional timeout.100 // EnterPaneMode switches to pane mode with an optional timeout.
101 // If timeout is 0, the mode stays until explicitly exited.101 // If timeout is 0, the mode stays until explicitly exited.
102 func (m *ModalState) EnterPaneMode(timeout time.Duration) {102 func (m *ModalState) EnterPaneMode(timeout time.Duration) {
103+ log := logging.FromContext(m.ctx)
103 m.mu.Lock()104 m.mu.Lock()
104 defer m.mu.Unlock()105 defer m.mu.Unlock()
105 106
@@ -120,13 +121,11 @@ func (m *ModalState) EnterPaneMode(timeout time.Duration) {
120 })121 })
121 }122 }
122 123
123- if m.logger != nil {124+ log.Debug().
124- m.logger.Debug().125+ Str("from", oldMode.String()).
125- Str("from", oldMode.String()).126+ Str("to", m.mode.String()).
126- Str("to", m.mode.String()).127+ Dur("timeout", timeout).
127- Dur("timeout", timeout).128+ Msg("entered pane mode")
128- Msg("entered pane mode")
129- }
130 129
131 if m.onModeChange != nil {130 if m.onModeChange != nil {
132 m.onModeChange(oldMode, m.mode)131 m.onModeChange(oldMode, m.mode)
@@ -135,6 +134,7 @@ func (m *ModalState) EnterPaneMode(timeout time.Duration) {
135 134
136 // ExitMode returns to normal mode.135 // ExitMode returns to normal mode.
137 func (m *ModalState) ExitMode() {136 func (m *ModalState) ExitMode() {
137+ log := logging.FromContext(m.ctx)
138 m.mu.Lock()138 m.mu.Lock()
139 defer m.mu.Unlock()139 defer m.mu.Unlock()
140 140
@@ -147,12 +147,10 @@ func (m *ModalState) ExitMode() {
147 m.mode = ModeNormal147 m.mode = ModeNormal
148 m.timeout = 0148 m.timeout = 0
149 149
150- if m.logger != nil {150+ log.Debug().
151- m.logger.Debug().151+ Str("from", oldMode.String()).
152- Str("from", oldMode.String()).152+ Str("to", "normal").
153- Str("to", "normal").153+ Msg("exited modal mode")
154- Msg("exited modal mode")
155- }
156 154
157 if m.onModeChange != nil {155 if m.onModeChange != nil {
158 m.onModeChange(oldMode, ModeNormal)156 m.onModeChange(oldMode, ModeNormal)
M internal/ui/input/shortcuts.go +34 -24
@@ -2,11 +2,12 @@
22 package input
33
44 import (
5+ "context"
56 "strings"
67
78 "github.com/bnema/dumber/internal/infrastructure/config"
9+ "github.com/bnema/dumber/internal/logging"
810 "github.com/jwijenbergh/puregotk/v4/gdk"
9- "github.com/rs/zerolog"
1011 )
1112
1213 // Modifier represents keyboard modifier flags.
@@ -95,42 +96,41 @@ type ShortcutSet struct {
9596 TabMode ShortcutTable
9697 // PaneMode shortcuts are only active in pane mode.
9798 PaneMode ShortcutTable
98-
99- logger *zerolog.Logger
10099 }
101100
102101 // NewShortcutSet creates a ShortcutSet from the workspace configuration.
103-func NewShortcutSet(cfg *config.WorkspaceConfig, logger *zerolog.Logger) *ShortcutSet {
102+func NewShortcutSet(ctx context.Context, cfg *config.WorkspaceConfig) *ShortcutSet {
103+ log := logging.FromContext(ctx)
104104 set := &ShortcutSet{
105105 Global: make(ShortcutTable),
106106 TabMode: make(ShortcutTable),
107107 PaneMode: make(ShortcutTable),
108- logger: logger,
109108 }
110109
111- set.buildGlobalShortcuts(cfg)
112- set.buildTabModeShortcuts(cfg)
113- set.buildPaneModeShortcuts(cfg)
110+ set.buildGlobalShortcuts(ctx, cfg)
111+ set.buildTabModeShortcuts(ctx, cfg)
112+ set.buildPaneModeShortcuts(ctx, cfg)
114113
115- logger.Debug().Int("global", len(set.Global)).Int("tab", len(set.TabMode)).Int("pane", len(set.PaneMode)).Msg("shortcuts registered")
114+ log.Debug().Int("global", len(set.Global)).Int("tab", len(set.TabMode)).Int("pane", len(set.PaneMode)).Msg("shortcuts registered")
116115
117116 return set
118117 }
119118
120119 // buildGlobalShortcuts populates global shortcuts from config.
121-func (s *ShortcutSet) buildGlobalShortcuts(cfg *config.WorkspaceConfig) {
120+func (s *ShortcutSet) buildGlobalShortcuts(ctx context.Context, cfg *config.WorkspaceConfig) {
121+ log := logging.FromContext(ctx)
122122 // Mode entry from activation shortcuts
123123 if binding, ok := ParseKeyString(cfg.TabMode.ActivationShortcut); ok {
124124 s.Global[binding] = ActionEnterTabMode
125- s.logger.Debug().Str("shortcut", cfg.TabMode.ActivationShortcut).Uint("keyval", binding.Keyval).Uint("mod", uint(binding.Modifiers)).Msg("tab mode activation registered")
125+ log.Trace().Str("shortcut", cfg.TabMode.ActivationShortcut).Uint("keyval", binding.Keyval).Uint("mod", uint(binding.Modifiers)).Msg("tab mode activation registered")
126126 } else {
127- s.logger.Warn().Str("shortcut", cfg.TabMode.ActivationShortcut).Msg("failed to parse tab mode activation shortcut")
127+ log.Warn().Str("shortcut", cfg.TabMode.ActivationShortcut).Msg("failed to parse tab mode activation shortcut")
128128 }
129129 if binding, ok := ParseKeyString(cfg.PaneMode.ActivationShortcut); ok {
130130 s.Global[binding] = ActionEnterPaneMode
131- s.logger.Debug().Str("shortcut", cfg.PaneMode.ActivationShortcut).Uint("keyval", binding.Keyval).Uint("mod", uint(binding.Modifiers)).Msg("pane mode activation registered")
131+ log.Trace().Str("shortcut", cfg.PaneMode.ActivationShortcut).Uint("keyval", binding.Keyval).Uint("mod", uint(binding.Modifiers)).Msg("pane mode activation registered")
132132 } else {
133- s.logger.Warn().Str("shortcut", cfg.PaneMode.ActivationShortcut).Msg("failed to parse pane mode activation shortcut")
133+ log.Warn().Str("shortcut", cfg.PaneMode.ActivationShortcut).Msg("failed to parse pane mode activation shortcut")
134134 }
135135
136136 // Tab shortcuts from TabKeyConfig
@@ -165,39 +165,49 @@ func (s *ShortcutSet) buildGlobalShortcuts(cfg *config.WorkspaceConfig) {
165165 }
166166
167167 // buildTabModeShortcuts populates tab mode shortcuts from config.
168-func (s *ShortcutSet) buildTabModeShortcuts(cfg *config.WorkspaceConfig) {
168+func (s *ShortcutSet) buildTabModeShortcuts(ctx context.Context, cfg *config.WorkspaceConfig) {
169+ log := logging.FromContext(ctx)
169170 bindings := cfg.TabMode.GetKeyBindings()
170- s.logger.Debug().Int("count", len(bindings)).Msg("building tab mode shortcuts")
171+ var registered, parseErrors, unknownActions int
171172 for key, configAction := range bindings {
172173 if binding, ok := ParseKeyString(key); ok {
173174 if action := mapConfigAction(configAction); action != "" {
174175 s.TabMode[binding] = action
175- s.logger.Debug().Str("key", key).Str("configAction", configAction).Str("action", string(action)).Uint("keyval", binding.Keyval).Msg("tab mode shortcut registered")
176+ registered++
177+ log.Trace().Str("key", key).Str("configAction", configAction).Str("action", string(action)).Uint("keyval", binding.Keyval).Msg("tab mode shortcut registered")
176178 } else {
177- s.logger.Warn().Str("key", key).Str("configAction", configAction).Msg("unknown config action in tab mode")
179+ unknownActions++
180+ log.Warn().Str("key", key).Str("configAction", configAction).Msg("unknown config action in tab mode")
178181 }
179182 } else {
180- s.logger.Warn().Str("key", key).Msg("failed to parse tab mode key")
183+ parseErrors++
184+ log.Warn().Str("key", key).Msg("failed to parse tab mode key")
181185 }
182186 }
187+ log.Debug().Int("registered", registered).Int("parseErrors", parseErrors).Int("unknownActions", unknownActions).Msg("tab mode shortcuts built")
183188 }
184189
185190 // buildPaneModeShortcuts populates pane mode shortcuts from config.
186-func (s *ShortcutSet) buildPaneModeShortcuts(cfg *config.WorkspaceConfig) {
191+func (s *ShortcutSet) buildPaneModeShortcuts(ctx context.Context, cfg *config.WorkspaceConfig) {
192+ log := logging.FromContext(ctx)
187193 bindings := cfg.PaneMode.GetKeyBindings()
188- s.logger.Debug().Int("count", len(bindings)).Msg("building pane mode shortcuts")
194+ var registered, parseErrors, unknownActions int
189195 for key, configAction := range bindings {
190196 if binding, ok := ParseKeyString(key); ok {
191197 if action := mapConfigAction(configAction); action != "" {
192198 s.PaneMode[binding] = action
193- s.logger.Debug().Str("key", key).Str("configAction", configAction).Str("action", string(action)).Uint("keyval", binding.Keyval).Msg("pane mode shortcut registered")
199+ registered++
200+ log.Trace().Str("key", key).Str("configAction", configAction).Str("action", string(action)).Uint("keyval", binding.Keyval).Msg("pane mode shortcut registered")
194201 } else {
195- s.logger.Warn().Str("key", key).Str("configAction", configAction).Msg("unknown config action in pane mode")
202+ unknownActions++
203+ log.Warn().Str("key", key).Str("configAction", configAction).Msg("unknown config action in pane mode")
196204 }
197205 } else {
198- s.logger.Warn().Str("key", key).Msg("failed to parse pane mode key")
206+ parseErrors++
207+ log.Warn().Str("key", key).Msg("failed to parse pane mode key")
199208 }
200209 }
210+ log.Debug().Int("registered", registered).Int("parseErrors", parseErrors).Int("unknownActions", unknownActions).Msg("pane mode shortcuts built")
201211 }
202212
203213 // mapConfigAction maps config action names to Action constants.
@@ -2,11 +2,12 @@
2 package input2 package input
3 3
4 import (4 import (
5+ "context"
5 "strings"6 "strings"
6 7
7 "github.com/bnema/dumber/internal/infrastructure/config"8 "github.com/bnema/dumber/internal/infrastructure/config"
9+ "github.com/bnema/dumber/internal/logging"
8 "github.com/jwijenbergh/puregotk/v4/gdk"10 "github.com/jwijenbergh/puregotk/v4/gdk"
9- "github.com/rs/zerolog"
10 )11 )
11 12
12 // Modifier represents keyboard modifier flags.13 // Modifier represents keyboard modifier flags.
@@ -95,42 +96,41 @@ type ShortcutSet struct {
95 TabMode ShortcutTable96 TabMode ShortcutTable
96 // PaneMode shortcuts are only active in pane mode.97 // PaneMode shortcuts are only active in pane mode.
97 PaneMode ShortcutTable98 PaneMode ShortcutTable
98-
99- logger *zerolog.Logger
100 }99 }
101 100
102 // NewShortcutSet creates a ShortcutSet from the workspace configuration.101 // NewShortcutSet creates a ShortcutSet from the workspace configuration.
103-func NewShortcutSet(cfg *config.WorkspaceConfig, logger *zerolog.Logger) *ShortcutSet {102+func NewShortcutSet(ctx context.Context, cfg *config.WorkspaceConfig) *ShortcutSet {
103+ log := logging.FromContext(ctx)
104 set := &ShortcutSet{104 set := &ShortcutSet{
105 Global: make(ShortcutTable),105 Global: make(ShortcutTable),
106 TabMode: make(ShortcutTable),106 TabMode: make(ShortcutTable),
107 PaneMode: make(ShortcutTable),107 PaneMode: make(ShortcutTable),
108- logger: logger,
109 }108 }
110 109
111- set.buildGlobalShortcuts(cfg)110+ set.buildGlobalShortcuts(ctx, cfg)
112- set.buildTabModeShortcuts(cfg)111+ set.buildTabModeShortcuts(ctx, cfg)
113- set.buildPaneModeShortcuts(cfg)112+ set.buildPaneModeShortcuts(ctx, cfg)
114 113
115- logger.Debug().Int("global", len(set.Global)).Int("tab", len(set.TabMode)).Int("pane", len(set.PaneMode)).Msg("shortcuts registered")114+ log.Debug().Int("global", len(set.Global)).Int("tab", len(set.TabMode)).Int("pane", len(set.PaneMode)).Msg("shortcuts registered")
116 115
117 return set116 return set
118 }117 }
119 118
120 // buildGlobalShortcuts populates global shortcuts from config.119 // buildGlobalShortcuts populates global shortcuts from config.
121-func (s *ShortcutSet) buildGlobalShortcuts(cfg *config.WorkspaceConfig) {120+func (s *ShortcutSet) buildGlobalShortcuts(ctx context.Context, cfg *config.WorkspaceConfig) {
121+ log := logging.FromContext(ctx)
122 // Mode entry from activation shortcuts122 // Mode entry from activation shortcuts
123 if binding, ok := ParseKeyString(cfg.TabMode.ActivationShortcut); ok {123 if binding, ok := ParseKeyString(cfg.TabMode.ActivationShortcut); ok {
124 s.Global[binding] = ActionEnterTabMode124 s.Global[binding] = ActionEnterTabMode
125- s.logger.Debug().Str("shortcut", cfg.TabMode.ActivationShortcut).Uint("keyval", binding.Keyval).Uint("mod", uint(binding.Modifiers)).Msg("tab mode activation registered")125+ log.Trace().Str("shortcut", cfg.TabMode.ActivationShortcut).Uint("keyval", binding.Keyval).Uint("mod", uint(binding.Modifiers)).Msg("tab mode activation registered")
126 } else {126 } else {
127- s.logger.Warn().Str("shortcut", cfg.TabMode.ActivationShortcut).Msg("failed to parse tab mode activation shortcut")127+ log.Warn().Str("shortcut", cfg.TabMode.ActivationShortcut).Msg("failed to parse tab mode activation shortcut")
128 }128 }
129 if binding, ok := ParseKeyString(cfg.PaneMode.ActivationShortcut); ok {129 if binding, ok := ParseKeyString(cfg.PaneMode.ActivationShortcut); ok {
130 s.Global[binding] = ActionEnterPaneMode130 s.Global[binding] = ActionEnterPaneMode
131- s.logger.Debug().Str("shortcut", cfg.PaneMode.ActivationShortcut).Uint("keyval", binding.Keyval).Uint("mod", uint(binding.Modifiers)).Msg("pane mode activation registered")131+ log.Trace().Str("shortcut", cfg.PaneMode.ActivationShortcut).Uint("keyval", binding.Keyval).Uint("mod", uint(binding.Modifiers)).Msg("pane mode activation registered")
132 } else {132 } else {
133- s.logger.Warn().Str("shortcut", cfg.PaneMode.ActivationShortcut).Msg("failed to parse pane mode activation shortcut")133+ log.Warn().Str("shortcut", cfg.PaneMode.ActivationShortcut).Msg("failed to parse pane mode activation shortcut")
134 }134 }
135 135
136 // Tab shortcuts from TabKeyConfig136 // Tab shortcuts from TabKeyConfig
@@ -165,39 +165,49 @@ func (s *ShortcutSet) buildGlobalShortcuts(cfg *config.WorkspaceConfig) {
165 }165 }
166 166
167 // buildTabModeShortcuts populates tab mode shortcuts from config.167 // buildTabModeShortcuts populates tab mode shortcuts from config.
168-func (s *ShortcutSet) buildTabModeShortcuts(cfg *config.WorkspaceConfig) {168+func (s *ShortcutSet) buildTabModeShortcuts(ctx context.Context, cfg *config.WorkspaceConfig) {
169+ log := logging.FromContext(ctx)
169 bindings := cfg.TabMode.GetKeyBindings()170 bindings := cfg.TabMode.GetKeyBindings()
170- s.logger.Debug().Int("count", len(bindings)).Msg("building tab mode shortcuts")171+ var registered, parseErrors, unknownActions int
171 for key, configAction := range bindings {172 for key, configAction := range bindings {
172 if binding, ok := ParseKeyString(key); ok {173 if binding, ok := ParseKeyString(key); ok {
173 if action := mapConfigAction(configAction); action != "" {174 if action := mapConfigAction(configAction); action != "" {
174 s.TabMode[binding] = action175 s.TabMode[binding] = action
175- s.logger.Debug().Str("key", key).Str("configAction", configAction).Str("action", string(action)).Uint("keyval", binding.Keyval).Msg("tab mode shortcut registered")176+ registered++
177+ log.Trace().Str("key", key).Str("configAction", configAction).Str("action", string(action)).Uint("keyval", binding.Keyval).Msg("tab mode shortcut registered")
176 } else {178 } else {
177- s.logger.Warn().Str("key", key).Str("configAction", configAction).Msg("unknown config action in tab mode")179+ unknownActions++
180+ log.Warn().Str("key", key).Str("configAction", configAction).Msg("unknown config action in tab mode")
178 }181 }
179 } else {182 } else {
180- s.logger.Warn().Str("key", key).Msg("failed to parse tab mode key")183+ parseErrors++
184+ log.Warn().Str("key", key).Msg("failed to parse tab mode key")
181 }185 }
182 }186 }
187+ log.Debug().Int("registered", registered).Int("parseErrors", parseErrors).Int("unknownActions", unknownActions).Msg("tab mode shortcuts built")
183 }188 }
184 189
185 // buildPaneModeShortcuts populates pane mode shortcuts from config.190 // buildPaneModeShortcuts populates pane mode shortcuts from config.
186-func (s *ShortcutSet) buildPaneModeShortcuts(cfg *config.WorkspaceConfig) {191+func (s *ShortcutSet) buildPaneModeShortcuts(ctx context.Context, cfg *config.WorkspaceConfig) {
192+ log := logging.FromContext(ctx)
187 bindings := cfg.PaneMode.GetKeyBindings()193 bindings := cfg.PaneMode.GetKeyBindings()
188- s.logger.Debug().Int("count", len(bindings)).Msg("building pane mode shortcuts")194+ var registered, parseErrors, unknownActions int
189 for key, configAction := range bindings {195 for key, configAction := range bindings {
190 if binding, ok := ParseKeyString(key); ok {196 if binding, ok := ParseKeyString(key); ok {
191 if action := mapConfigAction(configAction); action != "" {197 if action := mapConfigAction(configAction); action != "" {
192 s.PaneMode[binding] = action198 s.PaneMode[binding] = action
193- s.logger.Debug().Str("key", key).Str("configAction", configAction).Str("action", string(action)).Uint("keyval", binding.Keyval).Msg("pane mode shortcut registered")199+ registered++
200+ log.Trace().Str("key", key).Str("configAction", configAction).Str("action", string(action)).Uint("keyval", binding.Keyval).Msg("pane mode shortcut registered")
194 } else {201 } else {
195- s.logger.Warn().Str("key", key).Str("configAction", configAction).Msg("unknown config action in pane mode")202+ unknownActions++
203+ log.Warn().Str("key", key).Str("configAction", configAction).Msg("unknown config action in pane mode")
196 }204 }
197 } else {205 } else {
198- s.logger.Warn().Str("key", key).Msg("failed to parse pane mode key")206+ parseErrors++
207+ log.Warn().Str("key", key).Msg("failed to parse pane mode key")
199 }208 }
200 }209 }
210+ log.Debug().Int("registered", registered).Int("parseErrors", parseErrors).Int("unknownActions", unknownActions).Msg("pane mode shortcuts built")
201 }211 }
202 212
203 // mapConfigAction maps config action names to Action constants.213 // mapConfigAction maps config action names to Action constants.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close