v0.26.0 ae3a77a

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/jwijenbergh/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 check.
18var _ port.TextInputTarget = (*GTKEntryTarget)(nil)
19
20// NewGTKEntryTarget creates a new GTK entry target for a SearchEntry.
21func NewGTKEntryTarget(entry *gtk.SearchEntry) *GTKEntryTarget {
22	return &GTKEntryTarget{entry: entry}
23}
24
25// InsertText inserts text at the current cursor position.
26func (t *GTKEntryTarget) InsertText(ctx context.Context, text string) error {
27	log := logging.FromContext(ctx)
28
29	if t.entry == nil {
30		log.Warn().Msg("GTKEntryTarget: entry is nil")
31		return nil
32	}
33
34	// Get current text and cursor position
35	currentText := t.entry.GetText()
36	pos := t.entry.GetPosition()
37
38	// Convert to runes for proper Unicode handling
39	runes := []rune(currentText)
40	textRunes := []rune(text)
41
42	// Clamp position to valid range
43	if pos < 0 {
44		pos = 0
45	}
46	if pos > len(runes) {
47		pos = len(runes)
48	}
49
50	// Build new text with insertion
51	newRunes := make([]rune, 0, len(runes)+len(textRunes))
52	newRunes = append(newRunes, runes[:pos]...)
53	newRunes = append(newRunes, textRunes...)
54	newRunes = append(newRunes, runes[pos:]...)
55
56	// Set new text and cursor position
57	t.entry.SetText(string(newRunes))
58	newPos := pos + len(textRunes)
59	t.entry.SetPosition(newPos)
60
61	log.Debug().
62		Str("text", text).
63		Int("pos", pos).
64		Msg("inserted text into GTK entry")
65
66	return nil
67}
68
69// DeleteBeforeCursor deletes n characters before the cursor position.
70func (t *GTKEntryTarget) DeleteBeforeCursor(ctx context.Context, n int) error {
71	log := logging.FromContext(ctx)
72
73	if t.entry == nil {
74		log.Warn().Msg("GTKEntryTarget: entry is nil")
75		return nil
76	}
77
78	pos := t.entry.GetPosition()
79	if pos < n {
80		n = pos // Don't delete more than available
81	}
82
83	if n <= 0 {
84		return nil
85	}
86
87	// DeleteText takes start and end positions
88	t.entry.DeleteText(pos-n, pos)
89
90	log.Debug().
91		Int("n", n).
92		Int("pos", pos).
93		Msg("deleted text before cursor in GTK entry")
94
95	return nil
96}

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