Skip to content

HTML template CSS: add dark mode with --highlight-style-dark #7131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions MANUAL.txt
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,12 @@ header when requesting a document from a URL:
To generate the JSON version of an existing style,
use `--print-highlight-style`.

`--highlight-style-dark=`*STYLE*|*FILE*

: Specifies the coloring style to be used in highlighted source code
in [dark mode] for HTML-based output formats. The default is `breezeDark`.
See `--highlight-style` for more information.

`--print-highlight-style=`*STYLE*|*FILE*

: Prints a JSON version of a highlighting style, which can
Expand Down Expand Up @@ -6202,6 +6208,10 @@ scheme used by the Python library pygments (though pygments is not actually
used to do the highlighting). To see a list of highlight styles,
type `pandoc --list-highlight-styles`.

For HTML-based output formats, the color scheme used for [dark mode]
can be selected using the `--highlight-style-dark` option.
It defaults to `breezeDark`.

If you are not satisfied with the predefined styles, you can
use `--print-highlight-style` to generate a JSON `.theme` file which
can be modified and used as the argument to `--highlight-style`. To
Expand All @@ -6223,6 +6233,7 @@ definitions](https://github.com/KDE/syntax-highlighting/tree/master/data/syntax)
To disable highlighting, use the `--no-highlight` option.

[skylighting]: https://github.com/jgm/skylighting
[dark mode]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme

# Custom Styles

Expand Down
28 changes: 28 additions & 0 deletions data/templates/styles.html
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,31 @@
margin-left: 2em;
}
$endif$
$if(document-css)$
@media screen and (prefers-color-scheme: dark) {
html {
color: #d3d3d3;
background-color: #101010;
}
a, a:visited {
color: #d3d3d3;
}
blockquote {
border-color: #707070;
color: #d3d3d3;
}
hr {
background-color: #d3d3d3;
}
tbody, th {
border-color: #d3d3d3;
}
pre, code {
background-color: #1b1b1b;
}
$if(highlighting-css-dark)$
$highlighting-css-dark$
$endif$
}
$endif$

12 changes: 11 additions & 1 deletion src/Text/Pandoc/App/CommandLineOptions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,9 @@ options =

, Option "" ["no-highlight"]
(NoArg
(\opt -> return opt { optHighlightStyle = Nothing }))
(\opt -> return opt { optHighlightStyle = Nothing
, optHighlightStyleDark = Nothing
}))
"" -- "Don't highlight source code"

, Option "" ["highlight-style"]
Expand All @@ -330,6 +332,14 @@ options =
"STYLE|FILE")
"" -- "Style for highlighted code"

, Option "" ["highlight-style-dark"]
(ReqArg
(\arg opt ->
return opt{ optHighlightStyleDark = Just $
T.pack $ normalizePath arg })
"STYLE|FILE")
"" -- "Style for highlighted code in dark mode"

