Documentation
¶
Overview ¶
Package prettyview provides a memory-efficient, virtualized Fyne widget for viewing structured data — JSON, JSONC, XML, HTML, and raw text — in the style of Bruno's response viewer: syntax highlighting, per-node expand/fold with collapse summaries, copy-subtree, true character-level free-text selection, and incremental search.
The widget is built around a hard memory bound: only the rows currently visible in the viewport ever exist as live fyne.CanvasObjects. Everything else lives in a compact struct-of-arrays document model, and selection, search, and copy all operate on that model rather than on widgets. As a result a multi-megabyte document occupies a small, predictable number of canvas objects regardless of its size.
Threading ¶
PrettyView follows the standard Fyne widget threading model: it is NOT safe for concurrent use. Every method — including the data, fold, selection, and search mutators (SetData, SetText, Reparse, ExpandAll, CollapseAll, ExpandTo, Search, SearchNext/Prev, ClearSearch, SelectAll, ClearSelection, SetTheme, …) — must be called on the goroutine that runs the Fyne event loop (the "main"/Fyne goroutine), exactly like any other Fyne widget. To drive the widget from another goroutine (e.g. after a network fetch), marshal the call with fyne.Do:
go func() {
data := fetch()
fyne.Do(func() { pv.SetData(data, prettyview.FormatAuto) })
}()
The widget intentionally holds no locks: all of its state (the document, the fold index, and the selection/search state) is owned by the Fyne goroutine, so single-threaded access is a precondition rather than something guarded at runtime. The only work that runs off that goroutine is the search-debounce timer (time.AfterFunc); it marshals its scan back via fyne.Do and drops superseded scans via a generation counter, so it never touches widget state concurrently.
Index ¶
- Constants
- func NewFoldButtons(pv *PrettyView) fyne.CanvasObject
- func NewFormatSelect(pv *PrettyView) fyne.CanvasObject
- func NewSearchBar(pv *PrettyView) fyne.CanvasObject
- func NewToolbar(pv *PrettyView, cfg ToolbarConfig) fyne.CanvasObject
- func NewWrapToggle(pv *PrettyView) fyne.CanvasObject
- func ShowOpenDialog(pv *PrettyView, win fyne.Window)
- type Format
- type Match
- type Option
- func WithDefaultCollapseDepth(d int) Option
- func WithFormat(f Format) Option
- func WithIndentStep(px float32) Option
- func WithSearchConfig(s SearchConfig) Option
- func WithSyntaxColors(v fyne.ThemeVariant, s SyntaxColors) Option
- func WithTabWidth(n int) Option
- func WithTheme(v fyne.ThemeVariant, t Theme) Option
- func WithWrap(m WrapMode) Option
- type PrettyView
- func (pv *PrettyView) ClearSearch()
- func (pv *PrettyView) ClearSelection()
- func (pv *PrettyView) CollapseAll()
- func (pv *PrettyView) CopySelection()
- func (pv *PrettyView) CopySubtree(byteOffset int)
- func (pv *PrettyView) CreateRenderer() fyne.WidgetRenderer
- func (pv *PrettyView) Cursor() desktop.Cursor
- func (pv *PrettyView) DragEnd()
- func (pv *PrettyView) Dragged(ev *fyne.DragEvent)
- func (pv *PrettyView) ExpandAll()
- func (pv *PrettyView) ExpandTo(off int)
- func (pv *PrettyView) FocusGained()
- func (pv *PrettyView) FocusLost()
- func (pv *PrettyView) Format() Format
- func (pv *PrettyView) MouseDown(ev *desktop.MouseEvent)
- func (pv *PrettyView) MouseIn(*desktop.MouseEvent)
- func (pv *PrettyView) MouseMoved(ev *desktop.MouseEvent)
- func (pv *PrettyView) MouseOut()
- func (pv *PrettyView) MouseUp(*desktop.MouseEvent)
- func (pv *PrettyView) Reparse(format Format)
- func (pv *PrettyView) Search(q SearchQuery)
- func (pv *PrettyView) SearchNext()
- func (pv *PrettyView) SearchPrev()
- func (pv *PrettyView) SearchStatus() (active, total int, capped bool)
- func (pv *PrettyView) SelectAll()
- func (pv *PrettyView) SelectedText() string
- func (pv *PrettyView) SetData(src []byte, format Format)
- func (pv *PrettyView) SetDefaultCollapseDepth(depth int)
- func (pv *PrettyView) SetOnDataChanged(fn func())
- func (pv *PrettyView) SetOnSearchChanged(fn func())
- func (pv *PrettyView) SetOnSearchRequested(fn func())
- func (pv *PrettyView) SetSyntaxColors(variant fyne.ThemeVariant, c SyntaxColors)
- func (pv *PrettyView) SetText(s string)
- func (pv *PrettyView) SetTheme(variant fyne.ThemeVariant, t Theme)
- func (pv *PrettyView) SetWrap(mode WrapMode)
- func (pv *PrettyView) Source() []byte
- func (pv *PrettyView) Tapped(e *fyne.PointEvent)
- func (pv *PrettyView) TappedSecondary(e *fyne.PointEvent)
- func (pv *PrettyView) TypedKey(ev *fyne.KeyEvent)
- func (pv *PrettyView) TypedRune(rune)
- func (pv *PrettyView) TypedShortcut(s fyne.Shortcut)
- func (pv *PrettyView) Wrap() WrapMode
- type SearchConfig
- type SearchMode
- type SearchQuery
- type SyntaxColors
- type Theme
- type ToolbarConfig
- type WrapMode
Constants ¶
const ( FormatAuto = model.FormatAuto // run AutoDetect heuristics FormatRaw = model.FormatRaw // plain text, split into physical lines FormatJSON = model.FormatJSON // strict JSON FormatJSONC = model.FormatJSONC // JSON with // and /* */ comments FormatXML = model.FormatXML // XML FormatHTML = model.FormatHTML // HTML (tolerant) )
Variables ¶
This section is empty.
Functions ¶
func NewFoldButtons ¶
func NewFoldButtons(pv *PrettyView) fyne.CanvasObject
NewFoldButtons returns an expand-all / collapse-all icon pair bound to pv.
func NewFormatSelect ¶
func NewFormatSelect(pv *PrettyView) fyne.CanvasObject
NewFormatSelect returns a format selector bound to pv. Choosing a format re-parses the current source; the selection follows the document when content is loaded elsewhere (it registers PrettyView's data-changed hook).
func NewSearchBar ¶
func NewSearchBar(pv *PrettyView) fyne.CanvasObject
NewSearchBar returns a find box (with prev/next and a self-updating match counter) bound to pv. It registers PrettyView's search-changed and search-requested hooks so the counter stays in sync and Ctrl/Cmd+F focuses it.
func NewToolbar ¶
func NewToolbar(pv *PrettyView, cfg ToolbarConfig) fyne.CanvasObject
NewToolbar builds an optional control bar bound to pv from cfg. Disabled controls are omitted. The result is a plain fyne.CanvasObject; place it where you like (typically the top of a container.NewBorder around the PrettyView).
func NewWrapToggle ¶
func NewWrapToggle(pv *PrettyView) fyne.CanvasObject
NewWrapToggle returns a wrap-text icon toggle bound to pv: it flips between soft-wrap (WrapWord) and horizontal scroll (WrapNone), and is highlighted (HighImportance) while wrapping is on so the state is visible.
func ShowOpenDialog ¶
func ShowOpenDialog(pv *PrettyView, win fyne.Window)
ShowOpenDialog opens Fyne's built-in file-open dialog (an in-canvas widget, not the OS-native picker — Fyne draws its own UI) and loads the chosen file into pv, auto-detecting the format. Exposed so hosts can trigger it from their own menu/button. A host that wants the platform-native dialog should instead set ToolbarConfig.OnOpen (or call its own picker) and feed the bytes to pv.SetData.
Types ¶
type Format ¶
Format selects (or, with FormatAuto, detects) the input grammar. It is an alias of the model package's type so the document model and the public API share one type while keeping the model internal.
type Match ¶
Match is one search hit, in model coordinates: a stable display-line index and a rune column range into that line's expanded text. Keying by line (not visible row) makes matches survive folding; the visible row is an O(log n) lookup.
type Option ¶
type Option func(*config)
Option customizes a PrettyView at construction time.
func WithDefaultCollapseDepth ¶
WithDefaultCollapseDepth auto-collapses every container deeper than d on load (d <= 0 disables auto-collapse).
func WithFormat ¶
WithFormat forces a specific input format, skipping auto-detection.
func WithIndentStep ¶
WithIndentStep sets the pixels of indentation per nesting level.
func WithSearchConfig ¶
func WithSearchConfig(s SearchConfig) Option
WithSearchConfig overrides the search tuning parameters. The struct is used as given — it replaces the defaults wholesale, not field-by-field. A zero MaxMatches or MinQueryLen still falls back to its default at scan time, but a zero DebounceFor means "no debounce" (scan on every keystroke), NOT 150 ms; set it explicitly to keep keystroke coalescing.
func WithSyntaxColors ¶
func WithSyntaxColors(v fyne.ThemeVariant, s SyntaxColors) Option
WithSyntaxColors overrides just the syntax token colors for a theme variant (shorthand for WithTheme with only the token fields set).
func WithTabWidth ¶
WithTabWidth sets the display width of a tab character (default 4).
type PrettyView ¶
type PrettyView struct {
widget.BaseWidget
// contains filtered or unexported fields
}
PrettyView is the virtualized structured-data viewer widget.
All state is unexported. Construct one with New or NewWithData and feed it content with SetData / SetText.
PrettyView is not safe for concurrent use: call its methods on the Fyne goroutine (see the package doc's Threading section).
func New ¶
func New(opts ...Option) *PrettyView
New constructs an empty PrettyView, applying zero or more Options.
func NewWithData ¶
func NewWithData(src []byte, format Format, opts ...Option) *PrettyView
NewWithData constructs a PrettyView and immediately parses src under format.
func (*PrettyView) ClearSearch ¶
func (pv *PrettyView) ClearSearch()
ClearSearch clears search state and highlights. It also cancels any pending debounced scan so a stale query can't repopulate matches after a clear (this is the path SetData uses, so loading new data drops the old document's pending search too).
func (*PrettyView) ClearSelection ¶
func (pv *PrettyView) ClearSelection()
ClearSelection drops any selection.
func (*PrettyView) CollapseAll ¶
func (pv *PrettyView) CollapseAll()
CollapseAll collapses every node below the top level.
func (*PrettyView) CopySelection ¶
func (pv *PrettyView) CopySelection()
CopySelection copies SelectedText to the clipboard (no-op if empty).
func (*PrettyView) CopySubtree ¶
func (pv *PrettyView) CopySubtree(byteOffset int)
CopySubtree copies the serialized text of the node owning byteOffset (the whole {…}/[…]/<tag>…</tag> span), regardless of fold state.
func (*PrettyView) CreateRenderer ¶
func (pv *PrettyView) CreateRenderer() fyne.WidgetRenderer
CreateRenderer implements fyne.Widget. It builds the scroll + layered content and wires scrolling to the visible-window reflow.
func (*PrettyView) Cursor ¶
func (pv *PrettyView) Cursor() desktop.Cursor
Cursor reports the pointer shape: a pointer over a fold triangle, the text I-beam elsewhere. The over-triangle flag is updated by hover tracking.
func (*PrettyView) DragEnd ¶
func (pv *PrettyView) DragEnd()
func (*PrettyView) Dragged ¶
func (pv *PrettyView) Dragged(ev *fyne.DragEvent)
func (*PrettyView) ExpandTo ¶
func (pv *PrettyView) ExpandTo(off int)
ExpandTo expands every collapsed ancestor of the node owning byte offset off (JSON only; XML/HTML lack source offsets) and scrolls it into view.
func (*PrettyView) FocusGained ¶
func (pv *PrettyView) FocusGained()
func (*PrettyView) FocusLost ¶
func (pv *PrettyView) FocusLost()
func (*PrettyView) Format ¶
func (pv *PrettyView) Format() Format
Format reports the format actually used for the current document.
func (*PrettyView) MouseDown ¶
func (pv *PrettyView) MouseDown(ev *desktop.MouseEvent)
func (*PrettyView) MouseIn ¶
func (pv *PrettyView) MouseIn(*desktop.MouseEvent)
func (*PrettyView) MouseMoved ¶
func (pv *PrettyView) MouseMoved(ev *desktop.MouseEvent)
func (*PrettyView) MouseOut ¶
func (pv *PrettyView) MouseOut()
func (*PrettyView) MouseUp ¶
func (pv *PrettyView) MouseUp(*desktop.MouseEvent)
func (*PrettyView) Reparse ¶
func (pv *PrettyView) Reparse(format Format)
Reparse re-parses the current source under a different format (e.g. when a UI lets the user override auto-detection). No-op if no document is loaded.
func (*PrettyView) Search ¶
func (pv *PrettyView) Search(q SearchQuery)
Search starts or replaces the active search and reveals the first match. It runs synchronously and returns once matches are computed.
func (*PrettyView) SearchNext ¶
func (pv *PrettyView) SearchNext()
SearchNext moves to the next match (wrapping) and reveals it.
func (*PrettyView) SearchPrev ¶
func (pv *PrettyView) SearchPrev()
SearchPrev moves to the previous match (wrapping) and reveals it.
func (*PrettyView) SearchStatus ¶
func (pv *PrettyView) SearchStatus() (active, total int, capped bool)
SearchStatus returns the active 1-based index, the total match count, and whether the count was capped.
func (*PrettyView) SelectAll ¶
func (pv *PrettyView) SelectAll()
SelectAll selects the entire (currently visible) document.
func (*PrettyView) SelectedText ¶
func (pv *PrettyView) SelectedText() string
SelectedText returns the exact text currently selected, or "".
func (*PrettyView) SetData ¶
func (pv *PrettyView) SetData(src []byte, format Format)
SetData parses src under format (FormatAuto detects) and refreshes the view. Parsing is synchronous; the model it builds is compact (~5x the source) so this is fast even for multi-megabyte input.
The src slice is retained: the model holds zero-copy byte ranges into it, so callers must not mutate src after this call (copy it first if it may change).
func (*PrettyView) SetDefaultCollapseDepth ¶
func (pv *PrettyView) SetDefaultCollapseDepth(depth int)
SetDefaultCollapseDepth sets the auto-collapse depth applied on subsequent SetData calls (0 disables).
func (*PrettyView) SetOnDataChanged ¶
func (pv *PrettyView) SetOnDataChanged(fn func())
SetOnDataChanged registers a callback invoked whenever the document is replaced (SetData/SetText/Reparse). Use it to keep host controls (such as a format selector) in sync. Setting it replaces any previous callback.
func (*PrettyView) SetOnSearchChanged ¶
func (pv *PrettyView) SetOnSearchChanged(fn func())
SetOnSearchChanged registers a callback invoked whenever the search match set or active match changes. Use it to keep a host match counter in sync. Setting it replaces any previous callback.
func (*PrettyView) SetOnSearchRequested ¶
func (pv *PrettyView) SetOnSearchRequested(fn func())
SetOnSearchRequested registers a callback invoked when the user presses the search shortcut (Ctrl/Cmd+F), so a host can focus its search field.
func (*PrettyView) SetSyntaxColors ¶
func (pv *PrettyView) SetSyntaxColors(variant fyne.ThemeVariant, c SyntaxColors)
SetSyntaxColors overrides just the syntax token colors for a theme variant and refreshes (shorthand for SetTheme with only the token fields set).
func (*PrettyView) SetText ¶
func (pv *PrettyView) SetText(s string)
SetText is shorthand for SetData([]byte(s), FormatAuto).
func (*PrettyView) SetTheme ¶
func (pv *PrettyView) SetTheme(variant fyne.ThemeVariant, t Theme)
SetTheme overrides any of the viewer's colors for a theme variant and refreshes. Nil fields keep their defaults; calls compose with earlier WithTheme/WithSyntaxColors/SetTheme overrides for that variant.
func (*PrettyView) SetWrap ¶
func (pv *PrettyView) SetWrap(mode WrapMode)
SetWrap switches long-line handling between WrapNone (horizontal scroll) and WrapWord (soft-wrap to the viewport width) and refreshes. Wrapping is purely presentational: the model, selection, search, and copy are unchanged — a wrapped line still copies as one logical line.
func (*PrettyView) Source ¶
func (pv *PrettyView) Source() []byte
Source returns the bytes of the current document (the originally supplied input), or nil.
func (*PrettyView) Tapped ¶
func (pv *PrettyView) Tapped(e *fyne.PointEvent)
Tapped toggles a fold when the tap lands on a fold triangle. Other taps are left to the selection layer (M8).
func (*PrettyView) TappedSecondary ¶
func (pv *PrettyView) TappedSecondary(e *fyne.PointEvent)
TappedSecondary shows the context menu at the click. This is the standard Fyne pop-up menu — the same themed overlay Entry and read-only selectable text use for their right-click menus (Fyne draws its own UI on the GL canvas, so there is no native OS menu to invoke). A right-click never disturbs the selection (MouseDown returns early for the secondary button), so "Copy" acts on whatever the user had already highlighted.
func (*PrettyView) TypedKey ¶
func (pv *PrettyView) TypedKey(ev *fyne.KeyEvent)
TypedKey handles Escape (clear selection) and keyboard scrolling/navigation: Up/Down scroll one row, PageUp/PageDown one viewport, Home/End jump to the top/ bottom. A multi-megabyte viewer should be navigable without the mouse.
func (*PrettyView) TypedRune ¶
func (pv *PrettyView) TypedRune(rune)
func (*PrettyView) TypedShortcut ¶
func (pv *PrettyView) TypedShortcut(s fyne.Shortcut)
func (*PrettyView) Wrap ¶
func (pv *PrettyView) Wrap() WrapMode
Wrap reports the current long-line handling mode.
type SearchConfig ¶
type SearchConfig struct {
MaxMatches int // cap on stored matches (default 10_000)
DebounceFor time.Duration // keystroke debounce (default 150ms)
MinQueryLen int // shortest query that triggers a scan (default 1)
}
SearchConfig tunes the incremental search behavior. The scan is synchronous on the Fyne goroutine (debounced, and bounded by MaxMatches); see runSearch.
type SearchMode ¶
type SearchMode uint8
SearchMode selects plain-substring or regular-expression matching.
const ( SearchPlain SearchMode = iota SearchRegex )
type SearchQuery ¶
type SearchQuery struct {
Text string
Mode SearchMode
CaseSensitive bool
}
SearchQuery describes an incremental search request.
type SyntaxColors ¶
type SyntaxColors struct {
Key color.Color
String color.Color
Number color.Color
Bool color.Color
Null color.Color
Punct color.Color
Tag color.Color
Attr color.Color
Comment color.Color
}
SyntaxColors is the token-color subset of Theme, kept for the common case of recoloring only the syntax. A nil field keeps the default.
type Theme ¶
type Theme struct {
// Syntax token colors.
Key color.Color
String color.Color
Number color.Color
Bool color.Color
Null color.Color
Punct color.Color
Tag color.Color
Attr color.Color
Comment color.Color
// Structural / UI colors.
Foreground color.Color // default ("plain") text and punctuation fallback
Summary color.Color // fold-summary text, e.g. "{ 6 items }"
IndentGuide color.Color // the vertical indent guide lines
Selection color.Color // free-text selection highlight fill
Match color.Color // inactive search-match highlight fill
ActiveMatch color.Color // active search-match highlight fill
}
Theme is the full set of colors the viewer draws. Any nil field falls back to the built-in default for the active theme variant — and the structural defaults (Foreground, Summary, IndentGuide, Selection) themselves follow the host Fyne app theme, so an un-themed PrettyView blends into its surroundings.
Override per variant with WithTheme (construction) or SetTheme (at runtime). Overrides compose: setting only a few fields leaves the rest at their default, and repeated calls / WithSyntaxColors merge rather than replace.
type ToolbarConfig ¶
type ToolbarConfig struct {
ShowOpen bool // an "Open…" button (needs Window or OnOpen)
ShowFormat bool // a format selector (auto/json/xml/html/raw)
ShowExpandCollapse bool // Expand all / Collapse all buttons
ShowWrap bool // a wrap-text icon toggle (soft-wrap on/off)
ShowSearch bool // a find box with prev/next and a match counter
Window fyne.Window // enables the built-in Open dialog and Ctrl/Cmd+F focus
OnOpen func() // overrides the built-in Open behavior, if set
}
ToolbarConfig selects which built-in controls NewToolbar includes. Each is optional; leave a field false to omit that control and provide your own.
func DefaultToolbarConfig ¶
func DefaultToolbarConfig() ToolbarConfig
DefaultToolbarConfig enables every control.
type WrapMode ¶
type WrapMode uint8
WrapMode controls long-line handling. WrapNone lets long lines overflow and be reached by horizontal scrolling (matching Bruno); WrapWord soft-wraps them to the viewport width (breaking at word boundaries, with a char-break fallback for an unbreakable run). Wrapping is presentational only — selection, search, and copy still operate on whole logical lines.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
prettyview-demo
command
Command prettyview-demo exercises the prettyview widget.
|
Command prettyview-demo exercises the prettyview widget. |
|
internal
|
|
|
geometry
Package geometry holds the integer-rounded layout math that maps between model positions (line, rune column) and content-space pixels.
|
Package geometry holds the integer-rounded layout math that maps between model positions (line, rune column) and content-space pixels. |
|
parse
Package parse turns raw bytes into a model.Document.
|
Package parse turns raw bytes into a model.Document. |
