| 1 | // Copyright (c) 2020-2024 Raúl Hernández. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | @[has_globals] |
| 5 | module ui |
| 6 | |
| 7 | struct ExtraContext { |
| 8 | mut: |
| 9 | read_buf []u8 |
| 10 | // read_all_bytes causes all the raw bytes to be read as one event unit. |
| 11 | // This is cruicial for UTF-8 support since Unicode codepoints can span several bytes. |
| 12 | read_all_bytes bool = true |
| 13 | } |
| 14 | |
| 15 | __global ctx_ptr = &Context(unsafe { nil }) |
| 16 | |
| 17 | // init initializes the terminal console with Config `cfg`. |
| 18 | pub fn init(cfg Config) &Context { |
| 19 | caps := current_terminal_capabilities() |
| 20 | mut ctx := &Context{ |
| 21 | cfg: cfg |
| 22 | enable_ansi256: caps.enable_ansi256 |
| 23 | supports_alternate_buffer: caps.supports_alternate_buffer |
| 24 | supports_sgr_mouse: caps.supports_sgr_mouse |
| 25 | supports_sync_updates: caps.supports_sync_updates |
| 26 | supports_window_title: caps.supports_window_title |
| 27 | } |
| 28 | ctx.read_buf = []u8{cap: cfg.buffer_size} |
| 29 | |
| 30 | ctx_ptr = ctx |
| 31 | return ctx |
| 32 | } |
| 33 | |
| 34 | @[inline] |
| 35 | fn save_title() { |
| 36 | mut ctx := ctx_ptr |
| 37 | if unsafe { ctx == 0 } || !ctx.supports_window_title { |
| 38 | return |
| 39 | } |
| 40 | // restore the previously saved terminal title |
| 41 | print('\x1b[22;0t') |
| 42 | flush_stdout() |
| 43 | } |
| 44 | |
| 45 | @[inline] |
| 46 | fn load_title() { |
| 47 | mut ctx := ctx_ptr |
| 48 | if unsafe { ctx == 0 } || !ctx.supports_window_title { |
| 49 | return |
| 50 | } |
| 51 | // restore the previously saved terminal title |
| 52 | print('\x1b[23;0t') |
| 53 | flush_stdout() |
| 54 | } |
| 55 | |
| 56 | // run sets up and starts the terminal. |
| 57 | pub fn (mut ctx Context) run() ! { |
| 58 | if ctx.cfg.use_x11 { |
| 59 | ctx.fail('error: x11 backend not implemented yet') |
| 60 | exit(1) |
| 61 | } else { |
| 62 | ctx.termios_setup() or { panic(err) } |
| 63 | ctx.termios_loop() |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | // shifts the array left, to remove any data that was just read, and updates its len |
| 68 | // TODO: remove |
| 69 | @[inline] |
| 70 | fn (mut ctx Context) shift(len int) { |
| 71 | unsafe { |
| 72 | C.memmove(ctx.read_buf.data, &u8(ctx.read_buf.data) + len, ctx.read_buf.cap - len) |
| 73 | ctx.resize_arr(ctx.read_buf.len - len) |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | // TODO: don't actually do this, lmao |
| 78 | @[inline] |
| 79 | fn (mut ctx Context) resize_arr(size int) { |
| 80 | mut l := unsafe { &ctx.read_buf.len } |
| 81 | unsafe { |
| 82 | *l = size |
| 83 | _ = l |
| 84 | } |
| 85 | } |
| 86 | |