From 935aed7ca4339a72dc9ace7297d34550e991c6f9 Mon Sep 17 00:00:00 2001 From: Markus Heiser Date: Wed, 6 Sep 2023 19:12:27 +0200 Subject: [PATCH] [feature] dark theme for code highlighter in the result list Closes: https://github.com/searxng/searxng/issues/1354 Signed-off-by: Markus Heiser --- .../themes/simple/src/generated/pygments.less | 255 +++++++++++------- searx/static/themes/simple/src/less/code.less | 56 +++- .../simple/result_templates/code.html | 29 +- searx/webapp.py | 2 +- searxng_extra/update/update_pygments.py | 102 +++---- 5 files changed, 290 insertions(+), 154 deletions(-) diff --git a/searx/static/themes/simple/src/generated/pygments.less b/searx/static/themes/simple/src/generated/pygments.less index 083c4f296..d01c777fb 100644 --- a/searx/static/themes/simple/src/generated/pygments.less +++ b/searx/static/themes/simple/src/generated/pygments.less @@ -3,98 +3,171 @@ using pygments version 2.16.1 */ -.code-highlight .linenos { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - cursor: default; - &::selection { - background: transparent; /* WebKit/Blink Browsers */ - } - &::-moz-selection { - background: transparent; /* Gecko Browsers */ - } +.code-highlight { - margin-right: 8px; - text-align: right; + pre { line-height: 100%; } + td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } + span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } + td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } + span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } + .hll { background-color: #ffffcc } + .c { color: #3D7B7B; font-style: italic } /* Comment */ + .err { border: 1px solid #FF0000 } /* Error */ + .k { color: #008000; font-weight: bold } /* Keyword */ + .o { color: #666666 } /* Operator */ + .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ + .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ + .cp { color: #9C6500 } /* Comment.Preproc */ + .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ + .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ + .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ + .gd { color: #A00000 } /* Generic.Deleted */ + .ge { font-style: italic } /* Generic.Emph */ + .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ + .gr { color: #E40000 } /* Generic.Error */ + .gh { color: #000080; font-weight: bold } /* Generic.Heading */ + .gi { color: #008400 } /* Generic.Inserted */ + .go { color: #717171 } /* Generic.Output */ + .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ + .gs { font-weight: bold } /* Generic.Strong */ + .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ + .gt { color: #0044DD } /* Generic.Traceback */ + .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ + .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ + .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ + .kp { color: #008000 } /* Keyword.Pseudo */ + .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ + .kt { color: #B00040 } /* Keyword.Type */ + .m { color: #666666 } /* Literal.Number */ + .s { color: #BA2121 } /* Literal.String */ + .na { color: #687822 } /* Name.Attribute */ + .nb { color: #008000 } /* Name.Builtin */ + .nc { color: #0000FF; font-weight: bold } /* Name.Class */ + .no { color: #880000 } /* Name.Constant */ + .nd { color: #AA22FF } /* Name.Decorator */ + .ni { color: #717171; font-weight: bold } /* Name.Entity */ + .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ + .nf { color: #0000FF } /* Name.Function */ + .nl { color: #767600 } /* Name.Label */ + .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ + .nt { color: #008000; font-weight: bold } /* Name.Tag */ + .nv { color: #19177C } /* Name.Variable */ + .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ + .w { color: #bbbbbb } /* Text.Whitespace */ + .mb { color: #666666 } /* Literal.Number.Bin */ + .mf { color: #666666 } /* Literal.Number.Float */ + .mh { color: #666666 } /* Literal.Number.Hex */ + .mi { color: #666666 } /* Literal.Number.Integer */ + .mo { color: #666666 } /* Literal.Number.Oct */ + .sa { color: #BA2121 } /* Literal.String.Affix */ + .sb { color: #BA2121 } /* Literal.String.Backtick */ + .sc { color: #BA2121 } /* Literal.String.Char */ + .dl { color: #BA2121 } /* Literal.String.Delimiter */ + .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ + .s2 { color: #BA2121 } /* Literal.String.Double */ + .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ + .sh { color: #BA2121 } /* Literal.String.Heredoc */ + .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ + .sx { color: #008000 } /* Literal.String.Other */ + .sr { color: #A45A77 } /* Literal.String.Regex */ + .s1 { color: #BA2121 } /* Literal.String.Single */ + .ss { color: #19177C } /* Literal.String.Symbol */ + .bp { color: #008000 } /* Name.Builtin.Pseudo */ + .fm { color: #0000FF } /* Name.Function.Magic */ + .vc { color: #19177C } /* Name.Variable.Class */ + .vg { color: #19177C } /* Name.Variable.Global */ + .vi { color: #19177C } /* Name.Variable.Instance */ + .vm { color: #19177C } /* Name.Variable.Magic */ + .il { color: #666666 } /* Literal.Number.Integer.Long */ } -.code-highlight pre { line-height: 125%; } -.code-highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -.code-highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -.code-highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -.code-highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -.code-highlight .hll { background-color: #ffffcc } -.code-highlight { background: #f8f8f8; } -.code-highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ -.code-highlight .err { border: 1px solid #FF0000 } /* Error */ -.code-highlight .k { color: #008000; font-weight: bold } /* Keyword */ -.code-highlight .o { color: #666666 } /* Operator */ -.code-highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ -.code-highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ -.code-highlight .cp { color: #9C6500 } /* Comment.Preproc */ -.code-highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ -.code-highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ -.code-highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ -.code-highlight .gd { color: #A00000 } /* Generic.Deleted */ -.code-highlight .ge { font-style: italic } /* Generic.Emph */ -.code-highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ -.code-highlight .gr { color: #E40000 } /* Generic.Error */ -.code-highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.code-highlight .gi { color: #008400 } /* Generic.Inserted */ -.code-highlight .go { color: #717171 } /* Generic.Output */ -.code-highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -.code-highlight .gs { font-weight: bold } /* Generic.Strong */ -.code-highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.code-highlight .gt { color: #0044DD } /* Generic.Traceback */ -.code-highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ -.code-highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ -.code-highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ -.code-highlight .kp { color: #008000 } /* Keyword.Pseudo */ -.code-highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ -.code-highlight .kt { color: #B00040 } /* Keyword.Type */ -.code-highlight .m { color: #666666 } /* Literal.Number */ -.code-highlight .s { color: #BA2121 } /* Literal.String */ -.code-highlight .na { color: #687822 } /* Name.Attribute */ -.code-highlight .nb { color: #008000 } /* Name.Builtin */ -.code-highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ -.code-highlight .no { color: #880000 } /* Name.Constant */ -.code-highlight .nd { color: #AA22FF } /* Name.Decorator */ -.code-highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ -.code-highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ -.code-highlight .nf { color: #0000FF } /* Name.Function */ -.code-highlight .nl { color: #767600 } /* Name.Label */ -.code-highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ -.code-highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ -.code-highlight .nv { color: #19177C } /* Name.Variable */ -.code-highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ -.code-highlight .w { color: #bbbbbb } /* Text.Whitespace */ -.code-highlight .mb { color: #666666 } /* Literal.Number.Bin */ -.code-highlight .mf { color: #666666 } /* Literal.Number.Float */ -.code-highlight .mh { color: #666666 } /* Literal.Number.Hex */ -.code-highlight .mi { color: #666666 } /* Literal.Number.Integer */ -.code-highlight .mo { color: #666666 } /* Literal.Number.Oct */ -.code-highlight .sa { color: #BA2121 } /* Literal.String.Affix */ -.code-highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ -.code-highlight .sc { color: #BA2121 } /* Literal.String.Char */ -.code-highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ -.code-highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ -.code-highlight .s2 { color: #BA2121 } /* Literal.String.Double */ -.code-highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ -.code-highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ -.code-highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ -.code-highlight .sx { color: #008000 } /* Literal.String.Other */ -.code-highlight .sr { color: #A45A77 } /* Literal.String.Regex */ -.code-highlight .s1 { color: #BA2121 } /* Literal.String.Single */ -.code-highlight .ss { color: #19177C } /* Literal.String.Symbol */ -.code-highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ -.code-highlight .fm { color: #0000FF } /* Name.Function.Magic */ -.code-highlight .vc { color: #19177C } /* Name.Variable.Class */ -.code-highlight .vg { color: #19177C } /* Name.Variable.Global */ -.code-highlight .vi { color: #19177C } /* Name.Variable.Instance */ -.code-highlight .vm { color: #19177C } /* Name.Variable.Magic */ -.code-highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ +.code-highlight-dark(){ + .code-highlight { + + pre { line-height: 100%; } + td.linenos .normal { color: #3c4354; background-color: transparent; padding-left: 5px; padding-right: 5px; } + span.linenos { color: #3c4354; background-color: transparent; padding-left: 5px; padding-right: 5px; } + td.linenos .special { color: #3c4354; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } + span.linenos.special { color: #3c4354; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } + .hll { background-color: #6e7681 } + .c { color: #7e8aa1 } /* Comment */ + .err { color: #f88f7f } /* Error */ + .esc { color: #d4d2c8 } /* Escape */ + .g { color: #d4d2c8 } /* Generic */ + .k { color: #FFAD66 } /* Keyword */ + .l { color: #D5FF80 } /* Literal */ + .n { color: #d4d2c8 } /* Name */ + .o { color: #FFAD66 } /* Operator */ + .x { color: #d4d2c8 } /* Other */ + .p { color: #d4d2c8 } /* Punctuation */ + .ch { color: #f88f7f; font-style: italic } /* Comment.Hashbang */ + .cm { color: #7e8aa1 } /* Comment.Multiline */ + .cp { color: #FFAD66; font-weight: bold } /* Comment.Preproc */ + .cpf { color: #7e8aa1 } /* Comment.PreprocFile */ + .c1 { color: #7e8aa1 } /* Comment.Single */ + .cs { color: #7e8aa1; font-style: italic } /* Comment.Special */ + .gd { color: #f88f7f; background-color: #3d1e20 } /* Generic.Deleted */ + .ge { color: #d4d2c8; font-style: italic } /* Generic.Emph */ + .ges { color: #d4d2c8 } /* Generic.EmphStrong */ + .gr { color: #f88f7f } /* Generic.Error */ + .gh { color: #d4d2c8 } /* Generic.Heading */ + .gi { color: #6ad4af; background-color: #19362c } /* Generic.Inserted */ + .go { color: #7e8aa1 } /* Generic.Output */ + .gp { color: #d4d2c8 } /* Generic.Prompt */ + .gs { color: #d4d2c8; font-weight: bold } /* Generic.Strong */ + .gu { color: #d4d2c8 } /* Generic.Subheading */ + .gt { color: #f88f7f } /* Generic.Traceback */ + .kc { color: #FFAD66 } /* Keyword.Constant */ + .kd { color: #FFAD66 } /* Keyword.Declaration */ + .kn { color: #FFAD66 } /* Keyword.Namespace */ + .kp { color: #FFAD66 } /* Keyword.Pseudo */ + .kr { color: #FFAD66 } /* Keyword.Reserved */ + .kt { color: #73D0FF } /* Keyword.Type */ + .ld { color: #D5FF80 } /* Literal.Date */ + .m { color: #DFBFFF } /* Literal.Number */ + .s { color: #D5FF80 } /* Literal.String */ + .na { color: #FFD173 } /* Name.Attribute */ + .nb { color: #FFD173 } /* Name.Builtin */ + .nc { color: #73D0FF } /* Name.Class */ + .no { color: #FFD173 } /* Name.Constant */ + .nd { color: #7e8aa1; font-weight: bold; font-style: italic } /* Name.Decorator */ + .ni { color: #95E6CB } /* Name.Entity */ + .ne { color: #73D0FF } /* Name.Exception */ + .nf { color: #FFD173 } /* Name.Function */ + .nl { color: #d4d2c8 } /* Name.Label */ + .nn { color: #d4d2c8 } /* Name.Namespace */ + .nx { color: #d4d2c8 } /* Name.Other */ + .py { color: #FFD173 } /* Name.Property */ + .nt { color: #5CCFE6 } /* Name.Tag */ + .nv { color: #d4d2c8 } /* Name.Variable */ + .ow { color: #FFAD66 } /* Operator.Word */ + .pm { color: #d4d2c8 } /* Punctuation.Marker */ + .w { color: #d4d2c8 } /* Text.Whitespace */ + .mb { color: #DFBFFF } /* Literal.Number.Bin */ + .mf { color: #DFBFFF } /* Literal.Number.Float */ + .mh { color: #DFBFFF } /* Literal.Number.Hex */ + .mi { color: #DFBFFF } /* Literal.Number.Integer */ + .mo { color: #DFBFFF } /* Literal.Number.Oct */ + .sa { color: #F29E74 } /* Literal.String.Affix */ + .sb { color: #D5FF80 } /* Literal.String.Backtick */ + .sc { color: #D5FF80 } /* Literal.String.Char */ + .dl { color: #D5FF80 } /* Literal.String.Delimiter */ + .sd { color: #7e8aa1 } /* Literal.String.Doc */ + .s2 { color: #D5FF80 } /* Literal.String.Double */ + .se { color: #95E6CB } /* Literal.String.Escape */ + .sh { color: #D5FF80 } /* Literal.String.Heredoc */ + .si { color: #95E6CB } /* Literal.String.Interpol */ + .sx { color: #95E6CB } /* Literal.String.Other */ + .sr { color: #95E6CB } /* Literal.String.Regex */ + .s1 { color: #D5FF80 } /* Literal.String.Single */ + .ss { color: #DFBFFF } /* Literal.String.Symbol */ + .bp { color: #5CCFE6 } /* Name.Builtin.Pseudo */ + .fm { color: #FFD173 } /* Name.Function.Magic */ + .vc { color: #d4d2c8 } /* Name.Variable.Class */ + .vg { color: #d4d2c8 } /* Name.Variable.Global */ + .vi { color: #d4d2c8 } /* Name.Variable.Instance */ + .vm { color: #d4d2c8 } /* Name.Variable.Magic */ + .il { color: #DFBFFF } /* Literal.Number.Integer.Long */ + } +} diff --git a/searx/static/themes/simple/src/less/code.less b/searx/static/themes/simple/src/less/code.less index f4e6735ba..d6553feb8 100644 --- a/searx/static/themes/simple/src/less/code.less +++ b/searx/static/themes/simple/src/less/code.less @@ -1,9 +1,51 @@ -.code-highlight pre { - overflow: auto; - background-color: inherit; - color: inherit; - border: inherit; +@import "../generated/pygments.less"; + +.codelines { + margin: @results-margin 0 0 0; + padding: @result-padding 0 0 0; } -// stylelint-disable no-invalid-position-at-import-rule -@import "../generated/pygments.less"; +.code-highlight-sxng() { + .code-highlight { + pre { + overflow: auto; + margin: 0; + padding: 0 0 0.75rem 0; + } + + .linenos { + user-select: none; + cursor: default; + + &::selection { + background: transparent; /* WebKit/Blink Browsers */ + } + + &::-moz-selection { + background: transparent; /* Gecko Browsers */ + } + margin-right: 8px; + text-align: right; + } + + span.linenos { + color: #64708d; + } + } +} + +.code-highlight-sxng(); + +/// Dark Theme (autoswitch based on device pref) +@media (prefers-color-scheme: dark) { + :root.theme-auto { + .code-highlight-dark(); + .code-highlight-sxng(); + } +} + +// Dark Theme by preferences +:root.theme-dark { + .code-highlight-dark(); + .code-highlight-sxng(); +} diff --git a/searx/templates/simple/result_templates/code.html b/searx/templates/simple/result_templates/code.html index 3fe429caa..7d2c8ff79 100644 --- a/searx/templates/simple/result_templates/code.html +++ b/searx/templates/simple/result_templates/code.html @@ -2,12 +2,31 @@ {{ result_header(result, favicons, image_proxify) -}} {{- result_sub_header(result) -}} -{%- if result.content %}{{ result.content|safe }}{% endif %}

