detached 2a96044

feat(app): wire the hints adapter

commit
2a96044cc93aa6bd36cffdffec4750d2bce7a8d4
author
brice · · 2026-10-19 10:37 UTC
parent
4b455b2
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +20 -8
M internal/app/session.go +7 -0
@@ -14,6 +14,7 @@ import (
1414 "github.com/bnema/neferwl/internal/adapters/config"
1515 "github.com/bnema/neferwl/internal/adapters/drm"
1616 "github.com/bnema/neferwl/internal/adapters/headlessinput"
17+ "github.com/bnema/neferwl/internal/adapters/hints"
1718 "github.com/bnema/neferwl/internal/adapters/launcher"
1819 "github.com/bnema/neferwl/internal/adapters/libinput"
1920 "github.com/bnema/neferwl/internal/adapters/logging"
@@ -342,6 +343,12 @@ func (s *session) run(ctx context.Context, inject func(chan<- ports.InputEvent))
342343 }()
343344 workers.Add(1)
344345 go func() { defer workers.Done(); routeCaptured(ctx, p.capturedAll, p.captured, p.internalCaptured()) }()
346+ workers.Add(1)
347+ go func() {
348+ defer workers.Done()
349+ // Run only returns when ctx is done: nothing to report.
350+ _ = hints.Run(ctx, p.hintScans, p.captures, p.hintCaptured, p.hintResults)
351+ }()
345352 go func() { defer workers.Done(); done <- child.Run(ctx, p.spawn) }()
346353 go func() { defer workers.Done(); done <- c.Run(ctx) }()
347354 workers.Add(1)
@@ -14,6 +14,7 @@ import (
14 "github.com/bnema/neferwl/internal/adapters/config"14 "github.com/bnema/neferwl/internal/adapters/config"
15 "github.com/bnema/neferwl/internal/adapters/drm"15 "github.com/bnema/neferwl/internal/adapters/drm"
16 "github.com/bnema/neferwl/internal/adapters/headlessinput"16 "github.com/bnema/neferwl/internal/adapters/headlessinput"
17+ "github.com/bnema/neferwl/internal/adapters/hints"
17 "github.com/bnema/neferwl/internal/adapters/launcher"18 "github.com/bnema/neferwl/internal/adapters/launcher"
18 "github.com/bnema/neferwl/internal/adapters/libinput"19 "github.com/bnema/neferwl/internal/adapters/libinput"
19 "github.com/bnema/neferwl/internal/adapters/logging"20 "github.com/bnema/neferwl/internal/adapters/logging"
@@ -342,6 +343,12 @@ func (s *session) run(ctx context.Context, inject func(chan<- ports.InputEvent))
342 }()343 }()
343 workers.Add(1)344 workers.Add(1)
344 go func() { defer workers.Done(); routeCaptured(ctx, p.capturedAll, p.captured, p.internalCaptured()) }()345 go func() { defer workers.Done(); routeCaptured(ctx, p.capturedAll, p.captured, p.internalCaptured()) }()
346+ workers.Add(1)
347+ go func() {
348+ defer workers.Done()
349+ // Run only returns when ctx is done: nothing to report.
350+ _ = hints.Run(ctx, p.hintScans, p.captures, p.hintCaptured, p.hintResults)
351+ }()
345 go func() { defer workers.Done(); done <- child.Run(ctx, p.spawn) }()352 go func() { defer workers.Done(); done <- child.Run(ctx, p.spawn) }()
346 go func() { defer workers.Done(); done <- c.Run(ctx) }()353 go func() { defer workers.Done(); done <- c.Run(ctx) }()
347 workers.Add(1)354 workers.Add(1)
M internal/app/wiring.go +13 -8
@@ -46,6 +46,10 @@ type pipes struct {
4646 // move running slides.
4747 frames chan ports.OutputFrame
4848
49+ // Hint mode: core asks the hints adapter for a scan and gets the result.
50+ hintScans chan ports.HintScanRequest
51+ hintResults chan ports.HintScanResult
52+
4953 captures chan ports.CaptureRequest
5054 // Every admitted capture owns one reply slot until routeCaptured takes
5155 // it. Keep this capacity tied to admission so output routing never waits.
@@ -54,9 +58,7 @@ type pipes struct {
5458 // hintCaptured (internal consumers).
5559 capturedAll chan ports.CaptureDone
5660 captured chan ports.CaptureDone
57- // hintCaptured carries internal capture replies. Until an internal
58- // consumer (the hints adapter) is wired, nothing reads it: see
59- // internalCaptured.
61+ // hintCaptured carries internal capture replies to the hints adapter.
6062 hintCaptured chan ports.CaptureDone
6163
6264 outputFormats chan ports.OutputFormats
@@ -105,6 +107,9 @@ func newPipes(realSession bool) *pipes {
105107
106108 frames: make(chan ports.OutputFrame, 8),
107109
110+ hintScans: make(chan ports.HintScanRequest, 1),
111+ hintResults: make(chan ports.HintScanResult, 1),
112+
108113 captures: make(chan ports.CaptureRequest, ports.MaxCaptureInflight),
109114 capturedAll: make(chan ports.CaptureDone, ports.MaxCaptureInflight),
110115 captured: make(chan ports.CaptureDone, ports.MaxCaptureInflight),
@@ -146,14 +151,14 @@ func (p *pipes) core() core.Channels {
146151 ConfigErrors: p.configErrors,
147152 Scales: p.scales,
148153 Frames: p.frames,
154+ HintScans: p.hintScans,
155+ Hints: p.hintResults,
149156 }
150157 }
151158
152-// internalCaptured is the channel internal capture replies are routed to, nil
153-// while no internal consumer is wired: routeCaptured then drops them (debug
154-// log) rather than blocking on a channel nobody reads. The hints adapter
155-// makes it p.hintCaptured.
156-func (p *pipes) internalCaptured() chan<- ports.CaptureDone { return nil }
159+// internalCaptured is the channel internal capture replies are routed to: the
160+// hints adapter reads it.
161+func (p *pipes) internalCaptured() chan<- ports.CaptureDone { return p.hintCaptured }
157162
158163 // wayland is the wayland server's side.
159164 func (p *pipes) wayland() wayland.Channels {
@@ -46,6 +46,10 @@ type pipes struct {
46 // move running slides.46 // move running slides.
47 frames chan ports.OutputFrame47 frames chan ports.OutputFrame
48 48
49+ // Hint mode: core asks the hints adapter for a scan and gets the result.
50+ hintScans chan ports.HintScanRequest
51+ hintResults chan ports.HintScanResult
52+
49 captures chan ports.CaptureRequest53 captures chan ports.CaptureRequest
50 // Every admitted capture owns one reply slot until routeCaptured takes54 // Every admitted capture owns one reply slot until routeCaptured takes
51 // it. Keep this capacity tied to admission so output routing never waits.55 // it. Keep this capacity tied to admission so output routing never waits.
@@ -54,9 +58,7 @@ type pipes struct {
54 // hintCaptured (internal consumers).58 // hintCaptured (internal consumers).
55 capturedAll chan ports.CaptureDone59 capturedAll chan ports.CaptureDone
56 captured chan ports.CaptureDone60 captured chan ports.CaptureDone
57- // hintCaptured carries internal capture replies. Until an internal61+ // hintCaptured carries internal capture replies to the hints adapter.
58- // consumer (the hints adapter) is wired, nothing reads it: see
59- // internalCaptured.
60 hintCaptured chan ports.CaptureDone62 hintCaptured chan ports.CaptureDone
61 63
62 outputFormats chan ports.OutputFormats64 outputFormats chan ports.OutputFormats
@@ -105,6 +107,9 @@ func newPipes(realSession bool) *pipes {
105 107
106 frames: make(chan ports.OutputFrame, 8),108 frames: make(chan ports.OutputFrame, 8),
107 109
110+ hintScans: make(chan ports.HintScanRequest, 1),
111+ hintResults: make(chan ports.HintScanResult, 1),
112+
108 captures: make(chan ports.CaptureRequest, ports.MaxCaptureInflight),113 captures: make(chan ports.CaptureRequest, ports.MaxCaptureInflight),
109 capturedAll: make(chan ports.CaptureDone, ports.MaxCaptureInflight),114 capturedAll: make(chan ports.CaptureDone, ports.MaxCaptureInflight),
110 captured: make(chan ports.CaptureDone, ports.MaxCaptureInflight),115 captured: make(chan ports.CaptureDone, ports.MaxCaptureInflight),
@@ -146,14 +151,14 @@ func (p *pipes) core() core.Channels {
146 ConfigErrors: p.configErrors,151 ConfigErrors: p.configErrors,
147 Scales: p.scales,152 Scales: p.scales,
148 Frames: p.frames,153 Frames: p.frames,
154+ HintScans: p.hintScans,
155+ Hints: p.hintResults,
149 }156 }
150 }157 }
151 158
152-// internalCaptured is the channel internal capture replies are routed to, nil159+// internalCaptured is the channel internal capture replies are routed to: the
153-// while no internal consumer is wired: routeCaptured then drops them (debug160+// hints adapter reads it.
154-// log) rather than blocking on a channel nobody reads. The hints adapter161+func (p *pipes) internalCaptured() chan<- ports.CaptureDone { return p.hintCaptured }
155-// makes it p.hintCaptured.
156-func (p *pipes) internalCaptured() chan<- ports.CaptureDone { return nil }
157 162
158 // wayland is the wayland server's side.163 // wayland is the wayland server's side.
159 func (p *pipes) wayland() wayland.Channels {164 func (p *pipes) wayland() wayland.Channels {

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 26

Tags 10

↑↓ moveenter openesc close