v / examples / flag_layout_editor.v
243 lines · 227 sloc · 5.25 KB · f5013e569367f0b3e953920e9344c4e836024c3a
Raw
1import term.ui as tui
2import flag
3
4@[name: 'flag_layout_editor']
5@[version: '1.0']
6struct DocTest {
7 show_version bool @[short: v; xdoc: 'Show version and exit']
8 debug_level int @[long: debug; short: d; xdoc: 'Debug level']
9 level f32 @[only: l; xdoc: 'Do not show this']
10 example string
11 square bool
12 multi int @[only: m; repeats]
13 wroom []int @[short: w]
14 the_limit string
15}
16
17const field_docs = {
18 'level': 'Level of lorem ipsum\nand more\nmany many many more.\nNotice how user newlines/format is kept since\ninput lines are all less or within\nthe default layout.description_padding\nand max width'
19 'example': 'Looong example text without newlines or anything else and lorem ipsum and more and many many many more. Should be auto fitted'
20 'the_limit': 'Looongbobbytextwithoutnewlinesoranythingelseandlorem ipsumandmoreandmanymanymanymore ffffffffffffffffffffffffffffffff f'
21 'multi': 'This flag can be repeated'
22 '-e, --extra': 'Secret flag that does not exist on the struct, but we want documented (in same format as the others)'
23 '-q, --quiet-and-quite-long-flag <string>': 'Mega long description and secret flag that does not exist on the struct, but we want documented. Also the flag has custom newlines\nand the flag line itself is super long'
24}
25
26struct App {
27mut:
28 tui &tui.Context = unsafe { nil }
29 layout flag.DocLayout
30 options flag.DocOptions
31 edit Edit
32}
33
34enum Edit {
35 // DocLayout fields
36 description_padding
37 description_width
38 flag_indent
39 // DocOptions.compact
40 compact
41 // DocOptions.show flags
42 name
43 version
44 flags
45 flag_type
46 flag_hint
47 description
48 flags_header
49 footer
50}
51
52pub fn (e Edit) next() Edit {
53 return match e {
54 .description_padding {
55 .description_width
56 }
57 .description_width {
58 .flag_indent
59 }
60 .flag_indent {
61 .compact
62 }
63 .compact {
64 .name
65 }
66 .name {
67 .version
68 }
69 .version {
70 .flags
71 }
72 .flags {
73 .flag_type
74 }
75 .flag_type {
76 .flag_hint
77 }
78 .flag_hint {
79 .description
80 }
81 .description {
82 .flags_header
83 }
84 .flags_header {
85 .footer
86 }
87 .footer {
88 .description_padding
89 }
90 }
91}
92
93fn event(e &tui.Event, mut app App) {
94 mut incr_decr := 0
95 match e.typ {
96 .mouse_down {
97 app.edit = app.edit.next()
98 }
99 .mouse_drag {}
100 .mouse_up {}
101 .key_down {
102 match e.code {
103 .left {
104 incr_decr = -1
105 }
106 .right {
107 incr_decr = 1
108 }
109 .space {
110 app.edit = app.edit.next()
111 }
112 .escape {
113 exit(0)
114 }
115 else {}
116 }
117 }
118 else {}
119 }
120
121 if incr_decr != 0 {
122 match app.edit {
123 .flag_indent {
124 app.layout.flag_indent += incr_decr
125 }
126 .description_padding {
127 app.layout.description_padding += incr_decr
128 }
129 .description_width {
130 app.layout.description_width += incr_decr
131 }
132 .compact {
133 app.options.compact = !app.options.compact
134 }
135 .name {
136 app.options.show.toggle(.name)
137 }
138 .version {
139 app.options.show.toggle(.version)
140 }
141 .flags {
142 app.options.show.toggle(.flags)
143 }
144 .flag_type {
145 app.options.show.toggle(.flag_type)
146 }
147 .flag_hint {
148 app.options.show.toggle(.flag_hint)
149 }
150 .description {
151 app.options.show.toggle(.description)
152 }
153 .flags_header {
154 app.options.show.toggle(.flags_header)
155 }
156 .footer {
157 app.options.show.toggle(.footer)
158 }
159 }
160 }
161}
162
163fn frame(mut app App) {
164 app.tui.clear()
165
166 mut value := match app.edit {
167 .flag_indent {
168 '${app.layout.flag_indent}'
169 }
170 .description_padding {
171 '${app.layout.description_padding}'
172 }
173 .description_width {
174 '${app.layout.description_width}'
175 }
176 .compact {
177 if app.options.compact { 'on' } else { 'off' }
178 }
179 .name {
180 if app.options.show.has(.name) { 'on' } else { 'off' }
181 }
182 .version {
183 if app.options.show.has(.version) { 'on' } else { 'off' }
184 }
185 .flags {
186 if app.options.show.has(.flags) { 'on' } else { 'off' }
187 }
188 .flag_type {
189 if app.options.show.has(.flag_type) { 'on' } else { 'off' }
190 }
191 .flag_hint {
192 if app.options.show.has(.flag_hint) { 'on' } else { 'off' }
193 }
194 .description {
195 if app.options.show.has(.description) { 'on' } else { 'off' }
196 }
197 .flags_header {
198 if app.options.show.has(.flags_header) { 'on' } else { 'off' }
199 }
200 .footer {
201 if app.options.show.has(.footer) { 'on' } else { 'off' }
202 }
203 }
204
205 app.tui.draw_text(0, 0, 'Click left-mouse button or use space to edit the next property.
206Use keyboard arrow keys right and left to adjust the value of the property
207Editing property: ${app.edit}, value: ${value}')
208
209 help_text := flag.to_doc[DocTest](
210 description: 'Simple DocLayout editor.
211Press ESCAPE or Ctrl+C to exit and print layout code'
212 footer: '
213Press ESCAPE or Ctrl+C to exit and print layout code'
214 fields: unsafe { field_docs }
215 layout: app.layout
216 options: app.options
217 ) or { '' }
218
219 app.tui.draw_text(0, 5, '${help_text}')
220 app.tui.reset()
221
222 app.tui.flush()
223}
224
225type EventFn = fn (&tui.Event, voidptr)
226
227type FrameFn = fn (voidptr)
228
229fn main() {
230 mut app := &App{}
231 at_exit(fn [app] () {
232 println('${app.layout}\n')
233 println('${app.options}')
234 }) or {}
235 app.tui = tui.init(
236 user_data: app
237 event_fn: EventFn(event)
238 frame_fn: FrameFn(frame)
239 hide_cursor: true
240 frame_rate: 60
241 )
242 app.tui.run()!
243}
244