| 1 | import term.ui as tui |
| 2 | import flag |
| 3 | |
| 4 | @[name: 'flag_layout_editor'] |
| 5 | @[version: '1.0'] |
| 6 | struct 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 | |
| 17 | const 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 | |
| 26 | struct App { |
| 27 | mut: |
| 28 | tui &tui.Context = unsafe { nil } |
| 29 | layout flag.DocLayout |
| 30 | options flag.DocOptions |
| 31 | edit Edit |
| 32 | } |
| 33 | |
| 34 | enum 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 | |
| 52 | pub 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 | |
| 93 | fn 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 | |
| 163 | fn 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. |
| 206 | Use keyboard arrow keys right and left to adjust the value of the property |
| 207 | Editing property: ${app.edit}, value: ${value}') |
| 208 | |
| 209 | help_text := flag.to_doc[DocTest]( |
| 210 | description: 'Simple DocLayout editor. |
| 211 | Press ESCAPE or Ctrl+C to exit and print layout code' |
| 212 | footer: ' |
| 213 | Press 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 | |
| 225 | type EventFn = fn (&tui.Event, voidptr) |
| 226 | |
| 227 | type FrameFn = fn (voidptr) |
| 228 | |
| 229 | fn 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 | |