Skip to content

Commit 5fa4c15

Browse files
authored
fix: allow <tab> key to toggle between scroll hint and scroll mode (#87)
1 parent edd608f commit 5fa4c15

2 files changed

Lines changed: 37 additions & 27 deletions

File tree

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
</div>
2121

22-
https://github.com/user-attachments/assets/6d796898-b780-499d-b3a3-35b9ec537079
22+
<https://github.com/user-attachments/assets/6d796898-b780-499d-b3a3-35b9ec537079>
2323

2424
## About Neru
2525

@@ -286,10 +286,12 @@ Press `esc` anytime to quit the hint selection.
286286
**Default hotkey:** `Cmd+Shift+J`
287287

288288
1. Press the hotkey
289-
2. Type the hint label (will move the cursor to the position selected)
290-
3. Start scrolling
289+
2. In the hint selection mode, type the hint label (will move the cursor to the position selected)
290+
3. At the same time, press `tab` to enter scroll mode directly without selecting a hint
291+
4. Start scrolling
291292

292293
Press `esc` anytime to quit the scroll mode.
294+
Press `tab` to toggle between direct scroll and hint selection to move your cursor.
293295

294296
Vim-style navigation keys:
295297

cmd/neru/main.go

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,22 @@ const (
4141
type App struct {
4242
config *config.Config
4343
// ConfigPath holds the path the daemon was started with (if any)
44-
ConfigPath string
45-
logger *zap.Logger
46-
hotkeyManager *hotkeys.Manager
47-
hintGenerator *hints.Generator
48-
hintOverlay *hints.Overlay
49-
scrollController *scroll.Controller
50-
eventTap *eventtap.EventTap
51-
ipcServer *ipc.Server
52-
electronManager *electron.ElectronManager
53-
appWatcher *appwatcher.Watcher
54-
currentMode Mode
55-
hintManager *hints.Manager
56-
lastScrollKey string
57-
selectedHint *hints.Hint
58-
selectedScrollHint *hints.Hint
59-
enabled bool
44+
ConfigPath string
45+
logger *zap.Logger
46+
hotkeyManager *hotkeys.Manager
47+
hintGenerator *hints.Generator
48+
hintOverlay *hints.Overlay
49+
scrollController *scroll.Controller
50+
eventTap *eventtap.EventTap
51+
ipcServer *ipc.Server
52+
electronManager *electron.ElectronManager
53+
appWatcher *appwatcher.Watcher
54+
currentMode Mode
55+
hintManager *hints.Manager
56+
lastScrollKey string
57+
selectedHint *hints.Hint
58+
canScroll bool
59+
enabled bool
6060
// Track whether global hotkeys are currently registered
6161
hotkeysRegistered bool
6262
}
@@ -608,6 +608,7 @@ func (a *App) activateHintMode(mode Mode) {
608608

609609
// Reset state
610610
a.selectedHint = nil
611+
a.canScroll = false
611612

612613
// Enable event tap to capture keys (must be last to ensure proper initialization)
613614
if a.eventTap != nil {
@@ -640,11 +641,18 @@ func (a *App) handleHintKey(key string) {
640641
return
641642
}
642643

643-
if a.selectedScrollHint != nil {
644+
if a.canScroll {
644645
a.handleScrollKey(key)
645646
return
646647
}
647648

649+
if a.currentMode == ModeScroll && !a.canScroll && key == "\t" {
650+
a.canScroll = true
651+
a.hintOverlay.Clear()
652+
a.showScroll()
653+
return
654+
}
655+
648656
if hint, ok := a.hintManager.HandleInput(key); ok {
649657
switch a.currentMode {
650658
case ModeHintWithActions:
@@ -663,15 +671,15 @@ func (a *App) handleHintKey(key string) {
663671
}
664672
a.exitMode()
665673
case ModeScroll:
666-
a.selectedScrollHint = hint
674+
a.canScroll = true
667675
// Enter scroll mode - scroll to element
668676
a.logger.Info("Hint selected, start scrolling", zap.String("label", a.hintManager.GetInput()))
669677
if err := hint.Element.Element.GoToPosition(); err != nil {
670678
a.logger.Error("Failed to scroll to element", zap.Error(err))
671679
}
672680

673681
a.hintOverlay.Clear()
674-
a.showScroll(hint)
682+
a.showScroll()
675683
}
676684
return
677685
}
@@ -793,7 +801,7 @@ func (a *App) handleActionKey(key string) {
793801
}
794802

795803
// showActionMenu displays the action selection menu at the hint location
796-
func (a *App) showScroll(hint *hints.Hint) {
804+
func (a *App) showScroll() {
797805
a.drawScrollHighlightBorder()
798806
}
799807

@@ -835,9 +843,6 @@ func (a *App) handleScrollKey(key string) {
835843
err = a.scrollController.ScrollLeft()
836844
case "l":
837845
err = a.scrollController.ScrollRight()
838-
// Remove plain d/u - only use Ctrl+D/U
839-
// case "d": // Removed - use Ctrl+D instead
840-
// case "u": // Removed - use Ctrl+U instead
841846
case "g": // gg for top (need to press twice)
842847
if a.lastScrollKey == "g" {
843848
a.logger.Info("gg detected - scroll to top")
@@ -853,6 +858,9 @@ func (a *App) handleScrollKey(key string) {
853858
a.logger.Info("G key detected - scroll to bottom")
854859
err = a.scrollController.ScrollToBottom()
855860
a.lastScrollKey = ""
861+
case "\t":
862+
a.logger.Info("? key detected - show hint again")
863+
a.activateHintMode(ModeScroll)
856864
default:
857865
a.logger.Debug("Ignoring non-scroll key", zap.String("key", key))
858866
a.lastScrollKey = ""
@@ -899,7 +907,7 @@ func (a *App) exitMode() {
899907
a.hintManager.Reset()
900908
}
901909
a.selectedHint = nil
902-
a.selectedScrollHint = nil
910+
a.canScroll = false
903911

904912
// Then clear and hide the overlay after all potential visual generators are cleaned
905913
a.hintOverlay.Clear()

0 commit comments

Comments
 (0)