v0.7.2 ab6686c

screen_keyboard.go RawHistoryFolder

1package vt
2
3import (
4	"strconv"
5	"strings"
6)
7
8// Kitty keyboard progressive enhancement flags.
9// https://sw.kovidgoyal.net/kitty/keyboard-protocol/#progressive-enhancement
10const (
11	KittyKeyboardDisambiguate    = 1 << 0
12	KittyKeyboardReportEvents    = 1 << 1
13	KittyKeyboardAlternateKeys   = 1 << 2
14	KittyKeyboardAllKeysAsEscape = 1 << 3
15	KittyKeyboardAssociatedText  = 1 << 4
16
17	kittyKeyboardFlagMask = 1<<5 - 1
18	// maxKittyKeyboardStack bounds the per-screen flag stack. When full, a
19	// push evicts the oldest entry, as the protocol recommends.
20	maxKittyKeyboardStack = 16
21)
22
23// kittyKeyboardStack is one screen's stack of keyboard enhancement flags. The
24// current flags are the top entry, or zero when the stack is empty.
25type kittyKeyboardStack []int
26
27func (k kittyKeyboardStack) current() int {
28	if len(k) == 0 {
29		return 0
30	}
31	return k[len(k)-1]
32}
33
34func (k *kittyKeyboardStack) push(flags int) {
35	if len(*k) == maxKittyKeyboardStack {
36		copy(*k, (*k)[1:])
37		*k = (*k)[:len(*k)-1]
38	}
39	*k = append(*k, flags&kittyKeyboardFlagMask)
40}
41
42func (k *kittyKeyboardStack) pop(n int) {
43	*k = (*k)[:len(*k)-min(n, len(*k))]
44}
45
46// set applies CSI = flags ; mode u. Mode 1 replaces, 2 sets bits, 3 clears
47// bits. With an empty stack the result becomes the single entry.
48func (k *kittyKeyboardStack) set(flags, mode int) {
49	cur := k.current()
50	switch mode {
51	case 1:
52		cur = flags
53	case 2:
54		cur |= flags
55	case 3:
56		cur &^= flags
57	default:
58		return
59	}
60	cur &= kittyKeyboardFlagMask
61	if len(*k) == 0 {
62		*k = append(*k, cur)
63		return
64	}
65	(*k)[len(*k)-1] = cur
66}
67
68// KittyKeyboardFlags reports the kitty keyboard enhancement flags currently
69// requested by the application on the active (main or alternate) screen.
70func (s *Screen) KittyKeyboardFlags() int { return s.kittyKeyboard.current() }
71
72// applyKittyKeyboard handles CSI u sequences with a ?, >, <, or = prefix. It
73// reports whether params belonged to the kitty keyboard protocol.
74func (s *Screen) applyKittyKeyboard(params string) bool {
75	if params == "" {
76		return false
77	}
78	prefix, rest := params[0], params[1:]
79	switch prefix {
80	case '?':
81		if rest != "" {
82			return true
83		}
84		resp := make([]byte, 0, 8)
85		resp = append(resp, "\x1b[?"...)
86		resp = strconv.AppendInt(resp, int64(s.kittyKeyboard.current()), 10)
87		resp = append(resp, 'u')
88		s.respond(resp)
89	case '>':
90		flags, _ := kittyKeyboardParams(rest)
91		s.kittyKeyboard.push(flags)
92	case '<':
93		n, _ := kittyKeyboardParams(rest)
94		s.kittyKeyboard.pop(max(n, 1))
95	case '=':
96		flags, mode := kittyKeyboardParams(rest)
97		s.kittyKeyboard.set(flags, max(mode, 1))
98	default:
99		return false
100	}
101	return true
102}
103
104// kittyKeyboardParams parses up to two decimal parameters. Missing or
105// malformed values are zero.
106func kittyKeyboardParams(params string) (first, second int) {
107	a, b, _ := strings.Cut(params, ";")
108	return parseCSIInt(a), parseCSIInt(b)
109}

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