v0.4.0 2de4e1d

nefergui.go RawHistoryFolder

1// Package nefergui provides a pure-Go immediate-mode GUI for Wayland, rendered with
2// Vulkan and styled with a bounded CSS dialect (see docs/css.md).
3//
4// Run opens a window and calls the view function to build each frame. The view
5// receives a Frame; Frame and its Node handles are valid only during that call.
6// Key identifies a child among its siblings across frames; without a key,
7// position and type determine identity. ID is CSS metadata, not frame identity.
8// Options such as Title, Size, Styles and Transparent configure the window.
9//
10// The frame tree, controls, editors and input routing are implemented in
11// internal/ui; this package is the public facade and re-exports those types.
12//
13// Builds support CGO_ENABLED=0. At runtime, NeferGUI requires libvulkan.so.1,
14// libxkbcommon.so.0 and a Wayland compositor supporting linux-dmabuf and
15// linux-drm-syncobj. See docs/runtime.md and docs/troubleshooting.md.
16package nefergui
17
18import (
19	"context"
20
21	"github.com/bnema/nefergui/internal/ui"
22)
23
24// Frame is valid only during one call to the view function. Root builds the
25// application element; Diagnostics reports identity problems in debug builds.
26// Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.Frame.
27type Frame = ui.Frame
28
29// Node is an ephemeral handle into the current frame. Do not retain it between
30// frames. Container methods (Box, Row, Column, Stack, Scroll, Header, Nav,
31// Main, Section, Aside, Footer, Element) return child nodes; control methods
32// (Button, Checkbox, Radio, Slider, Input, Textarea, Text, Heading, Image,
33// Icon, Separator, Spacer) declare controls. Interactive controls return event
34// snapshots.
35// Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.Node.
36type Node = ui.Node
37
38// ButtonEvent is an immutable snapshot queried with Activated.
39// Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.ButtonEvent.
40type ButtonEvent = ui.ButtonEvent
41
42// EditEvent is an immutable snapshot queried with Changed and Submitted.
43// Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.EditEvent.
44type EditEvent = ui.EditEvent
45
46// ChangeEvent is an immutable snapshot queried with Changed.
47// Alias methods are listed by go doc github.com/bnema/nefergui/internal/ui.ChangeEvent.
48type ChangeEvent = ui.ChangeEvent
49
50// Option families are sealed: ContainerOption, ButtonOption, EditOption,
51// ValueOption and HeadingOption accept the common CSS options (Key, ID,
52// Class, Inline) plus the control-specific options listed on each function.
53type (
54	ContainerOption = ui.ContainerOption
55	ButtonOption    = ui.ButtonOption
56	EditOption      = ui.EditOption
57	ValueOption     = ui.ValueOption
58	HeadingOption   = ui.HeadingOption
59	WindowOption    = ui.WindowOption
60)
61
62// commonOption belongs to every option family; disabledOption to every
63// interactive control family. Both are concrete internal types, aliased so
64// the constructors below can return them without a second implementation.
65type (
66	commonOption   = ui.CommonOption
67	disabledOption = ui.DisabledOption
68)
69
70// Key identifies an element among its siblings across frames.
71func Key(key string) commonOption { return ui.Key(key) }
72
73// ID sets the CSS ID; it does not affect frame identity.
74func ID(id string) commonOption { return ui.ID(id) }
75
76// Class adds a CSS class.
77func Class(class string) commonOption { return ui.Class(class) }
78
79// Inline applies inline CSS declarations.
80func Inline(src string) commonOption { return ui.Inline(src) }
81
82// Disabled blocks focus and interaction on an interactive control.
83func Disabled(v bool) disabledOption { return ui.Disabled(v) }
84
85// Level sets the accessibility heading level (1 through 6).
86func Level(level int) HeadingOption { return ui.Level(level) }
87
88// Placeholder sets the text shown in an empty editor.
89func Placeholder(v string) EditOption { return ui.Placeholder(v) }
90
91// Password masks displayed editor text and blocks copy and cut.
92func Password(v bool) EditOption { return ui.Password(v) }
93
94// Title sets the window title.
95func Title(s string) WindowOption { return ui.Title(s) }
96
97// Size sets the initial logical window size.
98func Size(w, h int) WindowOption { return ui.Size(w, h) }
99
100// Styles loads an author stylesheet from a file path.
101func Styles(s string) WindowOption { return ui.Styles(s) }
102
103// Transparent requests an alpha-capable Wayland surface (opaque by default).
104func Transparent() WindowOption { return ui.Transparent() }
105
106// Layer surface, input and wake configuration. Layer selects a wlr-layer-shell
107// surface instead of an xdg toplevel; OnInput, OnResize and Wake integrate
108// callers that own state outside the view. See internal/ui for details.
109type (
110	LayerConfig  = ui.LayerConfig
111	LayerLevel   = ui.LayerLevel
112	Anchor       = ui.Anchor
113	KeyboardMode = ui.KeyboardMode
114	Rect         = ui.Rect
115	InputEvent   = ui.InputEvent
116	InputKind    = ui.InputKind
117	Modifiers    = ui.Modifiers
118)
119
120const (
121	LayerBackground = ui.LayerBackground
122	LayerBottom     = ui.LayerBottom
123	LayerTop        = ui.LayerTop
124	LayerOverlay    = ui.LayerOverlay
125
126	AnchorTop    = ui.AnchorTop
127	AnchorBottom = ui.AnchorBottom
128	AnchorLeft   = ui.AnchorLeft
129	AnchorRight  = ui.AnchorRight
130
131	KeyboardNone      = ui.KeyboardNone
132	KeyboardExclusive = ui.KeyboardExclusive
133	KeyboardOnDemand  = ui.KeyboardOnDemand
134
135	InputPointerMotion  = ui.InputPointerMotion
136	InputPointerPress   = ui.InputPointerPress
137	InputPointerRelease = ui.InputPointerRelease
138	InputPointerAxis    = ui.InputPointerAxis
139	InputPointerLeave   = ui.InputPointerLeave
140	InputKey            = ui.InputKey
141	InputFocusIn        = ui.InputFocusIn
142	InputFocusOut       = ui.InputFocusOut
143	InputReset          = ui.InputReset
144
145	ModShift = ui.ModShift
146	ModCtrl  = ui.ModCtrl
147)
148
149// Layer makes the window a layer-shell surface.
150func Layer(c LayerConfig) WindowOption { return ui.Layer(c) }
151
152// OnInput receives raw input on the owner loop before control routing; return
153// true to request a redraw.
154func OnInput(fn func(InputEvent) bool) WindowOption { return ui.OnInput(fn) }
155
156// OnResize reports logical size and scale at start and on change only.
157func OnResize(fn func(width, height int, scale float64)) WindowOption { return ui.OnResize(fn) }
158
159// WaylandSurface is the window's Wayland display and wl_surface for OnSurface.
160type WaylandSurface = ui.WaylandSurface
161
162// OnSurface runs fn once after the surface role is configured and before the
163// first buffer; an error aborts Run.
164func OnSurface(fn func(context.Context, WaylandSurface) error) WindowOption { return ui.OnSurface(fn) }
165
166// Wake requests a redraw for each value received on ch.
167func Wake(ch <-chan struct{}) WindowOption { return ui.Wake(ch) }
168
169// Run builds and presents an immediate view on the Wayland session owner loop.
170func Run[T any](ctx context.Context, model *T, view func(*Frame, *T), options ...WindowOption) error {
171	return ui.Run(ctx, model, view, options...)
172}
173
174// RunFrames is a deterministic harness entry: each commit requests a redraw
175// and the loop stops after the given number of committed frames.
176func RunFrames[T any](ctx context.Context, frames int, model *T, view func(*Frame, *T), committed func(uint64) error, options ...WindowOption) error {
177	return ui.RunFrames(ctx, frames, model, view, committed, options...)
178}
179
180// Session lock. RunLock acquires ext-session-lock, covers every output with
181// opaque black through the normal Vulkan/DMA-BUF/explicit-sync path and hosts
182// the caller's view on one output. See docs/session-lock.md.
183type (
184	LockConfig   = ui.LockConfig
185	LockState    = ui.LockState
186	LockStatus   = ui.LockStatus
187	SecretBuffer = ui.SecretBuffer
188)
189
190const (
191	LockIdle   = ui.LockIdle
192	LockBusy   = ui.LockBusy
193	LockFailed = ui.LockFailed
194)
195
196// ErrLockFinished reports that the compositor refused or ended the lock.
197var ErrLockFinished = ui.ErrLockFinished
198
199// NewSecretBuffer allocates a caller-owned secret input buffer (1..4096 bytes).
200func NewSecretBuffer(capacity int) *SecretBuffer { return ui.NewSecretBuffer(capacity) }
201
202// RunLock runs a session lock until an unlock requested on LockConfig.Unlock,
203// a failure, or cancellation. It never unlocks on failure or cancellation.
204func RunLock(ctx context.Context, cfg LockConfig) error { return ui.RunLock(ctx, cfg) }

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