vim_navigation.go RawHistoryFolder
1package usecase
2
3import (
4 "context"
5 "errors"
6
7 "github.com/bnema/dumber/internal/application/dto"
8 "github.com/bnema/dumber/internal/application/port"
9)
10
11var (
12 errUnsupportedVimNavigationAction = errors.New("vim navigation: unsupported action")
13 errUnsupportedVimNavigationEngine = errors.New("vim navigation: unsupported webview capability")
14)
15
16// VimNavigationUseCase maps configured Vim Mode navigation actions to optional
17// WebView capabilities. The UI layer supplies the active WebView and remains
18// responsible only for event and theme context.
19type VimNavigationUseCase struct{}
20
21// NewVimNavigationUseCase creates a stateless Vim navigation use case.
22func NewVimNavigationUseCase() *VimNavigationUseCase {
23 return &VimNavigationUseCase{}
24}
25
26// Execute dispatches a configured semantic Vim action to the active WebView.
27func (*VimNavigationUseCase) Execute(ctx context.Context, wv port.WebView, action string, count int, highlightColor string) error {
28 if wv == nil {
29 return errors.New("vim navigation: nil webview")
30 }
31
32 switch action {
33 case "confirm":
34 activator, ok := wv.(port.SemanticNavigationActivator)
35 if !ok {
36 return errUnsupportedVimNavigationEngine
37 }
38 return activator.ActivateSemanticNavigationTarget(ctx)
39 case "focus-input":
40 focuser, ok := wv.(port.PageInputFocuser)
41 if !ok {
42 return errUnsupportedVimNavigationEngine
43 }
44 focuser.FocusNextInput()
45 return nil
46 }
47
48 var request dto.SemanticNavigationRequest
49 switch action {
50 case "heading-next":
51 request = dto.SemanticNavigationRequest{
52 Target: dto.SemanticNavigationTargetHeading,
53 Direction: dto.SemanticNavigationForward,
54 Count: count,
55 HighlightColor: highlightColor,
56 }
57 case "heading-prev":
58 request = dto.SemanticNavigationRequest{
59 Target: dto.SemanticNavigationTargetHeading,
60 Direction: dto.SemanticNavigationBackward,
61 Count: count,
62 HighlightColor: highlightColor,
63 }
64 default:
65 return errUnsupportedVimNavigationAction
66 }
67
68 navigator, ok := wv.(port.SemanticNavigable)
69 if !ok {
70 return errUnsupportedVimNavigationEngine
71 }
72 return navigator.NavigateSemantic(ctx, request)
73}
74
75// ClearSemanticNavigationHighlight removes the visual target left by semantic
76// navigation when the active Vim Mode session ends.
77func (*VimNavigationUseCase) ClearSemanticNavigationHighlight(ctx context.Context, wv port.WebView) error {
78 if wv == nil {
79 return nil
80 }
81 clearer, ok := wv.(port.SemanticNavigationHighlightClearer)
82 if !ok {
83 return nil
84 }
85 return clearer.ClearSemanticNavigationHighlight(ctx)
86}
87
88// NavigatePageFocus keeps focus traversal inside a page when the active page
89// control would otherwise hand the host window a Tab event.
90func (*VimNavigationUseCase) NavigatePageFocus(wv port.WebView, backward bool) bool {
91 if wv == nil {
92 return false
93 }
94 navigator, ok := wv.(port.PageFocusNavigator)
95 if !ok {
96 return false
97 }
98 navigator.NavigatePageFocus(backward)
99 return true
100}