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.
Stability ¶
Pre-1.0 (v0.x) the exported API may change between minor versions (see CHANGELOG.md). As of v1.0.0 the surface is frozen under semantic import versioning: additions ship as v1.x and any breaking change ships under a new major module path (.../v2). The frozen surface is pinned by TestExportedSurfaceGolden.
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 WithLineNumbers() Option
- func WithMaxInputBytes(n int) 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) CollapseToDepth(depth int)
- func (pv *PrettyView) CopySelection()
- func (pv *PrettyView) CopySubtree(byteOffset int) bool
- 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) bool
- func (pv *PrettyView) ExpandToDepth(depth int)
- func (pv *PrettyView) FocusGained()
- func (pv *PrettyView) FocusLost()
- func (pv *PrettyView) Format() Format
- func (pv *PrettyView) KeyDown(key *fyne.KeyEvent)
- func (pv *PrettyView) KeyUp(key *fyne.KeyEvent)
- func (pv *PrettyView) Matches() []Match
- 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) ScrollOffset() fyne.Position
- func (pv *PrettyView) ScrollToLine(line int) bool
- func (pv *PrettyView) Search(q SearchQuery)
- func (pv *PrettyView) SearchDebounced(q SearchQuery)
- func (pv *PrettyView) SearchError() error
- 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) SetScrollOffset(p fyne.Position)
- 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
Examples ¶
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 case-sensitive and regex toggles, 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. Enter finds next, Shift+Enter finds previous, Esc clears.
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 [ColStart,ColEnd) into that line's expanded text. All three are int. Keying by line (not visible row) makes a match survive folding; the visible row is an O(log n) lookup. Retrieve the current hits with PrettyView.Matches.
type Option ¶
type Option func(*config)
Option customizes a PrettyView at construction time.
func WithDefaultCollapseDepth ¶
WithDefaultCollapseDepth auto-collapses every container at nesting depth d or deeper on load. Top-level containers are at depth 0, so d=1 collapses everything below the root and d=0 (or any 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 WithLineNumbers ¶
func WithLineNumbers() Option
WithLineNumbers renders a line-number gutter to the left of the content. Numbers are the logical display-line indices (1-based) drawn from the struct-of-arrays model, so no extra widgets are created per line and the virtualization invariant holds; wrap-continuation rows leave the gutter blank. Off by default.
func WithMaxInputBytes ¶
WithMaxInputBytes caps the source size SetData/SetText will load. Input longer than n bytes is truncated to n before parsing (the parsers are tolerant, so a truncated document still renders). It bounds the synchronous parse work and the resulting model size (≈5–7× the source, built on the calling/Fyne goroutine) for untrusted or unbounded input. n <= 0 (the default) imposes no cap beyond the model's 4 GiB source ceiling.
func WithSearchConfig ¶
func WithSearchConfig(s SearchConfig) Option
WithSearchConfig overrides the search tuning parameters, merging field-by-field: each NON-ZERO field of s replaces the default, and a zero field keeps its default (MaxMatches 10_000, DebounceFor 150ms, MinQueryLen 1). So setting only MaxMatches leaves debouncing at its default — there is no zero-value trap. To DISABLE keystroke debouncing, set a negative DebounceFor (e.g. -1), or drive input through Search, which always scans immediately (SearchDebounced is the coalescing path).
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.
Example ¶
ExampleNew builds a viewer, loads JSON with auto-detection, adds the optional toolbar, and shows it.
package main
import (
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/container"
prettyview "github.com/ideaconnect/go-fyne-pretty-view"
)
func main() {
a := app.New()
w := a.NewWindow("viewer")
pv := prettyview.New(prettyview.WithWrap(prettyview.WrapWord))
pv.SetData([]byte(`{"hello":"world","items":[1,2,3]}`), prettyview.FormatAuto)
bar := prettyview.NewToolbar(pv, prettyview.ToolbarConfig{
ShowSearch: true,
ShowExpandCollapse: true,
ShowWrap: true,
})
w.SetContent(container.NewBorder(bar, nil, nil, nil, pv))
w.ShowAndRun()
}
Output:
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) CollapseToDepth ¶
func (pv *PrettyView) CollapseToDepth(depth int)
CollapseToDepth collapses every container at nesting depth >= depth (top level is depth 0), leaving shallower containers as they are, and refreshes. ExpandToDepth expands every container at depth < depth. The two compose — e.g. ExpandToDepth(d) then CollapseToDepth(d) shows the tree exactly down to depth d. Call on the Fyne goroutine.
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) bool
CopySubtree copies the displayed text of the node owning byteOffset (its whole {…}/[…]/<tag>…</tag> span, regardless of fold state) to the clipboard, reporting whether a node was found and copied. Source byte offsets are populated for every structured format (JSON/JSONC/XML/HTML); an out-of-range offset returns false. The copied text is the viewer's pretty-printed rendering of the subtree, not the original bytes. (The right-click "Copy subtree" menu item does the same without an offset, for any format.)
Example ¶
ExamplePrettyView_CopySubtree copies a node's whole subtree to the clipboard by its source byte offset (JSON/JSONC; XML/HTML carry no per-node offset and return false). The right-click "Copy subtree" menu item does the same for any format.
package main
import (
prettyview "github.com/ideaconnect/go-fyne-pretty-view"
)
func main() {
pv := prettyview.NewWithData([]byte(`{"user":{"name":"ada","id":1}}`), prettyview.FormatJSON)
// Byte offset of the '{' opening the "user" object in the source.
pv.CopySubtree(8) // -> true; the "user" subtree is now on the clipboard
}
Output:
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) bool
ExpandTo expands every collapsed ancestor of the node owning byte offset off and scrolls it into view, reporting whether such a node was found. Source byte offsets are populated for every structured format (JSON/JSONC/XML/HTML), so this resolves a node on each; an out-of-range offset returns false without scrolling. See ScrollToLine for a line-index alternative.
func (*PrettyView) ExpandToDepth ¶
func (pv *PrettyView) ExpandToDepth(depth int)
ExpandToDepth expands every container at nesting depth < depth (see CollapseToDepth).
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) KeyDown ¶
func (pv *PrettyView) KeyDown(key *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. KeyDown / KeyUp track the Shift modifier (fyne.KeyEvent carries none), so TypedKey can tell Shift+arrow (extend the keyboard selection) from a plain arrow (scroll).
func (*PrettyView) KeyUp ¶
func (pv *PrettyView) KeyUp(key *fyne.KeyEvent)
func (*PrettyView) Matches ¶
func (pv *PrettyView) Matches() []Match
Matches returns a snapshot of the current search hits in document order (nil if there is no active search), letting a host build its own match list or minimap. The returned slice is a copy — mutating it does not affect the viewer, and it is not updated as the document or search changes; call Matches again after a Search.
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) ScrollOffset ¶
func (pv *PrettyView) ScrollOffset() fyne.Position
ScrollOffset returns the current content-space scroll offset (the viewport's top-left). Pair it with SetScrollOffset to save and restore scroll position across a reload or a layout change. Reports the zero position before the widget is shown.
func (*PrettyView) ScrollToLine ¶
func (pv *PrettyView) ScrollToLine(line int) bool
ScrollToLine reveals the given display line (expanding any collapsed ancestors) and scrolls it to the center of the viewport, reporting whether the index is in range. Unlike ExpandTo it takes a display-line index in [0, TotalLines), so it works for every format. Call it on the Fyne goroutine.
func (*PrettyView) Search ¶
func (pv *PrettyView) Search(q SearchQuery)
Search starts or replaces the active search and reveals the first match. It is the IMMEDIATE path: it scans synchronously and returns once matches are computed, and it never debounces. For per-keystroke input from a host search field, prefer SearchDebounced (which coalesces a burst into one scan); use Search when you want the scan to happen now. q.Mode selects SearchPlain or SearchRegex. Call it on the Fyne goroutine.
Example ¶
ExamplePrettyView_Search runs a regular-expression search, reads the live match counter, and steps to the next match.
package main
import (
prettyview "github.com/ideaconnect/go-fyne-pretty-view"
)
func main() {
pv := prettyview.NewWithData([]byte(`{"a":"x1","b":"x2","c":"yy"}`), prettyview.FormatJSON)
pv.Search(prettyview.SearchQuery{Text: `x\d`, Mode: prettyview.SearchRegex})
pv.SearchStatus() // -> (active, total, capped); total is 2 here
pv.SearchNext() // advance to the next match (wraps at the end)
}
Output:
func (*PrettyView) SearchDebounced ¶
func (pv *PrettyView) SearchDebounced(q SearchQuery)
SearchDebounced runs Search(q) after the configured SearchConfig.DebounceFor delay, coalescing a burst of rapid calls (e.g. one per keystroke from a host's own search field) so only the last query in the burst scans. With DebounceFor <= 0 it is equivalent to Search (immediate); since WithSearchConfig treats a zero DebounceFor as "keep the 150ms default", pass a NEGATIVE DebounceFor (or call Search) to disable debouncing. Last call wins: a newer SearchDebounced / Search / ClearSearch / SetData supersedes a still-pending scan. Call it on the Fyne goroutine.
func (*PrettyView) SearchError ¶
func (pv *PrettyView) SearchError() error
SearchError reports the error from the most recent Search / SearchDebounced, or nil. The only error is an invalid regular expression (a SearchRegex query whose pattern does not compile); it lets a caller distinguish "the pattern is bad" from "the pattern is valid but matched nothing". It is cleared by the next Search/ClearSearch.
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 on the calling goroutine (the Fyne goroutine), and builds a compact model ≈5–7× the source size. That is fast for multi-megabyte input but is still O(source) work done before this call returns; to load a large document without a UI hitch, parse off-thread is not supported, so either keep inputs bounded (see WithMaxInputBytes) or accept a brief synchronous cost. Input longer than WithMaxInputBytes (if set) is truncated before parsing.
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) SetScrollOffset ¶
func (pv *PrettyView) SetScrollOffset(p fyne.Position)
SetScrollOffset scrolls so p (content space) is the viewport's top-left, clamped to the valid range — e.g. to restore a previously saved ScrollOffset. No-op before the widget is shown. Call it on the Fyne goroutine.
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. The returned slice ALIASES the document's retained input buffer; treat it as read-only and copy before mutating, or you corrupt the model the viewer renders from.
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)
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 matches the query as a literal substring (the default). SearchPlain SearchMode = iota // SearchRegex matches the query as a Go regular expression (regexp/RE2). RE2 // matches in time linear in the input, so a host-supplied pattern cannot cause // catastrophic backtracking (no ReDoS); an invalid pattern is reported via // SearchError. A pathological pattern can still be expensive to compile, so treat // the pattern as you would any host input. 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/jsonc/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(win fyne.Window) ToolbarConfig
DefaultToolbarConfig enables every control bound to win: the Open button (its built-in file dialog and Ctrl/Cmd+F search-focus both need a Window). Pass nil to omit those two (or set OnOpen yourself afterward to drive Open without a Window).
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. |
|
Package fonttheme bundles the typefaces go-fyne-pretty-view ships with — JetBrains Mono for monospace (the viewer body) and Inter for UI text — and exposes them as a fyne.Theme you can install on your app.
|
Package fonttheme bundles the typefaces go-fyne-pretty-view ships with — JetBrains Mono for monospace (the viewer body) and Inter for UI text — and exposes them as a fyne.Theme you can install on your app. |
|
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. |
