1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00
v/vlib/term/ui
Thomas Mangin 580d9cedc7
termios: new termios module (#17792)
* termio: new termio module

move the tcgetattr and tcsetattr functions in a new termio module.
The code needed refactoring as different OS have different fields
size, position and number for the C.termios structure, which
could not be correctly expressed consitently otherwise.

It has the positive side effect to reduce the number of unsafe calls.
New testing code was also added for the readline module as it is
relying of the feature.

* apply 2023 copyright to the new files too
2023-03-30 08:58:52 +03:00
..
1_term_and_ui_compilation_test.v
2_term_and_ui_compilation_test.v
color.v
consoleapi_windows.c.v
input_nix.c.v
input_windows.c.v
input.v
README.md
termios_nix.c.v termios: new termios module (#17792) 2023-03-30 08:58:52 +03:00
ui_test.v
ui.v

term.ui

A V module for designing terminal UI apps

Quickstart

import term.ui as tui

struct App {
mut:
	tui &tui.Context = unsafe { nil }
}

fn event(e &tui.Event, x voidptr) {
	if e.typ == .key_down && e.code == .escape {
		exit(0)
	}
}

fn frame(x voidptr) {
	mut app := &App(x)

	app.tui.clear()
	app.tui.set_bg_color(r: 63, g: 81, b: 181)
	app.tui.draw_rect(20, 6, 41, 10)
	app.tui.draw_text(24, 8, 'Hello from V!')
	app.tui.set_cursor_position(0, 0)

	app.tui.reset()
	app.tui.flush()
}

fn main() {
	mut app := &App{}
	app.tui = tui.init(
		user_data: app
		event_fn: event
		frame_fn: frame
		hide_cursor: true
	)
	app.tui.run()?
}

See the /examples/term.ui/ folder for more usage examples.

Configuration

  • user_data voidptr - a pointer to any user_data, it will be passed as the last argument to each callback. Used for accessing your app context from the different callbacks.
  • init_fn fn(voidptr) - a callback that will be called after initialization and before the first event / frame. Useful for initializing any user data.
  • frame_fn fn(voidptr) - a callback that will be fired on each frame, at a rate of frame_rate frames per second. event_fn fn(&Event, voidptr) - a callback that will be fired for every event received.
  • cleanup_fn fn(voidptr) - a callback that will be fired once, before the application exits.
  • fail_fn fn(string) - a callback that will be fired if a fatal error occurs during app initialization.
  • buffer_size int = 256 - the internal size of the read buffer. Increasing it may help in case you're missing events, but you probably shouldn't lower this value unless you make sure you're still receiving all events. In general, higher frame rates work better with lower buffer sizes, and vice versa.
  • frame_rate int = 30 - the number of times per second that the frame callback will be fired. 30fps is a nice balance between smoothness and performance, but you can increase or lower it as you wish.
  • hide_cursor bool - whether to hide the mouse cursor. Useful if you want to use your own.
  • capture_events bool - sets the terminal into raw mode, which makes it intercept some escape codes such as ctrl + c and ctrl + z. Useful if you want to use those key combinations in your app.
  • window_title string - sets the title of the terminal window. This may be changed later, by calling the set_window_title() method.
  • reset []int = [1, 2, 3, 4, 6, 7, 8, 9, 11, 13, 14, 15, 19] - a list of reset signals, to setup handlers to cleanup the terminal state when they're received. You should not need to change this, unless you know what you're doing.

All of these fields may be omitted, in which case, the default value will be used. In the case of the various callbacks, they will not be fired if a handler has not been specified.

FAQ

Q: My terminal (doesn't receive events / doesn't print anything / prints gibberish characters), what's up with that? A: Please check if your terminal. The module has been tested with xterm-based terminals on Linux (like gnome-terminal and konsole), and Terminal.app and iterm2 on macOS. If your terminal does not work, open an issue with the output of echo $TERM.

Q: There are screen tearing issues when doing large prints A: This is an issue with how terminals render frames, as they may decide to do so in the middle of receiving a frame, and cannot be fully fixed unless your console implements the synchronized updates spec. It can be reduced drastically, though, by using the rendering methods built in to the module, and by only painting frames when your app's content has actually changed.

Q: Why does the module only emit keydown events, and not keyup like sokol/gg? A: It's because of the way terminals emit events. Every key event is received as a keypress, and there isn't a way of telling terminals to send keyboard events differently, nor a reliable way of converting these into keydown / keyup events.