v0.7.0 438604c

edit_paint.go RawHistoryFolder

1package ui
2
3import (
4	"math"
5
6	"github.com/bnema/nefergui/internal/css"
7	"github.com/bnema/nefergui/internal/edit"
8	"github.com/bnema/nefergui/internal/layout"
9)
10
11var selectionColor = css.Color{R: 0.22, G: 0.43, B: 0.85, A: 0.4}
12var caretColor = css.Color{R: 0, G: 0, B: 0, A: 1}
13
14func (r *runtime) paintEditors(root *element, out *layout.Output) {
15	var visit func(*element)
16	visit = func(e *element) {
17		if e == nil {
18			return
19		}
20		if e.typ == "input" || e.typ == "textarea" {
21			id := idKey(e.identity)
22			s := r.edits[id]
23			n := resultByID(out.Tree, id)
24			if s != nil && n != nil {
25				var commands []layout.Command
26				if s.Value == "" && s.Preedit == "" && e.placeholder != "" && r.textEngine != nil {
27					commands = placeholderCommand(e, n, r.textEngine)
28				}
29				if !e.disabled {
30					commands = append(commands, editorDecoration(s, n, out.Display, e.password, e.identity.same(r.state.focus))...)
31					if s.Preedit != "" && e.identity.same(r.state.focus) && r.textEngine != nil {
32						commands = append(commands, preeditCommands(s, n, e, r.textEngine, out.Display)...)
33					}
34				}
35				insertClippedCommands(out, id, commands)
36			}
37		}
38		for _, child := range e.children {
39			visit(child)
40		}
41	}
42	visit(root)
43}
44
45// editorDecoration maps logical grapheme selection to visual cluster spans.
46// The caret follows editorGeometry's policy: at an ambiguous boundary, such as
47// a bidi run change, the preceding character's trailing edge is used.
48func editorDecoration(s *edit.State, n *layout.Result, display []layout.Command, password, focused bool) []layout.Command {
49	if n == nil {
50		return nil
51	}
52	start, end := s.Range()
53	geometry := newEditorGeometry(s, n, display, password)
54	lines := geometry.lines
55	var result []layout.Command
56	for i, line := range lines {
57		h := geometry.lineHeight(i)
58		for j := 0; j+1 < len(line); j += 2 {
59			a, b := line[j], line[j+1]
60			if a.byteOffset == b.byteOffset {
61				continue
62			}
63			low, high := a.byteOffset, b.byteOffset
64			if low > high {
65				low, high = high, low
66			}
67			if start < high && end > low && start != end {
68				x := math.Min(a.x, b.x)
69				w := math.Abs(a.x - b.x)
70				if w > 0 {
71					result = append(result, layout.Command{Op: "selection", ID: n.ID, Rect: layout.Rect{X: x, Y: a.y, W: w, H: h}, Color: selectionColor, Opacity: 1})
72				}
73			}
74		}
75	}
76	if focused {
77		// The caret uses the preceding character's trailing edge when an
78		// offset has several visual positions.
79		point, found := geometry.caret(s.Cursor)
80		if !found && len(lines) == 0 {
81			result = append(result, layout.Command{Op: "caret", ID: n.ID, Rect: layout.Rect{X: n.Content.X, Y: n.Content.Y, W: 1, H: n.Content.H}, Color: caretColor, Opacity: 1})
82		}
83		if found {
84			result = append(result, layout.Command{Op: "caret", ID: n.ID, Rect: layout.Rect{X: point.x, Y: point.y, W: 1, H: geometry.lineHeight(point.line)}, Color: caretColor, Opacity: 1})
85		}
86	}
87	return result
88}

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 1

Tags 12

↑↓ moveenter openesc close