Support setting foreground/background colors to terminal defaults (#8073)

* Support setting foreground/background colors to terminal defaults

Adds fgDefault to ForegroundColor and bgDefault to BackgroundColor
enums.

For Windows console, the default foreground color is assumed to be
white, and the default background color black.

* Add default fg/bg color caching for Windows Console
This commit is contained in:
Kaushal Modi 2018-06-24 03:53:20 -04:00 • committed by Varriount
commit 4c2e712056

View file

@ -542,7 +542,9 @@ type
fgBlue, ## blue fgBlue, ## blue
fgMagenta, ## magenta fgMagenta, ## magenta
fgCyan, ## cyan fgCyan, ## cyan
fgWhite ## white fgWhite, ## white
fg8Bit, ## 256-color (not supported, see ``enableTrueColors`` instead.)
fgDefault ## default terminal foreground color
BackgroundColor* = enum ## terminal's background colors BackgroundColor* = enum ## terminal's background colors
bgBlack = 40, ## black bgBlack = 40, ## black
@ -552,28 +554,40 @@ type
bgBlue, ## blue bgBlue, ## blue
bgMagenta, ## magenta bgMagenta, ## magenta
bgCyan, ## cyan bgCyan, ## cyan
bgWhite ## white bgWhite, ## white
bg8Bit, ## 256-color (not supported, see ``enableTrueColors`` instead.)
bgDefault ## default terminal background color
{.deprecated: [TForegroundColor: ForegroundColor, {.deprecated: [TForegroundColor: ForegroundColor,
TBackgroundColor: BackgroundColor].} TBackgroundColor: BackgroundColor].}
when defined(windows):
var defaultForegroundColor, defaultBackgroundColor: int16 = 0xFFFF'i16 # Default to an invalid value 0xFFFF
proc setForegroundColor*(f: File, fg: ForegroundColor, bright=false) = proc setForegroundColor*(f: File, fg: ForegroundColor, bright=false) =
## Sets the terminal's foreground color. ## Sets the terminal's foreground color.
when defined(windows): when defined(windows):
let h = conHandle(f) let h = conHandle(f)
var old = getAttributes(h) and not FOREGROUND_RGB var old = getAttributes(h) and not FOREGROUND_RGB
if defaultForegroundColor == 0xFFFF'i16:
defaultForegroundColor = old
old = if bright: old or FOREGROUND_INTENSITY old = if bright: old or FOREGROUND_INTENSITY
else: old and not(FOREGROUND_INTENSITY) else: old and not(FOREGROUND_INTENSITY)
const lookup: array[ForegroundColor, int] = [ const lookup: array[ForegroundColor, int] = [
0, 0, # ForegroundColor enum with ordinal 30
(FOREGROUND_RED), (FOREGROUND_RED),
(FOREGROUND_GREEN), (FOREGROUND_GREEN),
(FOREGROUND_RED or FOREGROUND_GREEN), (FOREGROUND_RED or FOREGROUND_GREEN),
(FOREGROUND_BLUE), (FOREGROUND_BLUE),
(FOREGROUND_RED or FOREGROUND_BLUE), (FOREGROUND_RED or FOREGROUND_BLUE),
(FOREGROUND_BLUE or FOREGROUND_GREEN), (FOREGROUND_BLUE or FOREGROUND_GREEN),
(FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED)] (FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED),
discard setConsoleTextAttribute(h, toU16(old or lookup[fg])) 0, # fg8Bit not supported, see ``enableTrueColors`` instead.
0] # unused
if fg == fgDefault:
discard setConsoleTextAttribute(h, toU16(old or defaultForegroundColor))
else:
discard setConsoleTextAttribute(h, toU16(old or lookup[fg]))
else: else:
gFG = ord(fg) gFG = ord(fg)
if bright: inc(gFG, 60) if bright: inc(gFG, 60)
@ -584,18 +598,25 @@ proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) =
when defined(windows): when defined(windows):
let h = conHandle(f) let h = conHandle(f)
var old = getAttributes(h) and not BACKGROUND_RGB var old = getAttributes(h) and not BACKGROUND_RGB
if defaultBackgroundColor == 0xFFFF'i16:
defaultBackgroundColor = old
old = if bright: old or BACKGROUND_INTENSITY old = if bright: old or BACKGROUND_INTENSITY
else: old and not(BACKGROUND_INTENSITY) else: old and not(BACKGROUND_INTENSITY)
const lookup: array[BackgroundColor, int] = [ const lookup: array[BackgroundColor, int] = [
0, 0, # BackgroundColor enum with ordinal 40
(BACKGROUND_RED), (BACKGROUND_RED),
(BACKGROUND_GREEN), (BACKGROUND_GREEN),
(BACKGROUND_RED or BACKGROUND_GREEN), (BACKGROUND_RED or BACKGROUND_GREEN),
(BACKGROUND_BLUE), (BACKGROUND_BLUE),
(BACKGROUND_RED or BACKGROUND_BLUE), (BACKGROUND_RED or BACKGROUND_BLUE),
(BACKGROUND_BLUE or BACKGROUND_GREEN), (BACKGROUND_BLUE or BACKGROUND_GREEN),
(BACKGROUND_BLUE or BACKGROUND_GREEN or BACKGROUND_RED)] (BACKGROUND_BLUE or BACKGROUND_GREEN or BACKGROUND_RED),
discard setConsoleTextAttribute(h, toU16(old or lookup[bg])) 0, # bg8Bit not supported, see ``enableTrueColors`` instead.
0] # unused
if bg == bgDefault:
discard setConsoleTextAttribute(h, toU16(old or defaultBackgroundColor))
else:
discard setConsoleTextAttribute(h, toU16(old or lookup[bg]))
else: else:
gBG = ord(bg) gBG = ord(bg)
if bright: inc(gBG, 60) if bright: inc(gBG, 60)
@ -935,3 +956,6 @@ when not defined(testing) and isMainModule:
stdout.styledWrite(fgGreen, "green text") stdout.styledWrite(fgGreen, "green text")
echo "" echo ""
echo "ordinary text" echo "ordinary text"
stdout.styledWriteLine(fgRed, "red text ", styleBright, "bold red", fgDefault, " bold text")
stdout.styledWriteLine(bgYellow, "text in yellow bg", styleBright, " bold text in yellow bg", bgDefault, " bold text")
echo "ordinary text"