diff --git a/vlib/os/os.c.v b/vlib/os/os.c.v index 8dccd86a17e607..12369d07eec5a4 100644 --- a/vlib/os/os.c.v +++ b/vlib/os/os.c.v @@ -1008,15 +1008,3 @@ pub fn glob(patterns ...string) ?[]string { matches.sort() return matches } - -pub fn last_error() IError { - $if windows { - code := int(C.GetLastError()) - msg := get_error_msg(code) - return error_with_code(msg, code) - } $else { - code := C.errno - msg := posix_get_error_msg(code) - return error_with_code(msg, code) - } -} diff --git a/vlib/readline/readline.v b/vlib/readline/readline.v index ae41ddcf0a26d4..4f0ebf7c403e58 100644 --- a/vlib/readline/readline.v +++ b/vlib/readline/readline.v @@ -7,6 +7,18 @@ // module readline +// Termios stores the terminal options on Linux. +struct C.termios {} + +struct Termios { +mut: + c_iflag int + c_oflag int + c_cflag int + c_lflag int + c_cc [12]int // NCCS == 12. Can't use the defined value here +} + // Winsize stores the screen information on Linux. struct Winsize { ws_row u16 diff --git a/vlib/readline/readline_default.c.v b/vlib/readline/readline_default.c.v index 4d2107c8d5ba61..fcbbbb6eab6263 100644 --- a/vlib/readline/readline_default.c.v +++ b/vlib/readline/readline_default.c.v @@ -10,9 +10,7 @@ module readline import os -struct Termios { -} - +#include // Only use standard os.get_line // Need implementation for readline capabilities // diff --git a/vlib/readline/readline_linux.c.v b/vlib/readline/readline_linux.c.v index 01e947befae7df..eb0fda9f900bf4 100644 --- a/vlib/readline/readline_linux.c.v +++ b/vlib/readline/readline_linux.c.v @@ -13,32 +13,9 @@ import os #include #include -const cclen = 10 - -// Termios stores the terminal options on Linux. -struct C.termios { -mut: - c_iflag int - c_oflag int - c_cflag int - c_lflag int - c_line byte - c_cc [cclen]int -} - -struct Termios { -mut: - c_iflag u32 - c_oflag u32 - c_cflag u32 - c_lflag u32 - c_line byte - c_cc [cclen]int -} - fn C.tcgetattr(fd int, termios_p &C.termios) int -fn C.tcsetattr(fd int, optional_actions int, const_termios_p &C.termios) int +fn C.tcsetattr(fd int, optional_actions int, termios_p &C.termios) int fn C.raise(sig int) @@ -70,22 +47,18 @@ enum Action { // Please note that `enable_raw_mode` catches the `SIGUSER` (CTRL + C) signal. // For a method that does please see `enable_raw_mode_nosig`. pub fn (mut r Readline) enable_raw_mode() { - if unsafe { C.tcgetattr(0, &C.termios(&r.orig_termios)) } != 0 { + if C.tcgetattr(0, unsafe { &C.termios(&r.orig_termios) }) == -1 { r.is_tty = false r.is_raw = false return } - mut raw := C.termios{} - unsafe { vmemcpy(&raw, &r.orig_termios, int(sizeof(raw))) } - // println('> r.orig_termios: $r.orig_termios') - // println('> raw: $raw') + mut raw := r.orig_termios raw.c_iflag &= ~(C.BRKINT | C.ICRNL | C.INPCK | C.ISTRIP | C.IXON) raw.c_cflag |= C.CS8 raw.c_lflag &= ~(C.ECHO | C.ICANON | C.IEXTEN | C.ISIG) - raw.c_cc[C.VMIN] = byte(1) - raw.c_cc[C.VTIME] = byte(0) - unsafe { C.tcsetattr(0, C.TCSADRAIN, &raw) } - // println('> after raw: $raw') + raw.c_cc[C.VMIN] = 1 + raw.c_cc[C.VTIME] = 0 + C.tcsetattr(0, C.TCSADRAIN, unsafe { &C.termios(&raw) }) r.is_raw = true r.is_tty = true } @@ -95,19 +68,18 @@ pub fn (mut r Readline) enable_raw_mode() { // Please note that `enable_raw_mode_nosig` does not catch the `SIGUSER` (CTRL + C) signal // as opposed to `enable_raw_mode`. pub fn (mut r Readline) enable_raw_mode_nosig() { - if unsafe { C.tcgetattr(0, &C.termios(&r.orig_termios)) } != 0 { + if C.tcgetattr(0, unsafe { &C.termios(&r.orig_termios) }) == -1 { r.is_tty = false r.is_raw = false return } - mut raw := C.termios{} - unsafe { vmemcpy(&raw, &r.orig_termios, int(sizeof(raw))) } + mut raw := r.orig_termios raw.c_iflag &= ~(C.BRKINT | C.ICRNL | C.INPCK | C.ISTRIP | C.IXON) raw.c_cflag |= C.CS8 raw.c_lflag &= ~(C.ECHO | C.ICANON | C.IEXTEN) - raw.c_cc[C.VMIN] = byte(1) - raw.c_cc[C.VTIME] = byte(0) - unsafe { C.tcsetattr(0, C.TCSADRAIN, &raw) } + raw.c_cc[C.VMIN] = 1 + raw.c_cc[C.VTIME] = 0 + C.tcsetattr(0, C.TCSADRAIN, unsafe { &C.termios(&raw) }) r.is_raw = true r.is_tty = true } @@ -116,7 +88,7 @@ pub fn (mut r Readline) enable_raw_mode_nosig() { // For a description of raw mode please see the `enable_raw_mode` method. pub fn (mut r Readline) disable_raw_mode() { if r.is_raw { - unsafe { C.tcsetattr(0, C.TCSADRAIN, &C.termios(&r.orig_termios)) } + C.tcsetattr(0, C.TCSADRAIN, unsafe { &C.termios(&r.orig_termios) }) r.is_raw = false } } @@ -150,7 +122,7 @@ pub fn (mut r Readline) read_line_utf8(prompt string) ?[]rune { } print(r.prompt) for { - unsafe { C.fflush(C.stdout) } + C.fflush(C.stdout) c := r.read_char() a := r.analyse(c) if r.execute(a, c) { @@ -339,7 +311,7 @@ fn (mut r Readline) execute(a Action, c int) bool { // get_screen_columns returns the number of columns (`width`) in the terminal. fn get_screen_columns() int { ws := Winsize{} - cols := if unsafe { C.ioctl(1, C.TIOCGWINSZ, &ws) } == -1 { 80 } else { int(ws.ws_col) } + cols := if C.ioctl(1, C.TIOCGWINSZ, &ws) == -1 { 80 } else { int(ws.ws_col) } return cols } @@ -570,12 +542,10 @@ fn (mut r Readline) suspend() { r.disable_raw_mode() if !is_standalone { // We have to SIGSTOP the parent v process - unsafe { - ppid := C.getppid() - C.kill(ppid, C.SIGSTOP) - } + ppid := C.getppid() + C.kill(ppid, C.SIGSTOP) } - unsafe { C.raise(C.SIGSTOP) } + C.raise(C.SIGSTOP) r.enable_raw_mode() r.refresh_line() if r.is_tty { diff --git a/vlib/readline/readline_test.v b/vlib/readline/readline_test.v index a3613e85af656c..ab5154f38df216 100644 --- a/vlib/readline/readline_test.v +++ b/vlib/readline/readline_test.v @@ -5,7 +5,7 @@ fn no_lines(s string) string { } fn test_struct_readline() { - // mut rl := readline.Readline{} + // mut rl := Readline{} // eprintln('rl: $rl') // line := rl.read_line('Please, enter your name: ') or { panic(err) } // eprintln('line: $line') diff --git a/vlib/readline/readline_windows.c.v b/vlib/readline/readline_windows.c.v index bcd28f3fc9e952..887efdb912655a 100644 --- a/vlib/readline/readline_windows.c.v +++ b/vlib/readline/readline_windows.c.v @@ -10,10 +10,6 @@ module readline import os -// needed for parity with readline_default.c.v -struct Termios { -} - // Only use standard os.get_line // Need implementation for readline capabilities // diff --git a/vlib/term/declarations_default.c.v b/vlib/term/declarations_default.c.v deleted file mode 100644 index ab55adf25f0b1e..00000000000000 --- a/vlib/term/declarations_default.c.v +++ /dev/null @@ -1,10 +0,0 @@ -module term - -pub struct C.termios { -mut: - c_iflag int - c_oflag int - c_cflag int - c_lflag int - c_cc [10]int -} diff --git a/vlib/term/declarations_linux.c.v b/vlib/term/declarations_linux.c.v deleted file mode 100644 index 20464d40f91a67..00000000000000 --- a/vlib/term/declarations_linux.c.v +++ /dev/null @@ -1,11 +0,0 @@ -module term - -pub struct C.termios { -mut: - c_iflag int - c_oflag int - c_cflag int - c_lflag int - c_line byte - c_cc [10]int -} diff --git a/vlib/term/term_nix.c.v b/vlib/term/term_nix.c.v index c0c37c8b5a0766..45a0a9b8415aa9 100644 --- a/vlib/term/term_nix.c.v +++ b/vlib/term/term_nix.c.v @@ -13,10 +13,6 @@ pub: ws_ypixel u16 } -fn C.tcgetattr(fd int, ptr &C.termios) int - -fn C.tcsetattr(fd int, action int, const_ptr &C.termios) - fn C.ioctl(fd int, request u64, arg voidptr) int // get_terminal_size returns a number of colums and rows of terminal window. @@ -25,58 +21,70 @@ pub fn get_terminal_size() (int, int) { return default_columns_size, default_rows_size } w := C.winsize{} - unsafe { C.ioctl(1, u64(C.TIOCGWINSZ), &w) } + C.ioctl(1, u64(C.TIOCGWINSZ), &w) return int(w.ws_col), int(w.ws_row) } // get_cursor_position returns a Coord containing the current cursor position -pub fn get_cursor_position() ?Coord { +pub fn get_cursor_position() Coord { if os.is_atty(1) <= 0 || os.getenv('TERM') == 'dumb' { - return Coord{0, 0} - } - - old_state := C.termios{} - if unsafe { C.tcgetattr(0, &old_state) } != 0 { - return os.last_error() - } - defer { - // restore the old terminal state: - unsafe { C.tcsetattr(0, C.TCSANOW, &old_state) } + return Coord{ + x: 0 + y: 0 + } } - - mut state := C.termios{} - if unsafe { C.tcgetattr(0, &state) } != 0 { - return os.last_error() + // TODO: use termios.h, C.tcgetattr & C.tcsetattr directly, + // instead of using `stty` + mut oldsettings := os.execute('stty -g') + if oldsettings.exit_code < 0 { + oldsettings = os.Result{} } - state.c_lflag &= int(~(u32(C.ICANON) | u32(C.ECHO))) - unsafe { C.tcsetattr(0, C.TCSANOW, &state) } - - print('\e[6n') - + os.system('stty -echo -icanon time 0') + print('\033[6n') + mut ch := int(0) + mut i := 0 + // ESC [ YYY `;` XXX `R` + mut reading_x := false + mut reading_y := false mut x := 0 mut y := 0 - mut stage := byte(0) - - // ESC [ YYY `;` XXX `R` - for { - w := unsafe { C.getchar() } - if w < 0 { - return error_with_code('Failed to read from stdin', 888) - } else if w == `[` || w == `;` { - stage++ - } else if `0` <= w && w <= `9` { - match stage { - // converting string values to int: - 1 { y = y * 10 + int(w - `0`) } - 2 { x = x * 10 + int(w - `0`) } - else {} - } - } else if w == `R` { + ch = C.getchar() + b := byte(ch) + i++ + if i >= 15 { + panic('C.getchar() called too many times') + } + // state management: + if b == `R` { break } + if b == `[` { + reading_y = true + reading_x = false + continue + } + if b == `;` { + reading_y = false + reading_x = true + continue + } + // converting string vals to ints: + if reading_x { + x *= 10 + x += (b - byte(`0`)) + } + if reading_y { + y *= 10 + y += (b - byte(`0`)) + } + } + // restore the old terminal settings: + os.system('stty $oldsettings.output') + return Coord{ + x: x + y: y } - return Coord{x, y} } // set_terminal_title change the terminal title diff --git a/vlib/term/term_test.v b/vlib/term/term_test.v index 114b302cf7b005..00f929340218a5 100644 --- a/vlib/term/term_test.v +++ b/vlib/term/term_test.v @@ -57,9 +57,9 @@ fn test_header() { assert term_width == term.header('1234', '_-/\\/\\').len } -fn test_get_cursor_position() ? { - original_position := term.get_cursor_position() ? - cursor_position_1 := term.get_cursor_position() ? +fn test_get_cursor_position() { + original_position := term.get_cursor_position() + cursor_position_1 := term.get_cursor_position() assert original_position.x == cursor_position_1.x assert original_position.y == cursor_position_1.y // @@ -67,13 +67,13 @@ fn test_get_cursor_position() ? { x: 10 y: 11 ) - cursor_position_2 := term.get_cursor_position() ? + cursor_position_2 := term.get_cursor_position() // term.set_cursor_position( x: 5 y: 6 ) - cursor_position_3 := term.get_cursor_position() ? + cursor_position_3 := term.get_cursor_position() // term.set_cursor_position(original_position) eprintln('original_position: $original_position') diff --git a/vlib/term/term_windows.c.v b/vlib/term/term_windows.c.v index db55b62f086bf8..1d2f0329fb3960 100644 --- a/vlib/term/term_windows.c.v +++ b/vlib/term/term_windows.c.v @@ -69,15 +69,13 @@ pub fn get_terminal_size() (int, int) { } // get_cursor_position returns a Coord containing the current cursor position -pub fn get_cursor_position() ?Coord { +pub fn get_cursor_position() Coord { mut res := Coord{} if os.is_atty(1) > 0 && os.getenv('TERM') != 'dumb' { info := C.CONSOLE_SCREEN_BUFFER_INFO{} if C.GetConsoleScreenBufferInfo(C.GetStdHandle(C.STD_OUTPUT_HANDLE), &info) { res.x = info.dwCursorPosition.X res.y = info.dwCursorPosition.Y - } else { - return os.last_error() } } return res diff --git a/vlib/term/ui/color.v b/vlib/term/ui/color.v index 0e31e77cfea1b3..3e0a0bbf11b763 100644 --- a/vlib/term/ui/color.v +++ b/vlib/term/ui/color.v @@ -4,9 +4,10 @@ module ui -const value_range = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]! - -pub const color_table = init_color_table() +const ( + value_range = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]! + color_table = init_color_table() +) [direct_array_access] fn init_color_table() []int { diff --git a/vlib/term/ui/declarations_default.c.v b/vlib/term/ui/declarations_default.c.v deleted file mode 100644 index 27c1053c1169eb..00000000000000 --- a/vlib/term/ui/declarations_default.c.v +++ /dev/null @@ -1,10 +0,0 @@ -module ui - -struct C.termios { -mut: - c_iflag int - c_oflag int - c_cflag int - c_lflag int - c_cc [10]int -} diff --git a/vlib/term/ui/declarations_linux.c.v b/vlib/term/ui/declarations_linux.c.v deleted file mode 100644 index 43ec7aa409c76e..00000000000000 --- a/vlib/term/ui/declarations_linux.c.v +++ /dev/null @@ -1,11 +0,0 @@ -module ui - -struct C.termios { -mut: - c_iflag int - c_oflag int - c_cflag int - c_lflag int - c_line byte - c_cc [10]int -} diff --git a/vlib/term/ui/input_nix.c.v b/vlib/term/ui/input_nix.c.v index d11f3b4bd890c5..e806fb8c1a0f68 100644 --- a/vlib/term/ui/input_nix.c.v +++ b/vlib/term/ui/input_nix.c.v @@ -8,7 +8,9 @@ mut: read_buf []byte } -const ctx_ptr = &Context(0) +const ( + ctx_ptr = &Context(0) +) pub fn init(cfg Config) &Context { mut ctx := &Context{ diff --git a/vlib/term/ui/input_windows.c.v b/vlib/term/ui/input_windows.c.v index 6f08f2a934b289..bd9782d150409f 100644 --- a/vlib/term/ui/input_windows.c.v +++ b/vlib/term/ui/input_windows.c.v @@ -6,11 +6,11 @@ module ui import os import time -const buf_size = 64 - -const ctx_ptr = &Context(0) - -const stdin_at_startup = u32(0) +const ( + buf_size = 64 + ctx_ptr = &Context(0) + stdin_at_startup = u32(0) +) struct ExtraContext { mut: diff --git a/vlib/term/ui/termios_nix.c.v b/vlib/term/ui/termios_nix.c.v index 9bbaed3308c4a3..fb5ff76b25f740 100644 --- a/vlib/term/ui/termios_nix.c.v +++ b/vlib/term/ui/termios_nix.c.v @@ -10,18 +10,27 @@ import time #include #include -struct C.winsize { - ws_row u16 - ws_col u16 -} - fn C.tcgetattr(fd int, termios_p &C.termios) int -fn C.tcsetattr(fd int, optional_actions int, const_termios_p &C.termios) int +fn C.tcsetattr(fd int, optional_actions int, termios_p &C.termios) int fn C.ioctl(fd int, request u64, arg voidptr) int -const termios_at_startup = get_termios() +struct C.termios { +mut: + c_iflag u32 + c_lflag u32 + c_cc [32]byte +} + +struct C.winsize { + ws_row u16 + ws_col u16 +} + +const ( + termios_at_startup = get_termios() +) [inline] fn get_termios() C.termios { @@ -65,11 +74,11 @@ fn (mut ctx Context) termios_setup() ? { if ctx.cfg.capture_events { // Set raw input mode by unsetting ICANON and ECHO, // as well as disable e.g. ctrl+c and ctrl.z - termios.c_iflag &= ~(C.IGNBRK | C.BRKINT | C.PARMRK | C.IXON) - termios.c_lflag &= ~(C.ICANON | C.ISIG | C.ECHO | C.IEXTEN | C.TOSTOP) + termios.c_iflag &= ~u32(C.IGNBRK | C.BRKINT | C.PARMRK | C.IXON) + termios.c_lflag &= ~u32(C.ICANON | C.ISIG | C.ECHO | C.IEXTEN | C.TOSTOP) } else { // Set raw input mode by unsetting ICANON and ECHO - termios.c_lflag &= ~(C.ICANON | C.ECHO) + termios.c_lflag &= ~u32(C.ICANON | C.ECHO) } if ctx.cfg.hide_cursor { diff --git a/vlib/term/ui/ui.v b/vlib/term/ui/ui.v index 78e43eb522d45e..6ba3d7c357bd64 100644 --- a/vlib/term/ui/ui.v +++ b/vlib/term/ui/ui.v @@ -18,9 +18,10 @@ pub fn (c Color) hex() string { // Synchronized Updates spec, designed to avoid tearing during renders // https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec -const bsu = '\x1bP=1s\x1b\\' - -const esu = '\x1bP=2s\x1b\\' +const ( + bsu = '\x1bP=1s\x1b\\' + esu = '\x1bP=2s\x1b\\' +) // write puts the string `s` into the print buffer. [inline] diff --git a/vlib/term/ui/ui_test.v b/vlib/term/ui/ui_test.v deleted file mode 100644 index 5817bf8a657168..00000000000000 --- a/vlib/term/ui/ui_test.v +++ /dev/null @@ -1,8 +0,0 @@ -import term.ui - -// This test just ensures that programs importing term.ui can compile - -fn test_a_simple_term_ui_program_can_be_compiled() { - println(ui.color_table) - assert true -}