~sircmpwn/hare-vt

e5772d1ceff49d3420be04c90a6d10bc9dff802a — Drew DeVault 1 year, 1 month ago 90b202c
vt: implement cursor enable/disable and alt display
3 files changed, 74 insertions(+), 1 deletions(-)

M example.ha
M vt/driver.ha
M vt/xterm.ha
M example.ha => example.ha +2 -1
@@ 25,7 25,8 @@ export fn main() void = {
fn run() (void | vt::error) = {
	const term = vt::open();
	defer vt::close(term);
	vt::clear(term)?;
	vt::enablealt(term)?;
	vt::disablecur(term)?;

	const p1 = vt::newpen(void, color::RED, style::ULINE);
	const p2 = vt::newpen(color::YELLOW, color::RED);

M vt/driver.ha => vt/driver.ha +31 -0
@@ 15,6 15,15 @@ export type driver = struct {
	// Clears the screen and moves the cursor to the top-left corner.
	clear: *fn(term: *term) (void | error),

	// Enable or disable the alternate screen buffer, if supported.
	chalt: *fn(term: *term, alt: bool) (void | error),

	// Enable or disable the cursor display.
	chcur: *fn(term: *term, enable: bool) (void | error),

	// Move the cursor to the desired row and column, 1-indexed.
	movecur: *fn(term: *term, row: uint, col: uint) (void | error),

	// Releases state associated with the driver and cleans up the terminal.
	destroy: *fn(term: *term) void,
};


@@ 50,3 59,25 @@ export fn openfile(file: io::file) *term = {
export fn close(term: *term) void = {
	term.driver.destroy(term);
};

// Enables the alternate screen buffer. It will be automatically disabled again
// when destroying the terminal.
export fn enablealt(term: *term) (void | error) = {
	return term.driver.chalt(term, true);
};

// Disables the alternate screen buffer.
export fn disablealt(term: *term) (void | error) = {
	return term.driver.chalt(term, false);
};

// Enables the cursor display.
export fn enablecur(term: *term) (void | error) = {
	return term.driver.chcur(term, true);
};

// Disables the cursor display. It will be automatically enabled again when
// destroying the terminal.
export fn disablecur(term: *term) (void | error) = {
	return term.driver.chcur(term, false);
};

M vt/xterm.ha => vt/xterm.ha +41 -0
@@ 10,11 10,17 @@ type more = void;

def ESC: rune = '\x1b';

type xterm_state = enum uint {
	ALT = 1 << 0,
	CUR_DISABLE = 1 << 1,
};

type xterm = struct {
	term,
	in: io::file,
	out: io::file,
	termios: tty::termios,
	state: xterm_state,
	pen: pen,
	buf: [os::BUFSIZ]u8,
	end: size,


@@ 26,6 32,9 @@ const xterm_driver = driver {
	getpen = &xterm_getpen,
	pollev = &xterm_pollev,
	clear = &xterm_clear,
	chalt = &xterm_chalt,
	chcur = &xterm_chcur,
	movecur = &xterm_movecur,
	destroy = &xterm_destroy,
};



@@ 55,6 64,12 @@ fn xterm_init(in: io::file, out: io::file) *term = {

fn xterm_destroy(term: *term) void = {
	let term = term: *xterm;
	if (term.state & xterm_state::ALT != 0) {
		xterm_chalt(term, false)!;
	};
	if (term.state & xterm_state::CUR_DISABLE != 0) {
		xterm_chcur(term, true)!;
	};
	tty::termios_restore(&term.termios);
	free(term);
};


@@ 443,3 458,29 @@ fn xterm_clear(term: *term) (void | error) = {
	const term = term: *xterm;
	fmt::fprint(term.out, "\x1b[2J\x1b[1;1H")?;
};

fn xterm_chalt(term: *term, alt: bool) (void | error) = {
	let term = term: *xterm;
	if (alt) {
		term.state |= xterm_state::ALT;
		fmt::fprint(term.out, "\x1b[?1049h")?;
	} else {
		term.state &= ~xterm_state::ALT;
		fmt::fprint(term.out, "\x1b[?1049l")?;
	};
};

fn xterm_chcur(term: *term, enable: bool) (void | error) = {
	let term = term: *xterm;
	if (enable) {
		term.state &= ~xterm_state::CUR_DISABLE;
		fmt::fprint(term.out, "\x1b[?25h")?;
	} else {
		term.state |= xterm_state::CUR_DISABLE;
		fmt::fprint(term.out, "\x1b[?25l")?;
	};
};

fn xterm_movecur(term: *term, row: uint, col: uint) (void | error) = {
	abort(); // TODO
};