diff options
author | Charles Blake <cb@cblake.net> | 2016-09-01 07:34:42 -0400 |
---|---|---|
committer | Charles Blake <cb@cblake.net> | 2016-09-01 07:34:42 -0400 |
commit | 19f83ccd0bf03dea93698a5611c881f57499ca12 (patch) | |
tree | ce07b15040f963135cc2fcc39dcd4f6cd16f8cc9 /lib | |
parent | 0cb90f3eaf482415662091a62b06aceb53d4b1f5 (diff) | |
download | Nim-19f83ccd0bf03dea93698a5611c881f57499ca12.tar.gz |
Add terminal.terminalWidth and supporting types/calls.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/posix/termios.nim | 10 | ||||
-rw-r--r-- | lib/pure/terminal.nim | 45 |
2 files changed, 54 insertions, 1 deletions
diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index c3934c6a9..88c3edf01 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: "<termios.h>".} + +# Window size ioctl. Should work on on any Unix that xterm has been ported to. +var TIOCGWINSZ*{.importc, header: "<sys/ioctl.h>".}: culong + +type ioctl_winsize* {.importc: "struct winsize", header: "<termios.h>", + 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: "<stdio.h>", varargs.} diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 1f34ec07e..329c50f3e 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: "<stdio.h>".}: 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. |