From: Vladimír Vondruš Date: Tue, 21 Feb 2023 10:47:30 +0000 (+0100) Subject: m.code: support inverse video in the ANSI lexer. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~cjwatson/git?a=commitdiff_plain;h=5de213201100a16798787b026b8003b284740995;p=blog.git m.code: support inverse video in the ANSI lexer. I'm very glad for the extremely extensive code coverage here. Without it, I'd break half of other stuff by accident. --- diff --git a/css/m-dark+documentation.compiled.css b/css/m-dark+documentation.compiled.css index 9e36c569..e24e570b 100644 --- a/css/m-dark+documentation.compiled.css +++ b/css/m-dark+documentation.compiled.css @@ -2619,12 +2619,14 @@ article:last-child, article section:last-child { margin-bottom: 0; } .m-console .g-AnsiBrightCyan { color: #16a085; font-weight: bold } .m-console .g-AnsiBrightDefault { color: #ffffff; font-weight: bold } .m-console .g-AnsiBrightGreen { color: #1cdc9a; font-weight: bold } +.m-console .g-AnsiBrightInvertedDefault { color: #1a1c1d; font-weight: bold } .m-console .g-AnsiBrightMagenta { color: #8e44ad; font-weight: bold } .m-console .g-AnsiBrightRed { color: #c0392b; font-weight: bold } .m-console .g-AnsiBrightWhite { color: #ffffff; font-weight: bold } .m-console .g-AnsiBrightYellow { color: #fdbc4b; font-weight: bold } .m-console .g-AnsiCyan { color: #1abc9c } .m-console .g-AnsiGreen { color: #11d116 } +.m-console .g-AnsiInvertedDefault { color: #1a1c1d } .m-console .g-AnsiMagenta { color: #9b59b6 } .m-console .g-AnsiRed { color: #ed1515 } .m-console .g-AnsiWhite { color: #fcfcfc } diff --git a/css/m-dark.compiled.css b/css/m-dark.compiled.css index 587e8da8..571467e6 100644 --- a/css/m-dark.compiled.css +++ b/css/m-dark.compiled.css @@ -2619,12 +2619,14 @@ article:last-child, article section:last-child { margin-bottom: 0; } .m-console .g-AnsiBrightCyan { color: #16a085; font-weight: bold } .m-console .g-AnsiBrightDefault { color: #ffffff; font-weight: bold } .m-console .g-AnsiBrightGreen { color: #1cdc9a; font-weight: bold } +.m-console .g-AnsiBrightInvertedDefault { color: #1a1c1d; font-weight: bold } .m-console .g-AnsiBrightMagenta { color: #8e44ad; font-weight: bold } .m-console .g-AnsiBrightRed { color: #c0392b; font-weight: bold } .m-console .g-AnsiBrightWhite { color: #ffffff; font-weight: bold } .m-console .g-AnsiBrightYellow { color: #fdbc4b; font-weight: bold } .m-console .g-AnsiCyan { color: #1abc9c } .m-console .g-AnsiGreen { color: #11d116 } +.m-console .g-AnsiInvertedDefault { color: #1a1c1d } .m-console .g-AnsiMagenta { color: #9b59b6 } .m-console .g-AnsiRed { color: #ed1515 } .m-console .g-AnsiWhite { color: #fcfcfc } diff --git a/css/m-light+documentation.compiled.css b/css/m-light+documentation.compiled.css index ea5206ac..31ebcdab 100644 --- a/css/m-light+documentation.compiled.css +++ b/css/m-light+documentation.compiled.css @@ -2552,12 +2552,14 @@ article:last-child, article section:last-child { margin-bottom: 0; } .m-console .g-AnsiBrightCyan { color: #16a085; font-weight: bold } .m-console .g-AnsiBrightDefault { color: #ffffff; font-weight: bold } .m-console .g-AnsiBrightGreen { color: #1cdc9a; font-weight: bold } +.m-console .g-AnsiBrightInvertedDefault { color: #1a1c1d; font-weight: bold } .m-console .g-AnsiBrightMagenta { color: #8e44ad; font-weight: bold } .m-console .g-AnsiBrightRed { color: #c0392b; font-weight: bold } .m-console .g-AnsiBrightWhite { color: #ffffff; font-weight: bold } .m-console .g-AnsiBrightYellow { color: #fdbc4b; font-weight: bold } .m-console .g-AnsiCyan { color: #1abc9c } .m-console .g-AnsiGreen { color: #11d116 } +.m-console .g-AnsiInvertedDefault { color: #1a1c1d } .m-console .g-AnsiMagenta { color: #9b59b6 } .m-console .g-AnsiRed { color: #ed1515 } .m-console .g-AnsiWhite { color: #fcfcfc } diff --git a/css/m-light.compiled.css b/css/m-light.compiled.css index 421cb46d..a8c42325 100644 --- a/css/m-light.compiled.css +++ b/css/m-light.compiled.css @@ -2552,12 +2552,14 @@ article:last-child, article section:last-child { margin-bottom: 0; } .m-console .g-AnsiBrightCyan { color: #16a085; font-weight: bold } .m-console .g-AnsiBrightDefault { color: #ffffff; font-weight: bold } .m-console .g-AnsiBrightGreen { color: #1cdc9a; font-weight: bold } +.m-console .g-AnsiBrightInvertedDefault { color: #1a1c1d; font-weight: bold } .m-console .g-AnsiBrightMagenta { color: #8e44ad; font-weight: bold } .m-console .g-AnsiBrightRed { color: #c0392b; font-weight: bold } .m-console .g-AnsiBrightWhite { color: #ffffff; font-weight: bold } .m-console .g-AnsiBrightYellow { color: #fdbc4b; font-weight: bold } .m-console .g-AnsiCyan { color: #1abc9c } .m-console .g-AnsiGreen { color: #11d116 } +.m-console .g-AnsiInvertedDefault { color: #1a1c1d } .m-console .g-AnsiMagenta { color: #9b59b6 } .m-console .g-AnsiRed { color: #ed1515 } .m-console .g-AnsiWhite { color: #fcfcfc } diff --git a/css/pygments-console.css b/css/pygments-console.css index 0446bbd8..d74ad003 100644 --- a/css/pygments-console.css +++ b/css/pygments-console.css @@ -22,12 +22,14 @@ .m-console .g-AnsiBrightCyan { color: #16a085; font-weight: bold } /* Generic.AnsiBrightCyan */ .m-console .g-AnsiBrightDefault { color: #ffffff; font-weight: bold } /* Generic.AnsiBrightDefault */ .m-console .g-AnsiBrightGreen { color: #1cdc9a; font-weight: bold } /* Generic.AnsiBrightGreen */ +.m-console .g-AnsiBrightInvertedDefault { color: #1a1c1d; font-weight: bold } /* Generic.AnsiBrightInvertedDefault */ .m-console .g-AnsiBrightMagenta { color: #8e44ad; font-weight: bold } /* Generic.AnsiBrightMagenta */ .m-console .g-AnsiBrightRed { color: #c0392b; font-weight: bold } /* Generic.AnsiBrightRed */ .m-console .g-AnsiBrightWhite { color: #ffffff; font-weight: bold } /* Generic.AnsiBrightWhite */ .m-console .g-AnsiBrightYellow { color: #fdbc4b; font-weight: bold } /* Generic.AnsiBrightYellow */ .m-console .g-AnsiCyan { color: #1abc9c } /* Generic.AnsiCyan */ .m-console .g-AnsiGreen { color: #11d116 } /* Generic.AnsiGreen */ +.m-console .g-AnsiInvertedDefault { color: #1a1c1d } /* Generic.AnsiInvertedDefault */ .m-console .g-AnsiMagenta { color: #9b59b6 } /* Generic.AnsiMagenta */ .m-console .g-AnsiRed { color: #ed1515 } /* Generic.AnsiRed */ .m-console .g-AnsiWhite { color: #fcfcfc } /* Generic.AnsiWhite */ diff --git a/css/pygments-console.py b/css/pygments-console.py index 49955a40..e0bee34b 100644 --- a/css/pygments-console.py +++ b/css/pygments-console.py @@ -40,6 +40,7 @@ class ConsoleStyle(Style): # ANSI highlighting. Same order as in Konsole style dialog, following # the Breeze theme. + Generic.AnsiInvertedDefault: '#1a1c1d', Generic.AnsiBlack: '#232627', Generic.AnsiRed: '#ed1515', Generic.AnsiGreen: '#11d116', @@ -48,6 +49,7 @@ class ConsoleStyle(Style): Generic.AnsiMagenta: '#9b59b6', Generic.AnsiCyan: '#1abc9c', Generic.AnsiWhite: '#fcfcfc', + Generic.AnsiBrightInvertedDefault: 'bold #1a1c1d', Generic.AnsiBrightBlack: 'bold #7f8c8d', Generic.AnsiBrightRed: 'bold #c0392b', Generic.AnsiBrightGreen: 'bold #1cdc9a', diff --git a/plugins/ansilexer.py b/plugins/ansilexer.py index 05246507..fd791d26 100644 --- a/plugins/ansilexer.py +++ b/plugins/ansilexer.py @@ -30,9 +30,8 @@ from pygments.lexer import RegexLexer from pygments.formatters import HtmlFormatter from pygments.token import * -# Support ANSI SGR codes in input, styling the output. -# Code definitions are taken from -# http://man7.org/linux/man-pages/man4/console_codes.4.html, which +# Support ANSI SGR codes in input, styling the output. Code definitions are +# taken from http://man7.org/linux/man-pages/man4/console_codes.4.html, which # appears in part below, in case it disappears: # # ECMA-48 Set Graphics Rendition @@ -100,9 +99,8 @@ from pygments.token import * # For historical reasons, all "brown"s above are replaced with "yellow" # by m.css. # -# AnsiLexer supports commands 0, 1, 22, 30–39, 40–49, 90–97, and 100–107 -# (ranges inclusive). -# All other commands will be ignored completely. +# AnsiLexer supports commands 0, 1, 7, 22, 27, 30–39, 40–49, 90–97, and 100–107 +# (ranges inclusive). All other commands will be ignored completely. # # Foreground colors named Bright* are not affected by the "bright" SGR # setting—they will always appear bright, even after command 22 resets the @@ -152,6 +150,7 @@ class AnsiLexer(RegexLexer): RegexLexer.__init__(self, **options) self._bright = False + self._invert = False self._foreground = '' self._background = '' @@ -169,12 +168,17 @@ class AnsiLexer(RegexLexer): command = parameters.pop(0) if command == 0: self._bright = False + self._invert = False self._foreground = '' self._background = '' elif command == 1: self._bright = True + elif command == 7: + self._invert = True elif command == 22: self._bright = False + elif command == 27: + self._invert = False elif command >= 30 and command <= 37: self._foreground = self._named_colors[command - 30] elif command == 38: @@ -204,15 +208,35 @@ class AnsiLexer(RegexLexer): self._background = ('Bright' + self._named_colors[command - 100]) - if self._bright and self._foreground in self._named_colors: - token = 'Bright' + self._foreground - elif self._bright and not self._foreground: - token = 'BrightDefault' + # For "inverse video", foreground and background colors are swapped + if self._invert: + foreground, background = self._background, self._foreground else: - token = self._foreground + foreground, background = self._foreground, self._background - if (self._background): - token += '-On' + self._background + # If the bright bit is set for named colors (foreground or background + # in case of reverse video), use their bright variant + if self._bright and (not foreground or (foreground in self._named_colors)): + token = 'Bright' + else: + token = '' + + # If the foreground color (or background in case of inverse video) is + # set, use it. Otherwise pick a default if it's needed for the bright + # variant, for inverse video or both. + if foreground: + token += foreground + else: + if self._invert: + token += 'Inverted' + if token: + token += 'Default' + + # If the background color is set (or foreground in case of inverse + # video), use it as well. This gets subsequently separated to either a + # secondary CSS class or a separate background-color style item. + if background: + token += '-On' + background if token: token = 'Generic.Ansi' + token diff --git a/plugins/m/test/code/console-colors.ansi b/plugins/m/test/code/console-colors.ansi index c17093c7..7a3016f0 100644 --- a/plugins/m/test/code/console-colors.ansi +++ b/plugins/m/test/code/console-colors.ansi @@ -85,15 +85,21 @@ nor do RGB or palette-based colors RGB 0,128,128 on RGB 0,128,128 RGB 192,192,0 on RGB 0,128,128 +Inverted colors: + Blue Inverted Inverted again Reset + Blue Inverted Inverted back Reset + Blue Inverted and bright Inverted again Reset + Blue Inverted and bright Inverted back Reset + Bright blue Inverted Inverted again Reset + Bright blue Inverted Inverted back Reset + Other commands are ignored half-bright set underscore set blink - set reverse video reset selected mapping, display control flag, and toggle select null mapping, set display control flag, reset select null mapping, set display control flag, set toggle set underline underline off blink off - reverse video off diff --git a/plugins/m/test/code/page.html b/plugins/m/test/code/page.html index 2a63fc1e..59fdeb41 100644 --- a/plugins/m/test/code/page.html +++ b/plugins/m/test/code/page.html @@ -138,18 +138,24 @@ ASan reports: RGB 0,128,128 on RGB 0,128,128 RGB 192,192,0 on RGB 0,128,128 +Inverted colors: + Blue Inverted Inverted again Reset + Blue Inverted Inverted back Reset + Blue Inverted and bright Inverted again Reset + Blue Inverted and bright Inverted back Reset + Bright blue Inverted Inverted again Reset + Bright blue Inverted Inverted back Reset + Other commands are ignored half-bright set underscore set blink - set reverse video reset selected mapping, display control flag, and toggle select null mapping, set display control flag, reset select null mapping, set display control flag, set toggle set underline underline off - blink off - reverse video off + blink off
// this language is not highlighted

Properly preserve backslashes: \frac{a}{b} ... and backticks: :ref:`a function <os.path.join()>`