From 19f83ccd0bf03dea93698a5611c881f57499ca12 Mon Sep 17 00:00:00 2001 From: Charles Blake Date: Thu, 1 Sep 2016 07:34:42 -0400 Subject: [PATCH 1/7] Add terminal.terminalWidth and supporting types/calls. --- lib/posix/termios.nim | 10 ++++++++++ lib/pure/terminal.nim | 45 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index c3934c6a95..88c3edf01d 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -259,3 +259,13 @@ proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow", # Get process group ID for session leader for controlling terminal FD. proc tcGetSid*(fd: cint): Pid {.importc: "tcgetsid", header: "".} + +# Window size ioctl. Should work on on any Unix that xterm has been ported to. +var TIOCGWINSZ*{.importc, header: "".}: culong + +type ioctl_winsize* {.importc: "struct winsize", header: "", + final, pure.} = object + ws_row*, ws_col*, ws_xpixel*, ws_ypixel*: cushort + +proc ioctl*(fd: cint, request: culong, reply: ptr ioctl_winsize): int {. + importc: "ioctl", header: "", varargs.} diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 1f34ec07e4..329c50f3ee 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -60,6 +60,22 @@ when defined(windows): lpConsoleScreenBufferInfo: ptr CONSOLE_SCREEN_BUFFER_INFO): WINBOOL{.stdcall, dynlib: "kernel32", importc: "GetConsoleScreenBufferInfo".} + proc terminalWidth*(h: Handle): int = + var csbi: CONSOLE_SCREEN_BUFFER_INFO + if getConsoleScreenBufferInfo(h, addr csbi) != 0: + return int(csbi.srWindow.Right - csbi.srWindow.Left + 1) + return 0 + + proc terminalWidth*(): int = + var w: int = 0 + w = terminalWidth(getStdHandle(STD_INPUT_HANDLE)) + if w > 0: return w + w = terminalWidth(getStdHandle(STD_OUTPUT_HANDLE)) + if w > 0: return w + w = terminalWidth(getStdHandle(STD_ERROR_HANDLE)) + if w > 0: return w + return 80 + proc setConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "SetConsoleCursorPosition".} @@ -123,7 +139,7 @@ when defined(windows): if f == stderr: hStderr else: hStdout else: - import termios + import termios, posix, os, parseutils proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) = var mode: Termios @@ -137,6 +153,33 @@ else: mode.c_cc[VTIME] = 0.cuchar discard fd.tcsetattr(time, addr mode) + proc terminalWidthIoctl*(fds: openArray[int]): int = + ## Returns terminal width from first fd that supports the ioctl. + + var win: ioctl_winsize + for fd in fds: + if ioctl(cint(fd), TIOCGWINSZ, addr win) != -1: + return int(win.ws_col) + return 0 + + proc terminalWidth*(): int = + ## Returns **some** reasonable terminal width from either standard file + ## descriptors, controlling terminal, environment variables or tradition. + + var L_ctermid{.importc, header: "".}: cint + var w = terminalWidthIoctl([0, 1, 2]) #Try standard file descriptors + if w > 0: return w + var cterm = newString(L_ctermid) #Try controlling tty + var fd = open(ctermid(cstring(cterm)), O_RDONLY) + if fd != -1: + w = terminalWidthIoctl([ int(fd) ]) + discard close(fd) + if w > 0: return w + var s = getEnv("COLUMNS") #Try standard env var + if len(s) > 0 and parseInt(s, w) > 0 and w > 0: + return w + return 80 #Finally default to venerable value + proc setCursorPos*(f: File, x, y: int) = ## Sets the terminal's cursor to the (x,y) position. ## (0,0) is the upper left of the screen. From 7b73a94afc3ff604fab6daab58d2b3eabddf70ca Mon Sep 17 00:00:00 2001 From: Charles Blake Date: Thu, 1 Sep 2016 07:54:17 -0400 Subject: [PATCH 2/7] Oops - L_ctermid must be a global var to compile. --- lib/pure/terminal.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 329c50f3ee..90be431301 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -162,11 +162,11 @@ else: return int(win.ws_col) return 0 + var L_ctermid{.importc, header: "".}: cint proc terminalWidth*(): int = - ## Returns **some** reasonable terminal width from either standard file + ## Returns some reasonable terminal width from either standard file ## descriptors, controlling terminal, environment variables or tradition. - var L_ctermid{.importc, header: "".}: cint var w = terminalWidthIoctl([0, 1, 2]) #Try standard file descriptors if w > 0: return w var cterm = newString(L_ctermid) #Try controlling tty From 5db1de87b1e6c1163ebca91852bd55e93f0f09ed Mon Sep 17 00:00:00 2001 From: Charles Blake Date: Thu, 1 Sep 2016 08:16:28 -0400 Subject: [PATCH 3/7] Convert TaintedString to string. --- lib/pure/terminal.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 90be431301..63419114a4 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -176,7 +176,7 @@ else: discard close(fd) if w > 0: return w var s = getEnv("COLUMNS") #Try standard env var - if len(s) > 0 and parseInt(s, w) > 0 and w > 0: + if len(s) > 0 and parseInt(string(s), w) > 0 and w > 0: return w return 80 #Finally default to venerable value From 8df2078f08ad0abf3f50632ae783a997eb64b3be Mon Sep 17 00:00:00 2001 From: Charles Blake Date: Thu, 1 Sep 2016 08:33:39 -0400 Subject: [PATCH 4/7] Change type name to be more NEP-1-ish as per Araq request. --- lib/posix/termios.nim | 4 ++-- lib/pure/terminal.nim | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index 88c3edf01d..f8de740d76 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -263,9 +263,9 @@ proc tcGetSid*(fd: cint): Pid {.importc: "tcgetsid", header: "".} # Window size ioctl. Should work on on any Unix that xterm has been ported to. var TIOCGWINSZ*{.importc, header: "".}: culong -type ioctl_winsize* {.importc: "struct winsize", header: "", +type IOctl_WinSize* {.importc: "struct winsize", header: "", final, pure.} = object ws_row*, ws_col*, ws_xpixel*, ws_ypixel*: cushort -proc ioctl*(fd: cint, request: culong, reply: ptr ioctl_winsize): int {. +proc ioctl*(fd: cint, request: culong, reply: ptr IOctl_WinSize): int {. importc: "ioctl", header: "", varargs.} diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 63419114a4..4fdb04e4fd 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -156,7 +156,7 @@ else: proc terminalWidthIoctl*(fds: openArray[int]): int = ## Returns terminal width from first fd that supports the ioctl. - var win: ioctl_winsize + var win: IOctl_WinSize for fd in fds: if ioctl(cint(fd), TIOCGWINSZ, addr win) != -1: return int(win.ws_col) From d65589fe27c68e7e928c027898acd01cbed58d89 Mon Sep 17 00:00:00 2001 From: Charles Blake Date: Thu, 1 Sep 2016 08:49:07 -0400 Subject: [PATCH 5/7] Make Windows part match Unix part more closely per Araq request. --- lib/pure/terminal.nim | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 4fdb04e4fd..15c7f73235 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -60,19 +60,18 @@ when defined(windows): lpConsoleScreenBufferInfo: ptr CONSOLE_SCREEN_BUFFER_INFO): WINBOOL{.stdcall, dynlib: "kernel32", importc: "GetConsoleScreenBufferInfo".} - proc terminalWidth*(h: Handle): int = + proc terminalWidthIoctl*(handles: openArray[Handle]): int = var csbi: CONSOLE_SCREEN_BUFFER_INFO - if getConsoleScreenBufferInfo(h, addr csbi) != 0: - return int(csbi.srWindow.Right - csbi.srWindow.Left + 1) + for h in handles: + if getConsoleScreenBufferInfo(h, addr csbi) != 0: + return int(csbi.srWindow.Right - csbi.srWindow.Left + 1) return 0 proc terminalWidth*(): int = var w: int = 0 - w = terminalWidth(getStdHandle(STD_INPUT_HANDLE)) - if w > 0: return w - w = terminalWidth(getStdHandle(STD_OUTPUT_HANDLE)) - if w > 0: return w - w = terminalWidth(getStdHandle(STD_ERROR_HANDLE)) + w = terminalWidth([ getStdHandle(STD_INPUT_HANDLE), + getStdHandle(STD_OUTPUT_HANDLE), + getStdHandle(STD_ERROR_HANDLE) ] ) if w > 0: return w return 80 From 7b39545eb3cdb2ab21fc7fdff31567a75824cb43 Mon Sep 17 00:00:00 2001 From: Charles Blake Date: Thu, 1 Sep 2016 14:08:40 -0400 Subject: [PATCH 6/7] Evidently Travis build termios.h does not pull in sys/ioctl.h but my initial test system did. --- lib/posix/termios.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index f8de740d76..1fbccba9c8 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -263,7 +263,7 @@ proc tcGetSid*(fd: cint): Pid {.importc: "tcgetsid", header: "".} # Window size ioctl. Should work on on any Unix that xterm has been ported to. var TIOCGWINSZ*{.importc, header: "".}: culong -type IOctl_WinSize* {.importc: "struct winsize", header: "", +type IOctl_WinSize* {.importc: "struct winsize", header: "", final, pure.} = object ws_row*, ws_col*, ws_xpixel*, ws_ypixel*: cushort From e4ddcd836ce723859b71d2d52be85e8eaed7e119 Mon Sep 17 00:00:00 2001 From: Charles Blake Date: Thu, 1 Sep 2016 14:44:33 -0400 Subject: [PATCH 7/7] Use new name for call to low-level terminalWidth. --- lib/pure/terminal.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 15c7f73235..d4734c3e37 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -69,9 +69,9 @@ when defined(windows): proc terminalWidth*(): int = var w: int = 0 - w = terminalWidth([ getStdHandle(STD_INPUT_HANDLE), - getStdHandle(STD_OUTPUT_HANDLE), - getStdHandle(STD_ERROR_HANDLE) ] ) + w = terminalWidthIoctl([ getStdHandle(STD_INPUT_HANDLE), + getStdHandle(STD_OUTPUT_HANDLE), + getStdHandle(STD_ERROR_HANDLE) ] ) if w > 0: return w return 80