-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprogram.go
More file actions
158 lines (141 loc) · 4.97 KB
/
Copy pathprogram.go
File metadata and controls
158 lines (141 loc) · 4.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package wui
// Model is the user-implemented Elm Architecture model.
type Model interface {
Init() Cmd
Update(Msg) (Model, Cmd)
View() Element
}
// Pather is an optional interface a Model can implement to expose its
// current logical location as a path such as "/" or "/settings".
//
// When the TUI runs with WithWebServer, the status bar link points at
// the equivalent web location ("http://host/#/settings"). In the
// browser, the path is mirrored into location.hash after every update,
// and a NavigateMsg is dispatched on initial load and whenever the
// hash changes (e.g. back/forward navigation), so both platforms stay
// addressable at the same locations.
type Pather interface {
Path() string
}
type config struct {
serveEnabled bool
serveAddr string
webDir string
noBaseCSS bool
keyMap KeyMap
status StatusFunc
noStatusBar bool
title string
noAltScreen bool
noMouse bool
}
// Option configures a Program at construction time.
type Option func(*config)
// WithWebServer serves dir — a WASM build of the same app (index.html,
// main.wasm, wasm_exec.js) — over HTTP for as long as the TUI runs,
// and displays a status bar at the bottom of the TUI linking to the
// equivalent web page.
//
// addr is the listen address, e.g. ":8765" (all interfaces) or
// "127.0.0.1:8765". Pass "" to bind the loopback interface only, on
// the first free port in 8765–8864 (falling back to an OS-assigned
// port if the whole range is busy).
//
// It has no effect in WASM builds, so it is safe to pass
// unconditionally from shared code.
func WithWebServer(addr, dir string) Option {
return func(c *config) {
c.serveEnabled = true
c.serveAddr = addr
c.webDir = dir
}
}
// WithoutBaseCSS disables injection of wui's default terminal-like
// stylesheet in WASM builds. Use it when the host page provides its
// own styling. It has no effect in TUI builds.
func WithoutBaseCSS() Option {
return func(c *config) { c.noBaseCSS = true }
}
// WithKeyMap registers the app's key map with the runtime. wui does not
// dispatch it for you — Update stays the single place where state
// changes — but registering it means the status bar shows the shortcuts
// automatically, and Program.KeyMap can be consulted when building a
// help view.
func WithKeyMap(km KeyMap) Option {
return func(c *config) { c.keyMap = km }
}
// WithStatus supplies the status line content, replacing wui's default
// (the web URL plus the key map's short help). It is called on every
// frame with the current model:
//
// wui.WithStatus(func(m wui.Model) wui.Status {
// return wui.NewStatus().
// Left(m.(model).file).
// Right(fmt.Sprintf("%d items", len(m.(model).items)))
// })
//
// Returning a Status with no items falls back to the default bar;
// return NewStatus().Hide() to suppress the bar for a frame.
//
// The bar renders in both TUI and WASM builds. In the browser it is a
// fixed strip at the bottom of the viewport.
func WithStatus(f StatusFunc) Option {
return func(c *config) { c.status = f }
}
// WithoutStatusBar suppresses the status line on both platforms, even
// when WithWebServer or WithKeyMap would otherwise populate it.
func WithoutStatusBar() Option {
return func(c *config) { c.noStatusBar = true }
}
// WithTitle sets the application title. In WASM builds it becomes
// document.title; in the TUI it sets the terminal window title.
func WithTitle(title string) Option {
return func(c *config) { c.title = title }
}
// WithoutAltScreen runs the TUI inline in the terminal's normal buffer
// instead of the alternate screen, so the final frame stays in the
// scrollback after exit. It has no effect in WASM builds.
func WithoutAltScreen() Option {
return func(c *config) { c.noAltScreen = true }
}
// WithoutMouse disables TUI mouse tracking, leaving click and scroll
// events to the terminal (so text selection works normally). It has no
// effect in WASM builds.
func WithoutMouse() Option {
return func(c *config) { c.noMouse = true }
}
// Program is the wui runtime. Construct with NewProgram and call Run.
type Program struct {
model Model
cfg config
platformState
}
// NewProgram creates a Program for the given model.
func NewProgram(m Model, opts ...Option) *Program {
var cfg config
for _, opt := range opts {
opt(&cfg)
}
return newProgram(m, cfg)
}
// Run starts the program loop, blocking until the program exits.
func (p *Program) Run() error {
return p.run()
}
// KeyMap returns the key map registered with WithKeyMap, or the zero
// KeyMap when none was set.
func (p *Program) KeyMap() KeyMap { return p.cfg.keyMap }
// pathSuffix returns the model's current Path as a URL hash fragment
// ("#/settings"), or "" when the model is not a Pather or sits at the
// root. Both platforms use it to keep TUI and browser addressable at
// the same locations.
func (p *Program) pathSuffix() string {
pather, ok := p.model.(Pather)
if !ok {
return ""
}
if path := pather.Path(); path != "" && path != "/" {
return "#" + path
}
return ""
}