detached e672f74

fix(vt): reject invalid cursor styles

Apply CodeRabbit finding from the single review run against main: DECSCUSR values outside 0-6 are ignored and do not overwrite existing cursor style state.
commit
e672f742902217a671c056ab4bdd89eeea650e28
author
brice · · 2026-07-02 19:56 UTC
parent
922d0fd
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +15 -0
M pkg/vt/screen.go +3 -0
@@ -806,6 +806,9 @@ func (s *Screen) applyCursorStyle(params string) {
806806 }
807807 style = v
808808 }
809+ if style < 0 || style > 6 {
810+ return
811+ }
809812 s.cursorStyle = style
810813 s.cursorStyleSet = true
811814 }
@@ -806,6 +806,9 @@ func (s *Screen) applyCursorStyle(params string) {
806 }806 }
807 style = v807 style = v
808 }808 }
809+ if style < 0 || style > 6 {
810+ return
811+ }
809 s.cursorStyle = style812 s.cursorStyle = style
810 s.cursorStyleSet = true813 s.cursorStyleSet = true
811 }814 }
M pkg/vt/screen_test.go +12 -0
@@ -2281,6 +2281,8 @@ func TestScreenCursorStyleDECSCUSR(t *testing.T) {
22812281 }{
22822282 {name: "explicit style", seq: "\x1b[5 q", wantStyle: 5, wantSet: true},
22832283 {name: "blank style parameter", seq: "\x1b[ q", wantStyle: 0, wantSet: true},
2284+ {name: "invalid low style is ignored", seq: "\x1b[-1 q", wantStyle: 0, wantSet: false},
2285+ {name: "invalid high style is ignored", seq: "\x1b[7 q", wantStyle: 0, wantSet: false},
22842286 {name: "XTVERSION is ignored", seq: "\x1b[>0q", wantStyle: 0, wantSet: false},
22852287 }
22862288 for _, tt := range tests {
@@ -2295,6 +2297,16 @@ func TestScreenCursorStyleDECSCUSR(t *testing.T) {
22952297 }
22962298 }
22972299
2300+func TestScreenInvalidCursorStyleDoesNotOverwriteCurrentStyle(t *testing.T) {
2301+ s := NewScreen(10, 2)
2302+ s.Write([]byte("\x1b[5 q"))
2303+ s.Write([]byte("\x1b[99 q"))
2304+ style, set := s.CursorStyle()
2305+ if style != 5 || !set {
2306+ t.Fatalf("CursorStyle() = (%d, %v), want (5, true)", style, set)
2307+ }
2308+}
2309+
22982310 func TestScreenAltScreenActiveAccessor(t *testing.T) {
22992311 s := NewScreen(10, 2)
23002312 if s.AltScreenActive() {
@@ -2281,6 +2281,8 @@ func TestScreenCursorStyleDECSCUSR(t *testing.T) {
2281 }{2281 }{
2282 {name: "explicit style", seq: "\x1b[5 q", wantStyle: 5, wantSet: true},2282 {name: "explicit style", seq: "\x1b[5 q", wantStyle: 5, wantSet: true},
2283 {name: "blank style parameter", seq: "\x1b[ q", wantStyle: 0, wantSet: true},2283 {name: "blank style parameter", seq: "\x1b[ q", wantStyle: 0, wantSet: true},
2284+ {name: "invalid low style is ignored", seq: "\x1b[-1 q", wantStyle: 0, wantSet: false},
2285+ {name: "invalid high style is ignored", seq: "\x1b[7 q", wantStyle: 0, wantSet: false},
2284 {name: "XTVERSION is ignored", seq: "\x1b[>0q", wantStyle: 0, wantSet: false},2286 {name: "XTVERSION is ignored", seq: "\x1b[>0q", wantStyle: 0, wantSet: false},
2285 }2287 }
2286 for _, tt := range tests {2288 for _, tt := range tests {
@@ -2295,6 +2297,16 @@ func TestScreenCursorStyleDECSCUSR(t *testing.T) {
2295 }2297 }
2296 }2298 }
2297 2299
2300+func TestScreenInvalidCursorStyleDoesNotOverwriteCurrentStyle(t *testing.T) {
2301+ s := NewScreen(10, 2)
2302+ s.Write([]byte("\x1b[5 q"))
2303+ s.Write([]byte("\x1b[99 q"))
2304+ style, set := s.CursorStyle()
2305+ if style != 5 || !set {
2306+ t.Fatalf("CursorStyle() = (%d, %v), want (5, true)", style, set)
2307+ }
2308+}
2309+
2298 func TestScreenAltScreenActiveAccessor(t *testing.T) {2310 func TestScreenAltScreenActiveAccessor(t *testing.T) {
2299 s := NewScreen(10, 2)2311 s := NewScreen(10, 2)
2300 if s.AltScreenActive() {2312 if s.AltScreenActive() {

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 2

Tags 13

↑↓ moveenter openesc close