detached 830f50b

refactor(docmodel): share strict block motion scan

commit
830f50b8082c6de1176ffa914de35bc1c76fb71d
author
brice · · 2026-08-14 07:01 UTC
parent
d596066
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +10 -24
M internal/domain/docmodel/motions.go +10 -24
@@ -31,29 +31,9 @@ func (d Document) PreviousBlockOfKind(from Cursor, kind BlockKind, count int) (C
3131 }
3232
3333 func (d Document) headingMotion(from Cursor, count, direction int, levels []int) (Cursor, bool) {
34- start, ok := d.indexByID[from.BlockID]
35- if !ok {
36- return Cursor{}, false
37- }
38-
39- if count <= 0 {
40- count = 1
41- }
42-
43- remaining := count
44- for i := start + direction; i >= 0 && i < len(d.blocks); i += direction {
45- block := d.blocks[i]
46- if !block.IsHeading() || !headingLevelMatches(block.HeadingLevel, levels) {
47- continue
48- }
49-
50- remaining--
51- if remaining == 0 {
52- return Cursor{BlockID: block.ID}, true
53- }
54- }
55-
56- return Cursor{}, false
34+ return d.matchingBlockMotion(from, count, direction, func(block Block) bool {
35+ return block.IsHeading() && headingLevelMatches(block.HeadingLevel, levels)
36+ })
5737 }
5838
5939 func (d Document) blockKindMotion(from Cursor, kind BlockKind, count, direction int) (Cursor, bool) {
@@ -61,6 +41,12 @@ func (d Document) blockKindMotion(from Cursor, kind BlockKind, count, direction
6141 return Cursor{}, false
6242 }
6343
44+ return d.matchingBlockMotion(from, count, direction, func(block Block) bool {
45+ return block.Kind == kind
46+ })
47+}
48+
49+func (d Document) matchingBlockMotion(from Cursor, count, direction int, matches func(Block) bool) (Cursor, bool) {
6450 start, ok := d.indexByID[from.BlockID]
6551 if !ok {
6652 return Cursor{}, false
@@ -73,7 +59,7 @@ func (d Document) blockKindMotion(from Cursor, kind BlockKind, count, direction
7359 remaining := count
7460 for i := start + direction; i >= 0 && i < len(d.blocks); i += direction {
7561 block := d.blocks[i]
76- if block.Kind != kind {
62+ if !matches(block) {
7763 continue
7864 }
7965
@@ -31,29 +31,9 @@ func (d Document) PreviousBlockOfKind(from Cursor, kind BlockKind, count int) (C
31 }31 }
32 32
33 func (d Document) headingMotion(from Cursor, count, direction int, levels []int) (Cursor, bool) {33 func (d Document) headingMotion(from Cursor, count, direction int, levels []int) (Cursor, bool) {
34- start, ok := d.indexByID[from.BlockID]34+ return d.matchingBlockMotion(from, count, direction, func(block Block) bool {
35- if !ok {35+ return block.IsHeading() && headingLevelMatches(block.HeadingLevel, levels)
36- return Cursor{}, false36+ })
37- }
38-
39- if count <= 0 {
40- count = 1
41- }
42-
43- remaining := count
44- for i := start + direction; i >= 0 && i < len(d.blocks); i += direction {
45- block := d.blocks[i]
46- if !block.IsHeading() || !headingLevelMatches(block.HeadingLevel, levels) {
47- continue
48- }
49-
50- remaining--
51- if remaining == 0 {
52- return Cursor{BlockID: block.ID}, true
53- }
54- }
55-
56- return Cursor{}, false
57 }37 }
58 38
59 func (d Document) blockKindMotion(from Cursor, kind BlockKind, count, direction int) (Cursor, bool) {39 func (d Document) blockKindMotion(from Cursor, kind BlockKind, count, direction int) (Cursor, bool) {
@@ -61,6 +41,12 @@ func (d Document) blockKindMotion(from Cursor, kind BlockKind, count, direction
61 return Cursor{}, false41 return Cursor{}, false
62 }42 }
63 43
44+ return d.matchingBlockMotion(from, count, direction, func(block Block) bool {
45+ return block.Kind == kind
46+ })
47+}
48+
49+func (d Document) matchingBlockMotion(from Cursor, count, direction int, matches func(Block) bool) (Cursor, bool) {
64 start, ok := d.indexByID[from.BlockID]50 start, ok := d.indexByID[from.BlockID]
65 if !ok {51 if !ok {
66 return Cursor{}, false52 return Cursor{}, false
@@ -73,7 +59,7 @@ func (d Document) blockKindMotion(from Cursor, kind BlockKind, count, direction
73 remaining := count59 remaining := count
74 for i := start + direction; i >= 0 && i < len(d.blocks); i += direction {60 for i := start + direction; i >= 0 && i < len(d.blocks); i += direction {
75 block := d.blocks[i]61 block := d.blocks[i]
76- if block.Kind != kind {62+ if !matches(block) {
77 continue63 continue
78 }64 }
79 65

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