From 6de78ecb592f3bfa4ed9f65c114f3f3c097d738f Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Tue, 9 Feb 2021 17:55:31 +0530 Subject: [PATCH] term: implement term.clear() for windows (#8650) --- vlib/term/term.v | 8 ------ vlib/term/term_nix.c.v | 6 ++++ vlib/term/term_windows.c.v | 59 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/vlib/term/term.v b/vlib/term/term.v index a62612f665..37ff94ef3d 100644 --- a/vlib/term/term.v +++ b/vlib/term/term.v @@ -119,11 +119,3 @@ fn supports_escape_sequences(fd int) bool { return is_atty(fd) > 0 } } - -// clear clears current terminal screen. -pub fn clear() { - $if !windows { - print('\x1b[2J') - print('\x1b[H') - } -} diff --git a/vlib/term/term_nix.c.v b/vlib/term/term_nix.c.v index 4cb9bb3ce4..837cdede33 100644 --- a/vlib/term/term_nix.c.v +++ b/vlib/term/term_nix.c.v @@ -93,3 +93,9 @@ pub fn set_terminal_title(title string) bool { print('\033]0;${title}\007') return true } + +// clear clears current terminal screen. +pub fn clear() { + print('\x1b[2J') + print('\x1b[H') +} diff --git a/vlib/term/term_windows.c.v b/vlib/term/term_windows.c.v index f3fc965216..bd579f72d0 100644 --- a/vlib/term/term_windows.c.v +++ b/vlib/term/term_windows.c.v @@ -4,12 +4,14 @@ import os [typedef] struct C.COORD { +mut: X i16 Y i16 } [typedef] struct C.SMALL_RECT { +mut: Left u16 Top u16 Right u16 @@ -20,6 +22,7 @@ struct C.SMALL_RECT { // https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-info-str [typedef] struct C.CONSOLE_SCREEN_BUFFER_INFO { +mut: dwSize C.COORD dwCursorPosition C.COORD wAttributes u16 @@ -27,12 +30,31 @@ struct C.CONSOLE_SCREEN_BUFFER_INFO { dwMaximumWindowSize C.COORD } +union C.uChar { +mut: + UnicodeChar rune + AsciiChar byte +} + +[typedef] +struct C.CHAR_INFO { +mut: + Char C.uChar + Attributes u16 +} + // ref - https://docs.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo fn C.GetConsoleScreenBufferInfo(handle os.HANDLE, info &C.CONSOLE_SCREEN_BUFFER_INFO) bool // ref - https://docs.microsoft.com/en-us/windows/console/setconsoletitle fn C.SetConsoleTitle(title &u16) bool +// ref - https://docs.microsoft.com/en-us/windows/console/setconsolecursorposition +fn C.SetConsoleCursorPosition(handle os.HANDLE, coord C.COORD) bool + +// ref - https://docs.microsoft.com/en-us/windows/console/scrollconsolescreenbuffer +fn C.ScrollConsoleScreenBuffer(output os.HANDLE, scroll_rect &C.SMALL_RECT, clip_rect &C.SMALL_RECT, des C.COORD, fill C.CHAR_INFO) bool + // get_terminal_size returns a number of colums and rows of terminal window. pub fn get_terminal_size() (int, int) { if is_atty(1) > 0 && os.getenv('TERM') != 'dumb' { @@ -64,3 +86,40 @@ pub fn set_terminal_title(title string) bool { title_change := C.SetConsoleTitle(title.to_wide()) return title_change } + +// clear clears current terminal screen. +// Implementation taken from https://docs.microsoft.com/en-us/windows/console/clearing-the-screen#example-2. +pub fn clear() { + hconsole := C.GetStdHandle(C.STD_OUTPUT_HANDLE) + mut csbi := C.CONSOLE_SCREEN_BUFFER_INFO{} + mut scrollrect := C.SMALL_RECT{} + mut scrolltarget := C.COORD{} + mut fill := C.CHAR_INFO{} + + // Get the number of character cells in the current buffer. + if !C.GetConsoleScreenBufferInfo(hconsole, &csbi) { + return + } + // Scroll the rectangle of the entire buffer. + scrollrect.Left = 0 + scrollrect.Top = 0 + scrollrect.Right = u16(csbi.dwSize.X) + scrollrect.Bottom = u16(csbi.dwSize.Y) + + // Scroll it upwards off the top of the buffer with a magnitude of the entire height. + scrolltarget.X = 0 + scrolltarget.Y = (0 - csbi.dwSize.Y) + + // Fill with empty spaces with the buffer's default text attribute. + fill.Char.UnicodeChar = rune(` `) + fill.Attributes = csbi.wAttributes + + // Do the scroll + C.ScrollConsoleScreenBuffer(hconsole, &scrollrect, C.NULL, scrolltarget, &fill) + + // Move the cursor to the top left corner too. + csbi.dwCursorPosition.X = 0 + csbi.dwCursorPosition.Y = 0 + + C.SetConsoleCursorPosition(hconsole, csbi.dwCursorPosition) +}