-{%- if result.repository -%} -

{{ result.repository }}

+ +{%- if result.content -%} +

+ {{- result.content|safe -}} +

{%- endif -%} +{%- if result.repository -%} +

{{- '' -}} + {{ _('repo') }}: {{- ' ' -}} + + {{- result.repository -}} + {{- '' -}} +

+{%- endif -%} +
{{- result.codelines|code_highlighter(result.code_language)|safe -}} -
{{- '' -}} + + {{- result_sub_footer(result, proxify) -}} -{{ result_footer(result) }} +{{- result_footer(result) -}} diff --git a/searx/webapp.py b/searx/webapp.py index 9793ee534..ec4f7627e 100755 --- a/searx/webapp.py +++ b/searx/webapp.py @@ -216,7 +216,7 @@ def code_highlighter(codelines, language=None): lexer = get_lexer_by_name(language, stripall=True) except Exception as e: # pylint: disable=broad-except - logger.exception(e, exc_info=True) + logger.warning("pygments lexer: %s " % e) # if lexer is not found, using default one lexer = get_lexer_by_name('text', stripall=True) diff --git a/searxng_extra/update/update_pygments.py b/searxng_extra/update/update_pygments.py index ca14868a2..69a8ee2db 100755 --- a/searxng_extra/update/update_pygments.py +++ b/searxng_extra/update/update_pygments.py @@ -1,69 +1,71 @@ #!/usr/bin/env python # SPDX-License-Identifier: AGPL-3.0-or-later -""" -Update pygments style +"""Update pygments style Call this script after each upgrade of pygments + """ -# pylint: disable=C0116 - -# set path -from os.path import join +from pathlib import Path import pygments -from pygments.formatters import HtmlFormatter # pylint: disable=E0611 -from pygments.style import Style -from pygments.token import Comment, Error, Generic, Keyword, Literal, Name, Operator, Text +from pygments.formatters import HtmlFormatter from searx import searx_dir -CSSCLASS = '.code-highlight' -RULE_CODE_LINENOS = """ .linenos { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - cursor: default; +LESS_FILE = Path(searx_dir) / 'static/themes/simple/src/generated/pygments.less' - &::selection { - background: transparent; /* WebKit/Blink Browsers */ - } - &::-moz-selection { - background: transparent; /* Gecko Browsers */ - } - - margin-right: 8px; - text-align: right; -}""" - - -def get_output_filename(relative_name): - return join(searx_dir, relative_name) - - -def get_css(cssclass, style): - result = f"""/* +HEADER = f"""\ +/* this file is generated automatically by searxng_extra/update/update_pygments.py using pygments version {pygments.__version__} -*/\n\n""" - css_text = HtmlFormatter(style=style).get_style_defs(cssclass) - result += cssclass + RULE_CODE_LINENOS + '\n\n' - for line in css_text.splitlines(): - if ' ' in line and not line.startswith(cssclass): - line = cssclass + ' ' + line - result += line + '\n' - return result +*/ + +""" + +START_LIGHT_THEME = """ +.code-highlight { +""" + +END_LIGHT_THEME = """ +} +""" + +START_DARK_THEME = """ +.code-highlight-dark(){ + .code-highlight { +""" + +END_DARK_THEME = """ + } +} +""" -def main(): +class Formatter(HtmlFormatter): + @property + def _pre_style(self): + return 'line-height: 100%;' - fname = 'static/themes/simple/src/generated/pygments.less' - print("update: %s" % fname) - with open(get_output_filename(fname), 'w') as f: - f.write(get_css(CSSCLASS, 'default')) + def get_style_lines(self, arg=None): + style_lines = [] + style_lines.extend(self.get_linenos_style_defs()) + style_lines.extend(self.get_background_style_defs(arg)) + style_lines.extend(self.get_token_style_defs(arg)) + return style_lines + + +def generat_css(light_style, dark_style) -> str: + css = HEADER + START_LIGHT_THEME + for line in Formatter(style=light_style).get_style_lines(): + css += '\n ' + line + css += END_LIGHT_THEME + START_DARK_THEME + for line in Formatter(style=dark_style).get_style_lines(): + css += '\n ' + line + css += END_DARK_THEME + return css if __name__ == '__main__': - main() + print("update: %s" % LESS_FILE) + with open(LESS_FILE, 'w') as f: + f.write(generat_css('default', 'lightbulb'))