diff --git a/.gitignore b/.gitignore index c16d981..e527154 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,8 @@ npm-debug.log # Ignore the pygments venv directory /priv/pygments/ +# Ignore chroma bin directory +/priv/chroma/ # dev TODO.md diff --git a/assets/css/_chroma.css b/assets/css/_chroma.css new file mode 100644 index 0000000..b13aa15 --- /dev/null +++ b/assets/css/_chroma.css @@ -0,0 +1,60 @@ +/* Background */ .chroma { color: #8a8a8a; background-color: #1c1c1c } +/* Other */ .chroma .x { color: #d75f00 } +/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; } +/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; } +/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #323232 } +/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #454545 } +/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #454545 } +/* Keyword */ .chroma .k { color: #5f8700 } +/* KeywordConstant */ .chroma .kc { color: #d75f00 } +/* KeywordDeclaration */ .chroma .kd { color: #0087ff } +/* KeywordNamespace */ .chroma .kn { color: #d75f00 } +/* KeywordPseudo */ .chroma .kp { color: #5f8700 } +/* KeywordReserved */ .chroma .kr { color: #0087ff } +/* KeywordType */ .chroma .kt { color: #af0000 } +/* NameBuiltin */ .chroma .nb { color: #0087ff } +/* NameBuiltinPseudo */ .chroma .bp { color: #0087ff } +/* NameClass */ .chroma .nc { color: #0087ff } +/* NameConstant */ .chroma .no { color: #d75f00 } +/* NameDecorator */ .chroma .nd { color: #0087ff } +/* NameEntity */ .chroma .ni { color: #d75f00 } +/* NameException */ .chroma .ne { color: #af8700 } +/* NameFunction */ .chroma .nf { color: #0087ff } +/* NameTag */ .chroma .nt { color: #0087ff } +/* NameVariable */ .chroma .nv { color: #0087ff } +/* LiteralString */ .chroma .s { color: #00afaf } +/* LiteralStringAffix */ .chroma .sa { color: #00afaf } +/* LiteralStringBacktick */ .chroma .sb { color: #4e4e4e } +/* LiteralStringChar */ .chroma .sc { color: #00afaf } +/* LiteralStringDelimiter */ .chroma .dl { color: #00afaf } +/* LiteralStringDoc */ .chroma .sd { color: #00afaf } +/* LiteralStringDouble */ .chroma .s2 { color: #00afaf } +/* LiteralStringEscape */ .chroma .se { color: #af0000 } +/* LiteralStringHeredoc */ .chroma .sh { color: #00afaf } +/* LiteralStringInterpol */ .chroma .si { color: #00afaf } +/* LiteralStringOther */ .chroma .sx { color: #00afaf } +/* LiteralStringRegex */ .chroma .sr { color: #af0000 } +/* LiteralStringSingle */ .chroma .s1 { color: #00afaf } +/* LiteralStringSymbol */ .chroma .ss { color: #00afaf } +/* LiteralNumber */ .chroma .m { color: #00afaf } +/* LiteralNumberBin */ .chroma .mb { color: #00afaf } +/* LiteralNumberFloat */ .chroma .mf { color: #00afaf } +/* LiteralNumberHex */ .chroma .mh { color: #00afaf } +/* LiteralNumberInteger */ .chroma .mi { color: #00afaf } +/* LiteralNumberIntegerLong */ .chroma .il { color: #00afaf } +/* LiteralNumberOct */ .chroma .mo { color: #00afaf } +/* OperatorWord */ .chroma .ow { color: #5f8700 } +/* Comment */ .chroma .c { color: #4e4e4e } +/* CommentHashbang */ .chroma .ch { color: #4e4e4e } +/* CommentMultiline */ .chroma .cm { color: #4e4e4e } +/* CommentSingle */ .chroma .c1 { color: #4e4e4e } +/* CommentSpecial */ .chroma .cs { color: #5f8700 } +/* CommentPreproc */ .chroma .cp { color: #5f8700 } +/* CommentPreprocFile */ .chroma .cpf { color: #5f8700 } +/* GenericDeleted */ .chroma .gd { color: #af0000 } +/* GenericEmph */ .chroma .ge { font-style: italic } +/* GenericError */ .chroma .gr { color: #af0000; font-weight: bold } +/* GenericHeading */ .chroma .gh { color: #d75f00 } +/* GenericInserted */ .chroma .gi { color: #5f8700 } +/* GenericStrong */ .chroma .gs { font-weight: bold } +/* GenericSubheading */ .chroma .gu { color: #0087ff } diff --git a/assets/css/_pygments.css b/assets/css/_pygments.css deleted file mode 100644 index 2931fbd..0000000 --- a/assets/css/_pygments.css +++ /dev/null @@ -1,269 +0,0 @@ -pre { - line-height: 125%; -} -td.linenos .normal { - color: #37474f; - background-color: #263238; - padding-left: 5px; - padding-right: 5px; -} -span.linenos { - color: #37474f; - background-color: #263238; - padding-left: 5px; - padding-right: 5px; -} -td.linenos .special { - color: #607a86; - background-color: #263238; - padding-left: 5px; - padding-right: 5px; -} -span.linenos.special { - color: #607a86; - background-color: #263238; - padding-left: 5px; - padding-right: 5px; -} -pre.pygments .hll { - background-color: #2c3b41; -} -pre.pygments { - background: #263238; - color: #eeffff; -} -pre.pygments .c { - color: #546e7a; - font-style: italic; -} /* Comment */ -pre.pygments .err { - color: #ff5370; -} /* Error */ -pre.pygments .esc { - color: #89ddff; -} /* Escape */ -pre.pygments .g { - color: #eeffff; -} /* Generic */ -pre.pygments .k { - color: #bb80b3; -} /* Keyword */ -pre.pygments .l { - color: #c3e88d; -} /* Literal */ -pre.pygments .n { - color: #eeffff; -} /* Name */ -pre.pygments .o { - color: #89ddff; -} /* Operator */ -pre.pygments .p { - color: #89ddff; -} /* Punctuation */ -pre.pygments .ch { - color: #546e7a; - font-style: italic; -} /* Comment.Hashbang */ -pre.pygments .cm { - color: #546e7a; - font-style: italic; -} /* Comment.Multiline */ -pre.pygments .cp { - color: #546e7a; - font-style: italic; -} /* Comment.Preproc */ -pre.pygments .cpf { - color: #546e7a; - font-style: italic; -} /* Comment.PreprocFile */ -pre.pygments .c1 { - color: #546e7a; - font-style: italic; -} /* Comment.Single */ -pre.pygments .cs { - color: #546e7a; - font-style: italic; -} /* Comment.Special */ -pre.pygments .gd { - color: #ff5370; -} /* Generic.Deleted */ -pre.pygments .ge { - color: #89ddff; -} /* Generic.Emph */ -pre.pygments .gr { - color: #ff5370; -} /* Generic.Error */ -pre.pygments .gh { - color: #c3e88d; -} /* Generic.Heading */ -pre.pygments .gi { - color: #c3e88d; -} /* Generic.Inserted */ -pre.pygments .go { - color: #546e7a; -} /* Generic.Output */ -pre.pygments .gp { - color: #ffcb6b; -} /* Generic.Prompt */ -pre.pygments .gs { - color: #ff5370; -} /* Generic.Strong */ -pre.pygments .gu { - color: #89ddff; -} /* Generic.Subheading */ -pre.pygments .gt { - color: #ff5370; -} /* Generic.Traceback */ -pre.pygments .kc { - color: #89ddff; -} /* Keyword.Constant */ -pre.pygments .kd { - color: #bb80b3; -} /* Keyword.Declaration */ -pre.pygments .kn { - color: #89ddff; - font-style: italic; -} /* Keyword.Namespace */ -pre.pygments .kp { - color: #89ddff; -} /* Keyword.Pseudo */ -pre.pygments .kr { - color: #bb80b3; -} /* Keyword.Reserved */ -pre.pygments .kt { - color: #bb80b3; -} /* Keyword.Type */ -pre.pygments .ld { - color: #c3e88d; -} /* Literal.Date */ -pre.pygments .m { - color: #f78c6c; -} /* Literal.Number */ -pre.pygments .s { - color: #c3e88d; -} /* Literal.String */ -pre.pygments .na { - color: #bb80b3; -} /* Name.Attribute */ -pre.pygments .nb { - color: #82aaff; -} /* Name.Builtin */ -pre.pygments .nc { - color: #ffcb6b; -} /* Name.Class */ -pre.pygments .no { - color: #eeffff; -} /* Name.Constant */ -pre.pygments .nd { - color: #82aaff; -} /* Name.Decorator */ -pre.pygments .ni { - color: #89ddff; -} /* Name.Entity */ -pre.pygments .ne { - color: #ffcb6b; -} /* Name.Exception */ -pre.pygments .nf { - color: #82aaff; -} /* Name.Function */ -pre.pygments .nl { - color: #82aaff; -} /* Name.Label */ -pre.pygments .nn { - color: #ffcb6b; -} /* Name.Namespace */ -pre.pygments .nx { - color: #eeffff; -} /* Name.Other */ -pre.pygments .py { - color: #ffcb6b; -} /* Name.Property */ -pre.pygments .nt { - color: #ff5370; -} /* Name.Tag */ -pre.pygments .nv { - color: #89ddff; -} /* Name.Variable */ -pre.pygments .ow { - color: #89ddff; - font-style: italic; -} /* Operator.Word */ -pre.pygments .w { - color: #eeffff; -} /* Text.Whitespace */ -pre.pygments .mb { - color: #f78c6c; -} /* Literal.Number.Bin */ -pre.pygments .mf { - color: #f78c6c; -} /* Literal.Number.Float */ -pre.pygments .mh { - color: #f78c6c; -} /* Literal.Number.Hex */ -pre.pygments .mi { - color: #f78c6c; -} /* Literal.Number.Integer */ -pre.pygments .mo { - color: #f78c6c; -} /* Literal.Number.Oct */ -pre.pygments .sa { - color: #bb80b3; -} /* Literal.String.Affix */ -pre.pygments .sb { - color: #c3e88d; -} /* Literal.String.Backtick */ -pre.pygments .sc { - color: #c3e88d; -} /* Literal.String.Char */ -pre.pygments .dl { - color: #eeffff; -} /* Literal.String.Delimiter */ -pre.pygments .sd { - color: #546e7a; - font-style: italic; -} /* Literal.String.Doc */ -pre.pygments .s2 { - color: #c3e88d; -} /* Literal.String.Double */ -pre.pygments .se { - color: #eeffff; -} /* Literal.String.Escape */ -pre.pygments .sh { - color: #c3e88d; -} /* Literal.String.Heredoc */ -pre.pygments .si { - color: #89ddff; -} /* Literal.String.Interpol */ -pre.pygments .sx { - color: #c3e88d; -} /* Literal.String.Other */ -pre.pygments .sr { - color: #89ddff; -} /* Literal.String.Regex */ -pre.pygments .s1 { - color: #c3e88d; -} /* Literal.String.Single */ -pre.pygments .ss { - color: #89ddff; -} /* Literal.String.Symbol */ -pre.pygments .bp { - color: #89ddff; -} /* Name.Builtin.Pseudo */ -pre.pygments .fm { - color: #82aaff; -} /* Name.Function.Magic */ -pre.pygments .vc { - color: #89ddff; -} /* Name.Variable.Class */ -pre.pygments .vg { - color: #89ddff; -} /* Name.Variable.Global */ -pre.pygments .vi { - color: #89ddff; -} /* Name.Variable.Instance */ -pre.pygments .vm { - color: #82aaff; -} /* Name.Variable.Magic */ -pre.pygments .il { - color: #f78c6c; -} /* Literal.Number.Integer.Long */ diff --git a/assets/css/app.scss b/assets/css/app.scss index a6128d7..e10a266 100644 --- a/assets/css/app.scss +++ b/assets/css/app.scss @@ -16,24 +16,21 @@ /* Navbar custom styling */ @import "nav-bar-help"; -/* Pygments syntax highlighting styles */ -@import "pygments"; +/* Chroma syntax highlighting styles */ +@import "chroma"; /* code highlighting */ -pre.pygments { - line-height: 125%; - background-color: #272822 !important; - overflow: wrap !important; - padding: 0.75rem; - border-radius: .25em; +pre.chroma { + line-height: 1.5; + padding: 0.75rem 1rem; + border-radius: .5em; code { font-family: $font-family-code; - color: #eeffff; } } code.inline { - background-color: #272822; - color: #eeffff; + background-color: #1c1c1c; + color: #8a8a8a; padding: .2em .5em; border-radius: .25em; display: inline; diff --git a/assets/js/app.js b/assets/js/app.js index 925e425..3a2ff03 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -43,9 +43,6 @@ import { Socket } from "phoenix"; import topbar from "topbar"; import { LiveSocket } from "phoenix_live_view"; -// // Prismjs import -// import Prism from "prismjs" - // // Bootstrap v5 js imports // import "bootstrap/js/dist/alert"; import "bootstrap/js/dist/collapse"; diff --git a/assets/webpack.config.js b/assets/webpack.config.js index 1c82cd8..64b0643 100644 --- a/assets/webpack.config.js +++ b/assets/webpack.config.js @@ -93,7 +93,7 @@ module.exports = (env, options) => { "../**/live/**/*.ex", "./js/**/*.js", ]), - safelist: [/phx/, /topbar/, /linenos/, /pygments/], + safelist: [/phx/, /topbar/, /chroma/], }), ] ), diff --git a/config/config.exs b/config/config.exs index 43a2dfd..b6d32cc 100644 --- a/config/config.exs +++ b/config/config.exs @@ -14,7 +14,7 @@ config :elixir, :time_zone_database, Tzdata.TimeZoneDatabase config :home73k, :app_global_vars, time_zone: "America/New_York", blog_content: "priv/content", - pygmentize_bin: "priv/pygments/bin/pygmentize" + chroma_bin: "priv/chroma/chroma" # Configures the endpoint config :home73k, Home73kWeb.Endpoint, diff --git a/lib/home73k.ex b/lib/home73k.ex index b7c5af1..769dcd5 100644 --- a/lib/home73k.ex +++ b/lib/home73k.ex @@ -7,10 +7,14 @@ defmodule Home73k do if it comes from the database, an external API or others. """ - @app_vars Application.compile_env(:home73k, :app_global_vars, time_zone: "America/New_York") + @app_vars Application.compile_env(:home73k, :app_global_vars, [ + time_zone: "America/New_York", + blog_content: "priv/content", + chroma_bin: "priv/chroma/chroma" + ]) def app_vars, do: @app_vars def app_time_zone, do: @app_vars[:time_zone] def app_blog_content, do: @app_vars[:blog_content] - def app_pygmentize_bin, do: @app_vars[:pygmentize_bin] + def app_chroma_bin, do: @app_vars[:chroma_bin] end diff --git a/lib/home73k/highlighter.ex b/lib/home73k/highlighter.ex index b76ff18..94ab1ba 100644 --- a/lib/home73k/highlighter.ex +++ b/lib/home73k/highlighter.ex @@ -5,7 +5,8 @@ defmodule Home73k.Highlighter do alias Home73k.Temp - @pygments_cmd Home73k.app_pygmentize_bin() |> Path.expand() + @chroma_bin Home73k.app_chroma_bin() |> Path.expand() + @style "solarized-dark256" @doc """ Highlights all code block in an already generated HTML document. @@ -23,15 +24,12 @@ defmodule Home73k.Highlighter do tmp_file = Temp.file() File.write!(tmp_file, unescaped_code) - # pygmentize the code via temp file - pyg_args = ["-l", lang, "-f", "html", "-O", "cssclass=pygments", tmp_file] - {highlighted, _} = System.cmd(@pygments_cmd, pyg_args) + # use chroma to highlight the code via temp file + bin_args = ["-l", lang, "-f", "html", "-s", @style, "--html-only", "--html-prevent-surrounding-pre", tmp_file] + {highlighted, _} = System.cmd(@chroma_bin, bin_args) - # correct pygment wrapping markup - highlighted - |> String.replace("", "") - |> String.replace("
", "
")
-    |> String.replace("
", "") + # return properly wrapped highlighted code + ~s(
#{highlighted}
) end entities = [{"&", ?&}, {"<", ?<}, {">", ?>}, {""", ?"}, {"'", ?'}]