, Option "" ["syntax-definition"]
(ReqArg
(\arg opt -> do
Expand Down
4 changes: 4 additions & 0 deletions src/Text/Pandoc/App/Opt.hs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ data Opt = Opt
, optSelfContained :: Bool -- ^ Make HTML accessible offline
, optHtmlQTags :: Bool -- ^ Use <q> tags in HTML
, optHighlightStyle :: Maybe Text -- ^ Style to use for highlighted code
, optHighlightStyleDark :: Maybe Text -- ^ Style to use for highlighted code in dark mode
, optSyntaxDefinitions :: [FilePath] -- ^ xml syntax defs to load
, optTopLevelDivision :: TopLevelDivision -- ^ Type of the top-level divisions
, optHTMLMathMethod :: HTMLMathMethod -- ^ Method to print HTML math
Expand Down Expand Up @@ -417,6 +418,8 @@ doOpt (k',v) = do
parseYAML v >>= \x -> return (\o -> o{ optHtmlQTags = x })
"highlight-style" ->
parseYAML v >>= \x -> return (\o -> o{ optHighlightStyle = x })
"highlight-style-dark" ->
parseYAML v >>= \x -> return (\o -> o{ optHighlightStyleDark = x })
"syntax-definition" ->
(parseYAML v >>= \x ->
return (\o -> o{ optSyntaxDefinitions =
Expand Down Expand Up @@ -620,6 +623,7 @@ defaultOpts = Opt
, optSelfContained = False
, optHtmlQTags = False
, optHighlightStyle = Just "pygments"
, optHighlightStyleDark = Just "breezeDark"
, optSyntaxDefinitions = []
, optTopLevelDivision = TopLevelDefault
, optHTMLMathMethod = PlainMath
Expand Down
2 changes: 2 additions & 0 deletions src/Text/Pandoc/App/OutputSettings.hs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ optToOutputSettings opts = do
(optSyntaxDefinitions opts)

hlStyle <- traverse (lookupHighlightStyle . T.unpack) $ optHighlightStyle opts
hlStyleDark <- traverse (lookupHighlightStyle . T.unpack) $ optHighlightStyleDark opts

let setVariableM k v = return . setVariable k v

Expand Down Expand Up @@ -202,6 +203,7 @@ optToOutputSettings opts = do
, writerListings = optListings opts
, writerSlideLevel = optSlideLevel opts
, writerHighlightStyle = hlStyle
, writerHighlightStyleDark = hlStyleDark
, writerSetextHeaders = optSetextHeaders opts
, writerEpubSubdirectory = T.pack $ optEpubSubdirectory opts
, writerEpubMetadata = epubMetadata
Expand Down
4 changes: 3 additions & 1 deletion src/Text/Pandoc/Options.hs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import GHC.Generics (Generic)
import Skylighting (SyntaxMap, defaultSyntaxMap)
import Text.DocTemplates (Context(..), Template)
import Text.Pandoc.Extensions
import Text.Pandoc.Highlighting (Style, pygments)
import Text.Pandoc.Highlighting (Style, breezeDark, pygments)
import Text.Pandoc.Shared (camelCaseStrToHyphenated)
import Data.Aeson.TH (deriveJSON, defaultOptions, Options(..),
SumEncoding(..))
Expand Down Expand Up @@ -255,6 +255,7 @@ data WriterOptions = WriterOptions
, writerListings :: Bool -- ^ Use listings package for code
, writerHighlightStyle :: Maybe Style -- ^ Style to use for highlighting
-- (Nothing = no highlighting)
, writerHighlightStyleDark :: Maybe Style -- ^ Style to use for highlighting dark mode
, writerSetextHeaders :: Bool -- ^ Use setext headers for levels 1-2 in markdown
, writerEpubSubdirectory :: Text -- ^ Subdir for epub in OCF
, writerEpubMetadata :: Maybe Text -- ^ Metadata to include in EPUB
Expand Down Expand Up @@ -290,6 +291,7 @@ instance Default WriterOptions where
, writerTopLevelDivision = TopLevelDefault
, writerListings = False
, writerHighlightStyle = Just pygments
, writerHighlightStyleDark = Just breezeDark
, writerSetextHeaders = False
, writerEpubSubdirectory = "EPUB"
, writerEpubMetadata = Nothing
Expand Down
6 changes: 6 additions & 0 deletions src/Text/Pandoc/Writers/HTML.hs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,12 @@ pandocToHtml opts (Pandoc meta blocks) = do
(T.pack $ styleToCss sty)
Nothing -> id
else id) .
(if stHighlighting st
then case writerHighlightStyleDark opts of
Just sty -> defField "highlighting-css-dark"
(T.pack $ styleToCss sty)
Nothing -> id
else id) .
(if stCsl st
then defField "csl-css" True .
(case stCslEntrySpacing st of
Expand Down
88 changes: 88 additions & 0 deletions test/lhs-test.html
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,94 @@
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
@media screen and (prefers-color-scheme: dark) {
html {
color: #d3d3d3;
background-color: #101010;
}
a, a:visited {
color: #d3d3d3;
}
blockquote {
border-color: #707070;
color: #d3d3d3;
}
hr {
background-color: #d3d3d3;
}
tbody, th {
border-color: #d3d3d3;
}
pre, code {
background-color: #1b1b1b;
}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
background-color: #232629;
color: #7a7c7d;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #7a7c7d; padding-left: 4px; }
div.sourceCode
{ color: #cfcfc2; background-color: #232629; }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span { color: #cfcfc2; } /* Normal */
code span.al { color: #95da4c; background-color: #4d1f24; font-weight: bold; } /* Alert */
code span.an { color: #3f8058; } /* Annotation */
code span.at { color: #2980b9; } /* Attribute */
code span.bn { color: #f67400; } /* BaseN */
code span.bu { color: #7f8c8d; } /* BuiltIn */
code span.cf { color: #fdbc4b; font-weight: bold; } /* ControlFlow */
code span.ch { color: #3daee9; } /* Char */
code span.cn { color: #27aeae; font-weight: bold; } /* Constant */
code span.co { color: #7a7c7d; } /* Comment */
code span.cv { color: #7f8c8d; } /* CommentVar */
code span.do { color: #a43340; } /* Documentation */
code span.dt { color: #2980b9; } /* DataType */
code span.dv { color: #f67400; } /* DecVal */
code span.er { color: #da4453; text-decoration: underline; } /* Error */
code span.ex { color: #0099ff; font-weight: bold; } /* Extension */
code span.fl { color: #f67400; } /* Float */
code span.fu { color: #8e44ad; } /* Function */
code span.im { color: #27ae60; } /* Import */
code span.in { color: #c45b00; } /* Information */
code span.kw { color: #cfcfc2; font-weight: bold; } /* Keyword */
code span.op { color: #cfcfc2; } /* Operator */
code span.ot { color: #27ae60; } /* Other */
code span.pp { color: #27ae60; } /* Preprocessor */
code span.re { color: #2980b9; background-color: #153042; } /* RegionMarker */
code span.sc { color: #3daee9; } /* SpecialChar */
code span.ss { color: #da4453; } /* SpecialString */
code span.st { color: #f44f4f; } /* String */
code span.va { color: #27aeae; } /* Variable */
code span.vs { color: #da4453; } /* VerbatimString */
code span.wa { color: #da4453; } /* Warning */
}
</style>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
Expand Down
88 changes: 88 additions & 0 deletions test/lhs-test.html+lhs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,94 @@
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
@media screen and (prefers-color-scheme: dark) {
html {
color: #d3d3d3;
background-color: #101010;
}
a, a:visited {
color: #d3d3d3;
}
blockquote {
border-color: #707070;
color: #d3d3d3;
}
hr {
background-color: #d3d3d3;
}
tbody, th {
border-color: #d3d3d3;
}
pre, code {
background-color: #1b1b1b;
}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
background-color: #232629;
color: #7a7c7d;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #7a7c7d; padding-left: 4px; }
div.sourceCode
{ color: #cfcfc2; background-color: #232629; }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span { color: #cfcfc2; } /* Normal */
code span.al { color: #95da4c; background-color: #4d1f24; font-weight: bold; } /* Alert */
code span.an { color: #3f8058; } /* Annotation */
code span.at { color: #2980b9; } /* Attribute */
code span.bn { color: #f67400; } /* BaseN */
code span.bu { color: #7f8c8d; } /* BuiltIn */
code span.cf { color: #fdbc4b; font-weight: bold; } /* ControlFlow */
code span.ch { color: #3daee9; } /* Char */
code span.cn { color: #27aeae; font-weight: bold; } /* Constant */
code span.co { color: #7a7c7d; } /* Comment */
code span.cv { color: #7f8c8d; } /* CommentVar */
code span.do { color: #a43340; } /* Documentation */
code span.dt { color: #2980b9; } /* DataType */
code span.dv { color: #f67400; } /* DecVal */
code span.er { color: #da4453; text-decoration: underline; } /* Error */
code span.ex { color: #0099ff; font-weight: bold; } /* Extension */
code span.fl { color: #f67400; } /* Float */
code span.fu { color: #8e44ad; } /* Function */
code span.im { color: #27ae60; } /* Import */
code span.in { color: #c45b00; } /* Information */
code span.kw { color: #cfcfc2; font-weight: bold; } /* Keyword */
code span.op { color: #cfcfc2; } /* Operator */
code span.ot { color: #27ae60; } /* Other */
code span.pp { color: #27ae60; } /* Preprocessor */
code span.re { color: #2980b9; background-color: #153042; } /* RegionMarker */
code span.sc { color: #3daee9; } /* SpecialChar */
code span.ss { color: #da4453; } /* SpecialString */
code span.st { color: #f44f4f; } /* String */
code span.va { color: #27aeae; } /* Variable */
code span.vs { color: #da4453; } /* VerbatimString */
code span.wa { color: #da4453; } /* Warning */
}
</style>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
Expand Down
22 changes: 22 additions & 0 deletions test/writer.html4
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,28 @@
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
@media screen and (prefers-color-scheme: dark) {
html {
color: #d3d3d3;
background-color: #101010;
}
a, a:visited {
color: #d3d3d3;
}
blockquote {
border-color: #707070;
color: #d3d3d3;
}
hr {
background-color: #d3d3d3;
}
tbody, th {
border-color: #d3d3d3;
}
pre, code {
background-color: #1b1b1b;
}
}
</style>
</head>
<body>
Expand Down
Loading