Fossil SCM

fossil-scm / src / terminal.c
Source Blame History 180 lines
3504672… ashepilko 1 /*
3504672… ashepilko 2 ** Copyright (c) 2020 D. Richard Hipp
3504672… ashepilko 3 **
3504672… ashepilko 4 ** This program is free software; you can redistribute it and/or
3504672… ashepilko 5 ** modify it under the terms of the Simplified BSD License (also
3504672… ashepilko 6 ** known as the "2-Clause License" or "FreeBSD License".)
3504672… ashepilko 7
3504672… ashepilko 8 ** This program is distributed in the hope that it will be useful,
3504672… ashepilko 9 ** but without any warranty; without even the implied warranty of
3504672… ashepilko 10 ** merchantability or fitness for a particular purpose.
3504672… ashepilko 11 **
3504672… ashepilko 12 ** Author contact information:
3504672… ashepilko 13 ** [email protected]
3504672… ashepilko 14 ** http://www.hwaci.com/drh/
3504672… ashepilko 15 **
3504672… ashepilko 16 *******************************************************************************
3504672… ashepilko 17 **
3504672… ashepilko 18 ** This file contains code used to query terminal info
3504672… ashepilko 19 */
3504672… ashepilko 20
3504672… ashepilko 21 #include "config.h"
3504672… ashepilko 22 #include "terminal.h"
3504672… ashepilko 23 #include <assert.h>
3504672… ashepilko 24 #ifdef _WIN32
3504672… ashepilko 25 # include <windows.h>
3504672… ashepilko 26 #else
a8780e4… preben 27 #ifdef __EXTENSIONS__
a8780e4… preben 28 #include <termio.h>
a8780e4… preben 29 #endif
3504672… ashepilko 30 #include <sys/ioctl.h>
3504672… ashepilko 31 #include <stdio.h>
3504672… ashepilko 32 #include <unistd.h>
3504672… ashepilko 33 #endif
3504672… ashepilko 34
3504672… ashepilko 35
3504672… ashepilko 36
3504672… ashepilko 37 #if INTERFACE
3504672… ashepilko 38 /*
3504672… ashepilko 39 ** Terminal size defined in terms of columns and lines.
3504672… ashepilko 40 */
3504672… ashepilko 41 struct TerminalSize {
3504672… ashepilko 42 unsigned int nColumns; /* Number of characters on a single line */
3504672… ashepilko 43 unsigned int nLines; /* Number of lines */
3504672… ashepilko 44 };
3504672… ashepilko 45 #endif
3504672… ashepilko 46
3504672… ashepilko 47
3504672… ashepilko 48 /* Get the current terminal size by calling a system service.
3504672… ashepilko 49 **
e2bdc10… danield 50 ** Return 1 on success. This sets the size parameters to the values returned by
3504672… ashepilko 51 ** the system call, when such is supported; set the size to zero otherwise.
3504672… ashepilko 52 ** Return 0 on the system service call failure.
3504672… ashepilko 53 **
3504672… ashepilko 54 ** Under Linux/bash the size info is also available from env $LINES, $COLUMNS.
3504672… ashepilko 55 ** Or it can be queried using tput `echo -e "lines\ncols"|tput -S`.
3504672… ashepilko 56 ** Technically, this info could be cached, but then we'd need to handle
3504672… ashepilko 57 ** SIGWINCH signal to requery the terminal on resize event.
3504672… ashepilko 58 */
b241b9c… drh 59 int terminal_get_size(TerminalSize *t){
3504672… ashepilko 60 memset(t, 0, sizeof(*t));
3504672… ashepilko 61
3504672… ashepilko 62 #if defined(TIOCGSIZE)
3504672… ashepilko 63 {
3504672… ashepilko 64 struct ttysize ts;
3f30abc… drh 65 if( ioctl(STDIN_FILENO, TIOCGSIZE, &ts)>=0
3f30abc… drh 66 || ioctl(STDOUT_FILENO, TIOCGSIZE, &ts)>=0
3f30abc… drh 67 || ioctl(STDERR_FILENO, TIOCGSIZE, &ts)>=0
3f30abc… drh 68 ){
3504672… ashepilko 69 t->nColumns = ts.ts_cols;
3504672… ashepilko 70 t->nLines = ts.ts_lines;
3504672… ashepilko 71 return 1;
3504672… ashepilko 72 }
3504672… ashepilko 73 return 0;
3504672… ashepilko 74 }
3504672… ashepilko 75 #elif defined(TIOCGWINSZ)
3504672… ashepilko 76 {
3504672… ashepilko 77 struct winsize ws;
3f30abc… drh 78 if( ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)>=0
3f30abc… drh 79 || ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)>=0
3f30abc… drh 80 || ioctl(STDERR_FILENO, TIOCGWINSZ, &ws)>=0
3f30abc… drh 81 ){
3504672… ashepilko 82 t->nColumns = ws.ws_col;
3504672… ashepilko 83 t->nLines = ws.ws_row;
3504672… ashepilko 84 return 1;
3504672… ashepilko 85 }
3504672… ashepilko 86 return 0;
3504672… ashepilko 87 }
3504672… ashepilko 88 #elif defined(_WIN32)
3504672… ashepilko 89 {
3504672… ashepilko 90 CONSOLE_SCREEN_BUFFER_INFO csbi;
3f30abc… drh 91 if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)
3f30abc… drh 92 || GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)
3f30abc… drh 93 || GetConsoleScreenBufferInfo(GetStdHandle(STD_INPUT_HANDLE), &csbi)
3f30abc… drh 94 ){
3504672… ashepilko 95 t->nColumns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
3504672… ashepilko 96 t->nLines = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
3504672… ashepilko 97 return 1;
3504672… ashepilko 98 }
3504672… ashepilko 99 return 0;
3504672… ashepilko 100 }
3504672… ashepilko 101 #else
3504672… ashepilko 102 return 1;
3504672… ashepilko 103 #endif
3504672… ashepilko 104 }
3504672… ashepilko 105
3504672… ashepilko 106 /*
3504672… ashepilko 107 ** Return the terminal's current width in columns when available, otherwise
3504672… ashepilko 108 ** return the specified default value.
3504672… ashepilko 109 */
b241b9c… drh 110 unsigned int terminal_get_width(unsigned int nDefault){
b241b9c… drh 111 TerminalSize ts;
3504672… ashepilko 112 if( terminal_get_size(&ts) ){
3504672… ashepilko 113 return ts.nColumns;
3504672… ashepilko 114 }
3504672… ashepilko 115 return nDefault;
3504672… ashepilko 116 }
3504672… ashepilko 117
3504672… ashepilko 118 /*
3504672… ashepilko 119 ** Return the terminal's current height in lines when available, otherwise
3504672… ashepilko 120 ** return the specified default value.
3504672… ashepilko 121 */
b241b9c… drh 122 unsigned int terminal_get_height(unsigned int nDefault){
b241b9c… drh 123 TerminalSize ts;
3504672… ashepilko 124 if( terminal_get_size(&ts) ){
3504672… ashepilko 125 return ts.nLines;
3504672… ashepilko 126 }
3504672… ashepilko 127 return nDefault;
3504672… ashepilko 128 }
b241b9c… drh 129
b241b9c… drh 130 /*
f0d9fe2… drh 131 ** Return true if it is reasonable is emit VT100 escape codes.
f0d9fe2… drh 132 */
f0d9fe2… drh 133 int terminal_is_vt100(void){
f0d9fe2… drh 134 char *zNoColor;
360abc5… florian 135 #ifdef _WIN32
360abc5… florian 136 if( !win32_terminal_is_vt100(1) ) return 0;
360abc5… florian 137 #endif /* _WIN32 */
f0d9fe2… drh 138 if( !fossil_isatty(1) ) return 0;
f0d9fe2… drh 139 zNoColor =fossil_getenv("NO_COLOR");
f0d9fe2… drh 140 if( zNoColor==0 ) return 1;
f0d9fe2… drh 141 if( zNoColor[0]==0 ) return 1;
f0d9fe2… drh 142 if( is_false(zNoColor) ) return 1;
f0d9fe2… drh 143 return 0;
f0d9fe2… drh 144 }
360abc5… florian 145
360abc5… florian 146 #ifdef _WIN32
360abc5… florian 147 /*
360abc5… florian 148 ** Return true if the Windows console supports VT100 escape codes.
360abc5… florian 149 **
360abc5… florian 150 ** Support for VT100 escape codes is enabled by default in Windows Terminal
360abc5… florian 151 ** on Windows 10 and Windows 11, and disabled by default in Legacy Consoles
360abc5… florian 152 ** and on older versions of Windows. Programs can turn on VT100 support for
360abc5… florian 153 ** Legacy Consoles using the ENABLE_VIRTUAL_TERMINAL_PROCESSING flag.
360abc5… florian 154 **
360abc5… florian 155 ** NOTE: If this function needs to be called in more complex scenarios with
360abc5… florian 156 ** reassigned stdout and stderr streams, the following CRT calls are useful
360abc5… florian 157 ** to translate from CRT streams to file descriptors and to Win32 handles:
360abc5… florian 158 **
360abc5… florian 159 ** HANDLE hOutputHandle = (HANDLE)_get_osfhandle(_fileno(<FILE*>));
360abc5… florian 160 */
360abc5… florian 161 #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
360abc5… florian 162 #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
360abc5… florian 163 #endif
360abc5… florian 164 int win32_terminal_is_vt100(int fd){
360abc5… florian 165 HANDLE hConsole = NULL;
360abc5… florian 166 DWORD dwConsoleMode;
360abc5… florian 167 switch( fd ){
360abc5… florian 168 case 1:
360abc5… florian 169 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
360abc5… florian 170 break;
360abc5… florian 171 case 2:
360abc5… florian 172 hConsole = GetStdHandle(STD_ERROR_HANDLE);
360abc5… florian 173 break;
360abc5… florian 174 }
360abc5… florian 175 if( GetConsoleMode(hConsole,&dwConsoleMode) ){
360abc5… florian 176 return (dwConsoleMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)!=0;
360abc5… florian 177 }
360abc5… florian 178 return 0;
360abc5… florian 179 }
360abc5… florian 180 #endif /* _WIN32 */

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button