gtk_entry_target.go RawHistoryFolder

1package textinput
2
3import (
4	"context"
5
6	"github.com/bnema/dumber/internal/application/port"
7	"github.com/bnema/dumber/internal/logging"
8	"github.com/bnema/puregotk/v4/gtk"
9)
10
11// GTKEntryTarget implements TextInputTarget for GTK SearchEntry widgets.
12// It uses the Editable interface methods to insert and delete text.
13type GTKEntryTarget struct {
14	entry *gtk.SearchEntry
15}
16
17// Compile-time interface checks.
18var _ port.TextInputTarget = (*GTKEntryTarget)(nil)
19var _ port.EntryInputTarget = (*GTKEntryTarget)(nil)
20
21// IsGTKEntryTarget implements port.EntryInputTarget.
22func (*GTKEntryTarget) IsGTKEntryTarget() bool { return true }
23
24// NewGTKEntryTarget creates a new GTK entry target for a SearchEntry.
25func NewGTKEntryTarget(entry *gtk.SearchEntry) *GTKEntryTarget {
26	return &GTKEntryTarget{entry: entry}
27}
28
29// InsertText inserts text at the current cursor position.
30func (t *GTKEntryTarget) InsertText(ctx context.Context, text string) error {
31	log := logging.FromContext(ctx)
32
33	if t.entry == nil {
34		log.Warn().Msg("GTKEntryTarget: entry is nil")
35		return nil
36	}
37
38	// Get current text and cursor position
39	currentText := t.entry.GetText()
40	pos := t.entry.GetPosition()
41
42	// Convert to runes for proper Unicode handling
43	runes := []rune(currentText)
44	textRunes := []rune(text)
45
46	// Clamp position to valid range
47	if pos < 0 {
48		pos = 0
49	}
50	if pos > len(runes) {
51		pos = len(runes)
52	}
53
54	// Build new text with insertion
55	newRunes := make([]rune, 0, len(runes)+len(textRunes))
56	newRunes = append(newRunes, runes[:pos]...)
57	newRunes = append(newRunes, textRunes...)
58	newRunes = append(newRunes, runes[pos:]...)
59
60	// Set new text and cursor position
61	t.entry.SetText(string(newRunes))
62	newPos := pos + len(textRunes)
63	t.entry.SetPosition(newPos)
64
65	log.Debug().
66		Str("text", text).
67		Int("pos", pos).
68		Msg("inserted text into GTK entry")
69
70	return nil
71}
72
73// DeleteBeforeCursor deletes n characters before the cursor position.
74func (t *GTKEntryTarget) DeleteBeforeCursor(ctx context.Context, n int) error {
75	log := logging.FromContext(ctx)
76
77	if t.entry == nil {
78		log.Warn().Msg("GTKEntryTarget: entry is nil")
79		return nil
80	}
81
82	pos := t.entry.GetPosition()
83	if pos < n {
84		n = pos // Don't delete more than available
85	}
86
87	if n <= 0 {
88		return nil
89	}
90
91	// DeleteText takes start and end positions
92	t.entry.DeleteText(pos-n, pos)
93
94	log.Debug().
95		Int("n", n).
96		Int("pos", pos).
97		Msg("deleted text before cursor in GTK entry")
98
99	return nil
100}

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