diff --git a/Cargo.lock b/Cargo.lock index 5a650eb..c519ade 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aho-corasick" version = "1.1.4" @@ -233,6 +239,30 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "2.11.1" @@ -572,6 +602,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -1482,12 +1521,33 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fancy-regex" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2276,6 +2336,12 @@ dependencies = [ "libc", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -2484,6 +2550,16 @@ dependencies = [ "unicase", ] +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "mio" version = "1.2.0" @@ -2780,6 +2856,19 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "plist" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092791278e026273c1b65bbdcfbba3a300f2994c896bd01ab01da613c29c46f1" +dependencies = [ + "base64", + "indexmap", + "quick-xml", + "serde", + "time", +] + [[package]] name = "postgres-protocol" version = "0.6.11" @@ -2915,6 +3004,15 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" +[[package]] +name = "quick-xml" +version = "0.39.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +dependencies = [ + "memchr", +] + [[package]] name = "quinn" version = "0.11.9" @@ -3437,6 +3535,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + [[package]] name = "siphasher" version = "1.0.3" @@ -3617,6 +3721,27 @@ dependencies = [ "syn", ] +[[package]] +name = "syntect" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925" +dependencies = [ + "bincode", + "fancy-regex", + "flate2", + "fnv", + "once_cell", + "plist", + "regex-syntax", + "serde", + "serde_derive", + "serde_json", + "thiserror 2.0.18", + "walkdir", + "yaml-rust", +] + [[package]] name = "system-configuration" version = "0.7.0" @@ -4868,6 +4993,15 @@ version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yggdrasil" version = "0.1.0" @@ -4885,6 +5019,7 @@ dependencies = [ "rand 0.8.6", "regex", "serde", + "syntect", "tokio", "tokio-postgres", "tower-http", diff --git a/Cargo.toml b/Cargo.toml index 062ff7d..ee6b615 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ rand = { version = "0.8", features = ["getrandom"] } getrandom = { version = "0.2", features = ["js"] } http = "1" ammonia = { version = "4", optional = true } +syntect = { version = "5", default-features = false, features = ["default-syntaxes", "default-themes", "default-fancy", "html", "parsing", "dump-load"], optional = true } [target.'cfg(target_arch = "wasm32")'.dependencies] web-sys = { version = "0.3", features = ["Document", "Window", "HtmlDocument", "Storage", "Element", "DomTokenList", "MediaQueryList", "HtmlScriptElement"] } @@ -50,4 +51,5 @@ server = [ "dep:tracing-subscriber", "dep:tower-http", "dep:ammonia", + "dep:syntect", ] diff --git a/Makefile b/Makefile index 087d477..711ca51 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,14 @@ -.PHONY: dev build css css-watch clean build-editor +.PHONY: dev build css css-watch clean build-editor highlight-css build: @$(MAKE) build-editor + @$(MAKE) highlight-css @tailwindcss -i input.css -o public/style.css --minify @dx build --release +highlight-css: + @cargo run --bin generate_highlight_css + build-editor: @echo "Building Tiptap editor..." @cd libs/tiptap-editor && npm install && npx vite build diff --git a/generated/highlight.css b/generated/highlight.css new file mode 100644 index 0000000..db1de50 --- /dev/null +++ b/generated/highlight.css @@ -0,0 +1,1895 @@ +/* Auto-generated by generate_highlight_css — DO NOT EDIT */ + +/* Catppuccin Latte (light) */ +.md-content pre code { +color: #4c4f69; + background-color: #eff1f5; +} + +.md-content pre code .text, +.md-content pre code .source, +.md-content pre code .variable.other.readwrite, +.md-content pre code .punctuation.definition.variable { +color: #4c4f69; +} + +.md-content pre code .punctuation { +color: #7c7f93; +} + +.md-content pre code .comment, +.md-content pre code .punctuation.definition.comment { +color: #7c7f93; +font-style: italic; +} + +.md-content pre code .string, +.md-content pre code .punctuation.definition.string { +color: #40a02b; +} + +.md-content pre code .constant.character.escape { +color: #ea76cb; +} + +.md-content pre code .constant.numeric, +.md-content pre code .variable.other.constant, +.md-content pre code .entity.name.constant, +.md-content pre code .constant.language.boolean, +.md-content pre code .constant.language.false, +.md-content pre code .constant.language.true, +.md-content pre code .keyword.other.unit.user-defined, +.md-content pre code .keyword.other.unit.suffix.floating-point { +color: #fe640b; +} + +.md-content pre code .keyword, +.md-content pre code .keyword.operator.word, +.md-content pre code .keyword.operator.new, +.md-content pre code .variable.language.super, +.md-content pre code .support.type.primitive, +.md-content pre code .storage.type, +.md-content pre code .storage.modifier, +.md-content pre code .punctuation.definition.keyword { +color: #8839ef; +} + +.md-content pre code .entity.name.tag.documentation { +color: #8839ef; +} + +.md-content pre code .keyword.operator, +.md-content pre code .punctuation.accessor, +.md-content pre code .punctuation.definition.generic, +.md-content pre code .meta.function.closure .punctuation.section.parameters, +.md-content pre code .punctuation.definition.tag, +.md-content pre code .punctuation.separator.key-value { +color: #179299; +} + +.md-content pre code .entity.name.function, +.md-content pre code .meta.function-call.method, +.md-content pre code .support.function, +.md-content pre code .support.function.misc, +.md-content pre code .variable.function { +color: #1e66f5; +font-style: italic; +} + +.md-content pre code .entity.name.class, +.md-content pre code .entity.other.inherited-class, +.md-content pre code .support.class, +.md-content pre code .meta.function-call.constructor, +.md-content pre code .entity.name.struct { +color: #df8e1d; +font-style: italic; +} + +.md-content pre code .entity.name.enum { +color: #df8e1d; +font-style: italic; +} + +.md-content pre code .meta.enum .variable.other.readwrite, +.md-content pre code .variable.other.enummember { +color: #179299; +} + +.md-content pre code .meta.property.object { +color: #179299; +} + +.md-content pre code .meta.type, +.md-content pre code .meta.type-alias, +.md-content pre code .support.type, +.md-content pre code .entity.name.type { +color: #df8e1d; +font-style: italic; +} + +.md-content pre code .meta.annotation .variable.function, +.md-content pre code .meta.annotation .variable.annotation.function, +.md-content pre code .meta.annotation .punctuation.definition.annotation, +.md-content pre code .meta.decorator, +.md-content pre code .punctuation.decorator { +color: #fe640b; +} + +.md-content pre code .variable.parameter, +.md-content pre code .meta.function.parameters { +color: #e64553; +font-style: italic; +} + +.md-content pre code .constant.language, +.md-content pre code .support.function.builtin { +color: #d20f39; +} + +.md-content pre code .entity.other.attribute-name.documentation { +color: #d20f39; +} + +.md-content pre code .keyword.control.directive, +.md-content pre code .punctuation.definition.directive { +color: #df8e1d; +} + +.md-content pre code .punctuation.definition.typeparameters { +color: #04a5e5; +} + +.md-content pre code .entity.name.namespace { +color: #df8e1d; +} + +.md-content pre code .support.type.property-name.css { +color: #1e66f5; +} + +.md-content pre code .variable.language.this, +.md-content pre code .variable.language.this .punctuation.definition.variable { +color: #d20f39; +} + +.md-content pre code .variable.object.property { +color: #4c4f69; +} + +.md-content pre code .string.template .variable, +.md-content pre code .string .variable { +color: #4c4f69; +} + +.md-content pre code .keyword.operator.new { +font-weight: bold; +} + +.md-content pre code .storage.modifier.specifier.extern.cpp { +color: #8839ef; +} + +.md-content pre code .entity.name.scope-resolution.template.call.cpp, +.md-content pre code .entity.name.scope-resolution.parameter.cpp, +.md-content pre code .entity.name.scope-resolution.cpp, +.md-content pre code .entity.name.scope-resolution.function.definition.cpp { +color: #df8e1d; +} + +.md-content pre code .storage.modifier.reference.cpp { +color: #179299; +} + +.md-content pre code .meta.interpolation.cs { +color: #4c4f69; +} + +.md-content pre code .comment.block.documentation.cs { +color: #4c4f69; +} + +.md-content pre code .source.css .entity.other.attribute-name.class.css, +.md-content pre code .entity.other.attribute-name.parent-selector.css .punctuation.definition.entity.css { +color: #df8e1d; +} + +.md-content pre code .punctuation.separator.operator.css { +color: #179299; +} + +.md-content pre code .source.css .entity.other.attribute-name.pseudo-class { +color: #179299; +} + +.md-content pre code .source.css .constant.other.unicode-range { +color: #fe640b; +} + +.md-content pre code .source.css .variable.parameter.url { +color: #40a02b; +} + +.md-content pre code .support.type.vendored.property-name { +color: #04a5e5; +} + +.md-content pre code .source.css .meta.property-value .variable, +.md-content pre code .source.css .meta.property-value .variable.other.less, +.md-content pre code .source.css .meta.property-value .variable.other.less .punctuation.definition.variable.less, +.md-content pre code .meta.definition.variable.scss { +color: #e64553; +} + +.md-content pre code .source.css .meta.property-list .variable, +.md-content pre code .meta.property-list .variable.other.less, +.md-content pre code .meta.property-list .variable.other.less .punctuation.definition.variable.less { +color: #1e66f5; +} + +.md-content pre code .keyword.other.unit.percentage.css { +color: #fe640b; +} + +.md-content pre code .source.css .meta.attribute-selector { +color: #40a02b; +} + +.md-content pre code .keyword.other.definition.ini, +.md-content pre code .punctuation.support.type.property-name.json, +.md-content pre code .support.type.property-name.json, +.md-content pre code .punctuation.support.type.property-name.toml, +.md-content pre code .support.type.property-name.toml, +.md-content pre code .entity.name.tag.yaml, +.md-content pre code .punctuation.support.type.property-name.yaml, +.md-content pre code .support.type.property-name.yaml { +color: #1e66f5; +} + +.md-content pre code .constant.language.json, +.md-content pre code .constant.language.yaml { +color: #fe640b; +} + +.md-content pre code .entity.name.type.anchor.yaml, +.md-content pre code .variable.other.alias.yaml { +color: #df8e1d; +} + +.md-content pre code .support.type.property-name.table, +.md-content pre code .entity.name.section.group-title.ini { +color: #df8e1d; +} + +.md-content pre code .constant.other.time.datetime.offset.toml { +color: #ea76cb; +} + +.md-content pre code .punctuation.definition.anchor.yaml, +.md-content pre code .punctuation.definition.alias.yaml { +color: #ea76cb; +} + +.md-content pre code .entity.other.document.begin.yaml { +color: #ea76cb; +} + +.md-content pre code .markup.changed.diff { +color: #fe640b; +} + +.md-content pre code .meta.diff.header.from-file, +.md-content pre code .meta.diff.header.to-file, +.md-content pre code .punctuation.definition.from-file.diff, +.md-content pre code .punctuation.definition.to-file.diff { +color: #1e66f5; +} + +.md-content pre code .markup.inserted.diff { +color: #40a02b; +} + +.md-content pre code .markup.deleted.diff { +color: #d20f39; +} + +.md-content pre code .variable.other.env { +color: #1e66f5; +} + +.md-content pre code .string.quoted .variable.other.env { +color: #4c4f69; +} + +.md-content pre code .support.function.builtin.gdscript { +color: #1e66f5; +} + +.md-content pre code .constant.language.gdscript { +color: #fe640b; +} + +.md-content pre code .comment .meta.annotation.go { +color: #e64553; +} + +.md-content pre code .comment .meta.annotation.parameters.go { +color: #fe640b; +} + +.md-content pre code .constant.language.go { +color: #fe640b; +} + +.md-content pre code .variable.graphql { +color: #4c4f69; +} + +.md-content pre code .string.unquoted.alias.graphql { +color: #dd7878; +} + +.md-content pre code .constant.character.enum.graphql { +color: #179299; +} + +.md-content pre code .meta.objectvalues.graphql .constant.object.key.graphql .string.unquoted.graphql { +color: #dd7878; +} + +.md-content pre code .keyword.other.doctype, +.md-content pre code .meta.tag.sgml.doctype .punctuation.definition.tag, +.md-content pre code .meta.tag.metadata.doctype .entity.name.tag, +.md-content pre code .meta.tag.metadata.doctype .punctuation.definition.tag { +color: #8839ef; +} + +.md-content pre code .entity.name.tag { +color: #1e66f5; +} + +.md-content pre code .text.html .constant.character.entity, +.md-content pre code .text.html .constant.character.entity .punctuation, +.md-content pre code .constant.character.entity.xml, +.md-content pre code .constant.character.entity.xml .punctuation, +.md-content pre code .constant.character.entity.js.jsx, +.md-content pre code .constant.charactger.entity.js.jsx .punctuation, +.md-content pre code .constant.character.entity.tsx, +.md-content pre code .constant.character.entity.tsx .punctuation { +color: #d20f39; +} + +.md-content pre code .entity.other.attribute-name { +color: #df8e1d; +} + +.md-content pre code .support.class.component, +.md-content pre code .support.class.component.jsx, +.md-content pre code .support.class.component.tsx, +.md-content pre code .support.class.component.vue { +color: #ea76cb; +} + +.md-content pre code .punctuation.definition.annotation, +.md-content pre code .storage.type.annotation { +color: #fe640b; +} + +.md-content pre code .constant.other.enum.java { +color: #179299; +} + +.md-content pre code .storage.modifier.import.java { +color: #4c4f69; +} + +.md-content pre code .meta.export .variable.other.readwrite.js { +color: #e64553; +} + +.md-content pre code .variable.other.constant.js, +.md-content pre code .variable.other.constant.ts, +.md-content pre code .variable.other.property.js, +.md-content pre code .variable.other.property.ts { +color: #4c4f69; +} + +.md-content pre code .variable.other.jsdoc, +.md-content pre code .comment.block.documentation .variable.other { +color: #e64553; +} + +.md-content pre code .support.type.object.console.js { +color: #4c4f69; +} + +.md-content pre code .support.constant.node, +.md-content pre code .support.type.object.module.js { +color: #8839ef; +} + +.md-content pre code .storage.modifier.implements { +color: #8839ef; +} + +.md-content pre code .constant.language.null.js, +.md-content pre code .constant.language.null.ts, +.md-content pre code .constant.language.undefined.js, +.md-content pre code .constant.language.undefined.ts, +.md-content pre code .support.type.builtin.ts { +color: #8839ef; +} + +.md-content pre code .variable.parameter.generic { +color: #df8e1d; +} + +.md-content pre code .keyword.declaration.function.arrow.js, +.md-content pre code .storage.type.function.arrow.ts { +color: #179299; +} + +.md-content pre code .punctuation.decorator.ts { +color: #1e66f5; +font-style: italic; +} + +.md-content pre code .keyword.operator.expression.in.js, +.md-content pre code .keyword.operator.expression.in.ts, +.md-content pre code .keyword.operator.expression.infer.ts, +.md-content pre code .keyword.operator.expression.instanceof.js, +.md-content pre code .keyword.operator.expression.instanceof.ts, +.md-content pre code .keyword.operator.expression.is, +.md-content pre code .keyword.operator.expression.keyof.ts, +.md-content pre code .keyword.operator.expression.of.js, +.md-content pre code .keyword.operator.expression.of.ts, +.md-content pre code .keyword.operator.expression.typeof.ts { +color: #8839ef; +} + +.md-content pre code .support.function.macro.julia { +color: #179299; +font-style: italic; +} + +.md-content pre code .constant.language.julia { +color: #fe640b; +} + +.md-content pre code .constant.other.symbol.julia { +color: #e64553; +} + +.md-content pre code .text.tex .keyword.control.preamble { +color: #179299; +} + +.md-content pre code .text.tex .support.function.be { +color: #04a5e5; +} + +.md-content pre code .constant.other.general.math.tex { +color: #dd7878; +} + +.md-content pre code .variable.language.liquid { +color: #ea76cb; +} + +.md-content pre code .comment.line.double-dash.documentation.lua .storage.type.annotation.lua { +color: #8839ef; +} + +.md-content pre code .comment.line.double-dash.documentation.lua .entity.name.variable.lua, +.md-content pre code .comment.line.double-dash.documentation.lua .variable.lua { +color: #4c4f69; +} + +.md-content pre code .heading.\31 .markdown .punctuation.definition.heading.markdown, +.md-content pre code .heading.\31 .markdown, +.md-content pre code .heading.\31 .quarto .punctuation.definition.heading.quarto, +.md-content pre code .heading.\31 .quarto, +.md-content pre code .markup.heading.atx.\31 .mdx, +.md-content pre code .markup.heading.atx.\31 .mdx .punctuation.definition.heading.mdx, +.md-content pre code .markup.heading.setext.\31 .markdown, +.md-content pre code .markup.heading.heading-0.asciidoc { +color: #d20f39; +} + +.md-content pre code .heading.\32 .markdown .punctuation.definition.heading.markdown, +.md-content pre code .heading.\32 .markdown, +.md-content pre code .heading.\32 .quarto .punctuation.definition.heading.quarto, +.md-content pre code .heading.\32 .quarto, +.md-content pre code .markup.heading.atx.\32 .mdx, +.md-content pre code .markup.heading.atx.\32 .mdx .punctuation.definition.heading.mdx, +.md-content pre code .markup.heading.setext.\32 .markdown, +.md-content pre code .markup.heading.heading-1.asciidoc { +color: #fe640b; +} + +.md-content pre code .heading.\33 .markdown .punctuation.definition.heading.markdown, +.md-content pre code .heading.\33 .markdown, +.md-content pre code .heading.\33 .quarto .punctuation.definition.heading.quarto, +.md-content pre code .heading.\33 .quarto, +.md-content pre code .markup.heading.atx.\33 .mdx, +.md-content pre code .markup.heading.atx.\33 .mdx .punctuation.definition.heading.mdx, +.md-content pre code .markup.heading.heading-2.asciidoc { +color: #df8e1d; +} + +.md-content pre code .heading.\34 .markdown .punctuation.definition.heading.markdown, +.md-content pre code .heading.\34 .markdown, +.md-content pre code .heading.\34 .quarto .punctuation.definition.heading.quarto, +.md-content pre code .heading.\34 .quarto, +.md-content pre code .markup.heading.atx.\34 .mdx, +.md-content pre code .markup.heading.atx.\34 .mdx .punctuation.definition.heading.mdx, +.md-content pre code .markup.heading.heading-3.asciidoc { +color: #40a02b; +} + +.md-content pre code .heading.\35 .markdown .punctuation.definition.heading.markdown, +.md-content pre code .heading.\35 .markdown, +.md-content pre code .heading.\35 .quarto .punctuation.definition.heading.quarto, +.md-content pre code .heading.\35 .quarto, +.md-content pre code .markup.heading.atx.\35 .mdx, +.md-content pre code .markup.heading.atx.\35 .mdx .punctuation.definition.heading.mdx, +.md-content pre code .markup.heading.heading-4.asciidoc { +color: #209fb5; +} + +.md-content pre code .heading.\36 .markdown .punctuation.definition.heading.markdown, +.md-content pre code .heading.\36 .markdown, +.md-content pre code .heading.\36 .quarto .punctuation.definition.heading.quarto, +.md-content pre code .heading.\36 .quarto, +.md-content pre code .markup.heading.atx.\36 .mdx, +.md-content pre code .markup.heading.atx.\36 .mdx .punctuation.definition.heading.mdx, +.md-content pre code .markup.heading.heading-5.asciidoc { +color: #7287fd; +} + +.md-content pre code .markup.bold { +color: #d20f39; +font-weight: bold; +} + +.md-content pre code .markup.italic { +color: #d20f39; +font-style: italic; +} + +.md-content pre code .punctuation.definition.link, +.md-content pre code .markup.underline.link { +color: #1e66f5; +} + +.md-content pre code .text.html.markdown .punctuation.definition.link.title, +.md-content pre code .text.html.quarto .punctuation.definition.link.title, +.md-content pre code .string.other.link.title.markdown, +.md-content pre code .string.other.link.title.quarto, +.md-content pre code .markup.link, +.md-content pre code .punctuation.definition.constant.markdown, +.md-content pre code .punctuation.definition.constant.quarto, +.md-content pre code .constant.other.reference.link.markdown, +.md-content pre code .constant.other.reference.link.quarto, +.md-content pre code .markup.substitution.attribute-reference { +color: #7287fd; +} + +.md-content pre code .punctuation.definition.raw.markdown, +.md-content pre code .punctuation.definition.raw.quarto, +.md-content pre code .markup.inline.raw.string.markdown, +.md-content pre code .markup.inline.raw.string.quarto, +.md-content pre code .markup.raw.block.markdown, +.md-content pre code .markup.raw.block.quarto { +color: #40a02b; +} + +.md-content pre code .fenced_code.block.language { +color: #04a5e5; +} + +.md-content pre code .markup.fenced_code.block .punctuation.definition, +.md-content pre code .markup.raw .support.asciidoc { +color: #7c7f93; +} + +.md-content pre code .markup.quote, +.md-content pre code .punctuation.definition.quote.begin { +color: #ea76cb; +} + +.md-content pre code .meta.separator.markdown { +color: #179299; +} + +.md-content pre code .punctuation.definition.list.begin.markdown, +.md-content pre code .punctuation.definition.list.begin.quarto, +.md-content pre code .markup.list.bullet { +color: #179299; +} + +.md-content pre code .markup.heading.quarto { +font-weight: bold; +} + +.md-content pre code .entity.other.attribute-name.multipart.nix, +.md-content pre code .entity.other.attribute-name.single.nix { +color: #1e66f5; +} + +.md-content pre code .variable.parameter.name.nix { +color: #4c4f69; +} + +.md-content pre code .meta.embedded .variable.parameter.name.nix { +color: #7287fd; +} + +.md-content pre code .string.unquoted.path.nix { +color: #ea76cb; +} + +.md-content pre code .support.attribute.builtin, +.md-content pre code .meta.attribute.php { +color: #df8e1d; +} + +.md-content pre code .meta.function.parameters.php .punctuation.definition.variable.php { +color: #e64553; +} + +.md-content pre code .constant.language.php { +color: #8839ef; +} + +.md-content pre code .text.html.php .support.function { +color: #04a5e5; +} + +.md-content pre code .support.variable.magic.python, +.md-content pre code .meta.function-call.arguments.python { +color: #4c4f69; +} + +.md-content pre code .support.function.magic.python { +color: #04a5e5; +font-style: italic; +} + +.md-content pre code .variable.parameter.function.language.special.self.python, +.md-content pre code .variable.language.special.self.python { +color: #d20f39; +font-style: italic; +} + +.md-content pre code .keyword.control.flow.python, +.md-content pre code .keyword.operator.logical.python { +color: #8839ef; +} + +.md-content pre code .storage.type.function.python { +color: #8839ef; +} + +.md-content pre code .support.token.decorator.python, +.md-content pre code .meta.function.decorator.identifier.python { +color: #04a5e5; +} + +.md-content pre code .meta.function-call.python { +color: #1e66f5; +} + +.md-content pre code .entity.name.function.decorator.python, +.md-content pre code .punctuation.definition.decorator.python { +color: #fe640b; +font-style: italic; +} + +.md-content pre code .constant.character.format.placeholder.other.python { +color: #ea76cb; +} + +.md-content pre code .support.type.exception.python, +.md-content pre code .support.function.builtin.python { +color: #fe640b; +} + +.md-content pre code .support.type.python { +color: #8839ef; +} + +.md-content pre code .constant.language.python { +color: #fe640b; +} + +.md-content pre code .meta.indexed-name.python, +.md-content pre code .meta.item-access.python { +color: #e64553; +font-style: italic; +} + +.md-content pre code .storage.type.string.python { +color: #40a02b; +font-style: italic; +} + +.md-content pre code .string.regexp .punctuation.definition.string.begin, +.md-content pre code .string.regexp .punctuation.definition.string.end { +color: #ea76cb; +} + +.md-content pre code .keyword.control.anchor.regexp { +color: #8839ef; +} + +.md-content pre code .string.regexp.ts { +color: #4c4f69; +} + +.md-content pre code .punctuation.definition.group.regexp, +.md-content pre code .keyword.other.back-reference.regexp { +color: #40a02b; +} + +.md-content pre code .punctuation.definition.character-class.regexp { +color: #df8e1d; +} + +.md-content pre code .constant.other.character-class.regexp { +color: #ea76cb; +} + +.md-content pre code .constant.other.character-class.range.regexp { +color: #dc8a78; +} + +.md-content pre code .keyword.operator.quantifier.regexp { +color: #179299; +} + +.md-content pre code .constant.character.numeric.regexp { +color: #fe640b; +} + +.md-content pre code .punctuation.definition.group.no-capture.regexp, +.md-content pre code .meta.assertion.look-ahead.regexp, +.md-content pre code .meta.assertion.negative-look-ahead.regexp { +color: #1e66f5; +} + +.md-content pre code .meta.annotation.rust, +.md-content pre code .meta.annotation.rust .punctuation, +.md-content pre code .meta.attribute.rust, +.md-content pre code .punctuation.definition.attribute.rust { +color: #df8e1d; +font-style: italic; +} + +.md-content pre code .entity.name.function.macro.rules.rust, +.md-content pre code .storage.type.module.rust, +.md-content pre code .storage.modifier.rust, +.md-content pre code .storage.type.struct.rust, +.md-content pre code .storage.type.enum.rust, +.md-content pre code .storage.type.trait.rust, +.md-content pre code .storage.type.union.rust, +.md-content pre code .storage.type.impl.rust, +.md-content pre code .storage.type.rust, +.md-content pre code .storage.type.function.rust, +.md-content pre code .storage.type.type.rust { +color: #8839ef; +} + +.md-content pre code .entity.name.type.numeric.rust { +color: #8839ef; +} + +.md-content pre code .meta.generic.rust { +color: #fe640b; +} + +.md-content pre code .entity.name.impl.rust { +color: #df8e1d; +font-style: italic; +} + +.md-content pre code .entity.name.module.rust { +color: #fe640b; +} + +.md-content pre code .entity.name.trait.rust { +color: #df8e1d; +font-style: italic; +} + +.md-content pre code .storage.type.source.rust { +color: #df8e1d; +} + +.md-content pre code .entity.name.union.rust { +color: #df8e1d; +} + +.md-content pre code .meta.enum.rust .storage.type.source.rust { +color: #179299; +} + +.md-content pre code .support.macro.rust, +.md-content pre code .meta.macro.rust .support.function.rust, +.md-content pre code .entity.name.function.macro.rust { +color: #1e66f5; +font-style: italic; +} + +.md-content pre code .storage.modifier.lifetime.rust, +.md-content pre code .entity.name.type.lifetime { +color: #1e66f5; +font-style: italic; +} + +.md-content pre code .string.quoted.double.rust .constant.other.placeholder.rust { +color: #ea76cb; +} + +.md-content pre code .meta.function.return-type.rust .meta.generic.rust .storage.type.rust { +color: #4c4f69; +} + +.md-content pre code .meta.function.call.rust { +color: #1e66f5; +} + +.md-content pre code .punctuation.brackets.angle.rust { +color: #04a5e5; +} + +.md-content pre code .constant.other.caps.rust { +color: #fe640b; +} + +.md-content pre code .meta.function.definition.rust .variable.other.rust { +color: #e64553; +} + +.md-content pre code .meta.function.call.rust .variable.other.rust { +color: #4c4f69; +} + +.md-content pre code .variable.language.self.rust { +color: #d20f39; +} + +.md-content pre code .variable.other.metavariable.name.rust, +.md-content pre code .meta.macro.metavariable.rust .keyword.operator.macro.dollar.rust { +color: #ea76cb; +} + +.md-content pre code .comment.line.shebang, +.md-content pre code .comment.line.shebang .punctuation.definition.comment, +.md-content pre code .comment.line.shebang, +.md-content pre code .punctuation.definition.comment.shebang.shell, +.md-content pre code .meta.shebang.shell { +color: #ea76cb; +font-style: italic; +} + +.md-content pre code .comment.line.shebang .constant.language { +color: #179299; +font-style: italic; +} + +.md-content pre code .meta.function-call.arguments.shell .punctuation.definition.variable.shell, +.md-content pre code .meta.function-call.arguments.shell .punctuation.section.interpolation, +.md-content pre code .meta.function-call.arguments.shell .punctuation.definition.variable.shell, +.md-content pre code .meta.function-call.arguments.shell .punctuation.section.interpolation { +color: #d20f39; +} + +.md-content pre code .meta.string .meta.interpolation.parameter.shell .variable.other.readwrite { +color: #fe640b; +font-style: italic; +} + +.md-content pre code .source.shell .punctuation.section.interpolation, +.md-content pre code .punctuation.definition.evaluation.backticks.shell { +color: #179299; +} + +.md-content pre code .entity.name.tag.heredoc.shell { +color: #8839ef; +} + +.md-content pre code .string.quoted.double.shell .variable.other.normal.shell { +color: #4c4f69; +} + +.md-content pre code .markup.heading.typst { +color: #d20f39; +} + +.md-content pre code .source.json .meta.mapping.key .string { +color: #1e66f5; +} + +.md-content pre code .source.json .meta.mapping.key .punctuation.definition.string.begin, +.md-content pre code .source.json .meta.mapping.key .punctuation.definition.string.end { +color: #7c7f93; +} + +.md-content pre code .markup.heading.synopsis.man, +.md-content pre code .markup.heading.title.man, +.md-content pre code .markup.heading.other.man, +.md-content pre code .markup.heading.env.man { +color: #8839ef; +} + +.md-content pre code .markup.heading.commands.man { +color: #1e66f5; +} + +.md-content pre code .markup.heading.env.man { +color: #ea76cb; +} + +.md-content pre code .entity.name { +color: #179299; +} + +.md-content pre code .markup.heading.\31 .markdown { +color: #d20f39; +} + +.md-content pre code .markup.heading.\32 .markdown { +color: #fe640b; +} + +.md-content pre code .markup.heading.markdown { +color: #df8e1d; +} + + +/* Catppuccin Mocha (dark) */ +.dark .md-content pre code { +color: #cdd6f4; + background-color: #1e1e2e; +} + +.dark .md-content pre code .text, +.dark .md-content pre code .source, +.dark .md-content pre code .variable.other.readwrite, +.dark .md-content pre code .punctuation.definition.variable { +color: #cdd6f4; +} + +.dark .md-content pre code .punctuation { +color: #9399b2; +} + +.dark .md-content pre code .comment, +.dark .md-content pre code .punctuation.definition.comment { +color: #9399b2; +font-style: italic; +} + +.dark .md-content pre code .string, +.dark .md-content pre code .punctuation.definition.string { +color: #a6e3a1; +} + +.dark .md-content pre code .constant.character.escape { +color: #f5c2e7; +} + +.dark .md-content pre code .constant.numeric, +.dark .md-content pre code .variable.other.constant, +.dark .md-content pre code .entity.name.constant, +.dark .md-content pre code .constant.language.boolean, +.dark .md-content pre code .constant.language.false, +.dark .md-content pre code .constant.language.true, +.dark .md-content pre code .keyword.other.unit.user-defined, +.dark .md-content pre code .keyword.other.unit.suffix.floating-point { +color: #fab387; +} + +.dark .md-content pre code .keyword, +.dark .md-content pre code .keyword.operator.word, +.dark .md-content pre code .keyword.operator.new, +.dark .md-content pre code .variable.language.super, +.dark .md-content pre code .support.type.primitive, +.dark .md-content pre code .storage.type, +.dark .md-content pre code .storage.modifier, +.dark .md-content pre code .punctuation.definition.keyword { +color: #cba6f7; +} + +.dark .md-content pre code .entity.name.tag.documentation { +color: #cba6f7; +} + +.dark .md-content pre code .keyword.operator, +.dark .md-content pre code .punctuation.accessor, +.dark .md-content pre code .punctuation.definition.generic, +.dark .md-content pre code .meta.function.closure .punctuation.section.parameters, +.dark .md-content pre code .punctuation.definition.tag, +.dark .md-content pre code .punctuation.separator.key-value { +color: #94e2d5; +} + +.dark .md-content pre code .entity.name.function, +.dark .md-content pre code .meta.function-call.method, +.dark .md-content pre code .support.function, +.dark .md-content pre code .support.function.misc, +.dark .md-content pre code .variable.function { +color: #89b4fa; +font-style: italic; +} + +.dark .md-content pre code .entity.name.class, +.dark .md-content pre code .entity.other.inherited-class, +.dark .md-content pre code .support.class, +.dark .md-content pre code .meta.function-call.constructor, +.dark .md-content pre code .entity.name.struct { +color: #f9e2af; +font-style: italic; +} + +.dark .md-content pre code .entity.name.enum { +color: #f9e2af; +font-style: italic; +} + +.dark .md-content pre code .meta.enum .variable.other.readwrite, +.dark .md-content pre code .variable.other.enummember { +color: #94e2d5; +} + +.dark .md-content pre code .meta.property.object { +color: #94e2d5; +} + +.dark .md-content pre code .meta.type, +.dark .md-content pre code .meta.type-alias, +.dark .md-content pre code .support.type, +.dark .md-content pre code .entity.name.type { +color: #f9e2af; +font-style: italic; +} + +.dark .md-content pre code .meta.annotation .variable.function, +.dark .md-content pre code .meta.annotation .variable.annotation.function, +.dark .md-content pre code .meta.annotation .punctuation.definition.annotation, +.dark .md-content pre code .meta.decorator, +.dark .md-content pre code .punctuation.decorator { +color: #fab387; +} + +.dark .md-content pre code .variable.parameter, +.dark .md-content pre code .meta.function.parameters { +color: #eba0ac; +font-style: italic; +} + +.dark .md-content pre code .constant.language, +.dark .md-content pre code .support.function.builtin { +color: #f38ba8; +} + +.dark .md-content pre code .entity.other.attribute-name.documentation { +color: #f38ba8; +} + +.dark .md-content pre code .keyword.control.directive, +.dark .md-content pre code .punctuation.definition.directive { +color: #f9e2af; +} + +.dark .md-content pre code .punctuation.definition.typeparameters { +color: #89dceb; +} + +.dark .md-content pre code .entity.name.namespace { +color: #f9e2af; +} + +.dark .md-content pre code .support.type.property-name.css { +color: #89b4fa; +} + +.dark .md-content pre code .variable.language.this, +.dark .md-content pre code .variable.language.this .punctuation.definition.variable { +color: #f38ba8; +} + +.dark .md-content pre code .variable.object.property { +color: #cdd6f4; +} + +.dark .md-content pre code .string.template .variable, +.dark .md-content pre code .string .variable { +color: #cdd6f4; +} + +.dark .md-content pre code .keyword.operator.new { +font-weight: bold; +} + +.dark .md-content pre code .storage.modifier.specifier.extern.cpp { +color: #cba6f7; +} + +.dark .md-content pre code .entity.name.scope-resolution.template.call.cpp, +.dark .md-content pre code .entity.name.scope-resolution.parameter.cpp, +.dark .md-content pre code .entity.name.scope-resolution.cpp, +.dark .md-content pre code .entity.name.scope-resolution.function.definition.cpp { +color: #f9e2af; +} + +.dark .md-content pre code .storage.modifier.reference.cpp { +color: #94e2d5; +} + +.dark .md-content pre code .meta.interpolation.cs { +color: #cdd6f4; +} + +.dark .md-content pre code .comment.block.documentation.cs { +color: #cdd6f4; +} + +.dark .md-content pre code .source.css .entity.other.attribute-name.class.css, +.dark .md-content pre code .entity.other.attribute-name.parent-selector.css .punctuation.definition.entity.css { +color: #f9e2af; +} + +.dark .md-content pre code .punctuation.separator.operator.css { +color: #94e2d5; +} + +.dark .md-content pre code .source.css .entity.other.attribute-name.pseudo-class { +color: #94e2d5; +} + +.dark .md-content pre code .source.css .constant.other.unicode-range { +color: #fab387; +} + +.dark .md-content pre code .source.css .variable.parameter.url { +color: #a6e3a1; +} + +.dark .md-content pre code .support.type.vendored.property-name { +color: #89dceb; +} + +.dark .md-content pre code .source.css .meta.property-value .variable, +.dark .md-content pre code .source.css .meta.property-value .variable.other.less, +.dark .md-content pre code .source.css .meta.property-value .variable.other.less .punctuation.definition.variable.less, +.dark .md-content pre code .meta.definition.variable.scss { +color: #eba0ac; +} + +.dark .md-content pre code .source.css .meta.property-list .variable, +.dark .md-content pre code .meta.property-list .variable.other.less, +.dark .md-content pre code .meta.property-list .variable.other.less .punctuation.definition.variable.less { +color: #89b4fa; +} + +.dark .md-content pre code .keyword.other.unit.percentage.css { +color: #fab387; +} + +.dark .md-content pre code .source.css .meta.attribute-selector { +color: #a6e3a1; +} + +.dark .md-content pre code .keyword.other.definition.ini, +.dark .md-content pre code .punctuation.support.type.property-name.json, +.dark .md-content pre code .support.type.property-name.json, +.dark .md-content pre code .punctuation.support.type.property-name.toml, +.dark .md-content pre code .support.type.property-name.toml, +.dark .md-content pre code .entity.name.tag.yaml, +.dark .md-content pre code .punctuation.support.type.property-name.yaml, +.dark .md-content pre code .support.type.property-name.yaml { +color: #89b4fa; +} + +.dark .md-content pre code .constant.language.json, +.dark .md-content pre code .constant.language.yaml { +color: #fab387; +} + +.dark .md-content pre code .entity.name.type.anchor.yaml, +.dark .md-content pre code .variable.other.alias.yaml { +color: #f9e2af; +} + +.dark .md-content pre code .support.type.property-name.table, +.dark .md-content pre code .entity.name.section.group-title.ini { +color: #f9e2af; +} + +.dark .md-content pre code .constant.other.time.datetime.offset.toml { +color: #f5c2e7; +} + +.dark .md-content pre code .punctuation.definition.anchor.yaml, +.dark .md-content pre code .punctuation.definition.alias.yaml { +color: #f5c2e7; +} + +.dark .md-content pre code .entity.other.document.begin.yaml { +color: #f5c2e7; +} + +.dark .md-content pre code .markup.changed.diff { +color: #fab387; +} + +.dark .md-content pre code .meta.diff.header.from-file, +.dark .md-content pre code .meta.diff.header.to-file, +.dark .md-content pre code .punctuation.definition.from-file.diff, +.dark .md-content pre code .punctuation.definition.to-file.diff { +color: #89b4fa; +} + +.dark .md-content pre code .markup.inserted.diff { +color: #a6e3a1; +} + +.dark .md-content pre code .markup.deleted.diff { +color: #f38ba8; +} + +.dark .md-content pre code .variable.other.env { +color: #89b4fa; +} + +.dark .md-content pre code .string.quoted .variable.other.env { +color: #cdd6f4; +} + +.dark .md-content pre code .support.function.builtin.gdscript { +color: #89b4fa; +} + +.dark .md-content pre code .constant.language.gdscript { +color: #fab387; +} + +.dark .md-content pre code .comment .meta.annotation.go { +color: #eba0ac; +} + +.dark .md-content pre code .comment .meta.annotation.parameters.go { +color: #fab387; +} + +.dark .md-content pre code .constant.language.go { +color: #fab387; +} + +.dark .md-content pre code .variable.graphql { +color: #cdd6f4; +} + +.dark .md-content pre code .string.unquoted.alias.graphql { +color: #f2cdcd; +} + +.dark .md-content pre code .constant.character.enum.graphql { +color: #94e2d5; +} + +.dark .md-content pre code .meta.objectvalues.graphql .constant.object.key.graphql .string.unquoted.graphql { +color: #f2cdcd; +} + +.dark .md-content pre code .keyword.other.doctype, +.dark .md-content pre code .meta.tag.sgml.doctype .punctuation.definition.tag, +.dark .md-content pre code .meta.tag.metadata.doctype .entity.name.tag, +.dark .md-content pre code .meta.tag.metadata.doctype .punctuation.definition.tag { +color: #cba6f7; +} + +.dark .md-content pre code .entity.name.tag { +color: #89b4fa; +} + +.dark .md-content pre code .text.html .constant.character.entity, +.dark .md-content pre code .text.html .constant.character.entity .punctuation, +.dark .md-content pre code .constant.character.entity.xml, +.dark .md-content pre code .constant.character.entity.xml .punctuation, +.dark .md-content pre code .constant.character.entity.js.jsx, +.dark .md-content pre code .constant.charactger.entity.js.jsx .punctuation, +.dark .md-content pre code .constant.character.entity.tsx, +.dark .md-content pre code .constant.character.entity.tsx .punctuation { +color: #f38ba8; +} + +.dark .md-content pre code .entity.other.attribute-name { +color: #f9e2af; +} + +.dark .md-content pre code .support.class.component, +.dark .md-content pre code .support.class.component.jsx, +.dark .md-content pre code .support.class.component.tsx, +.dark .md-content pre code .support.class.component.vue { +color: #f5c2e7; +} + +.dark .md-content pre code .punctuation.definition.annotation, +.dark .md-content pre code .storage.type.annotation { +color: #fab387; +} + +.dark .md-content pre code .constant.other.enum.java { +color: #94e2d5; +} + +.dark .md-content pre code .storage.modifier.import.java { +color: #cdd6f4; +} + +.dark .md-content pre code .meta.export .variable.other.readwrite.js { +color: #eba0ac; +} + +.dark .md-content pre code .variable.other.constant.js, +.dark .md-content pre code .variable.other.constant.ts, +.dark .md-content pre code .variable.other.property.js, +.dark .md-content pre code .variable.other.property.ts { +color: #cdd6f4; +} + +.dark .md-content pre code .variable.other.jsdoc, +.dark .md-content pre code .comment.block.documentation .variable.other { +color: #eba0ac; +} + +.dark .md-content pre code .support.type.object.console.js { +color: #cdd6f4; +} + +.dark .md-content pre code .support.constant.node, +.dark .md-content pre code .support.type.object.module.js { +color: #cba6f7; +} + +.dark .md-content pre code .storage.modifier.implements { +color: #cba6f7; +} + +.dark .md-content pre code .constant.language.null.js, +.dark .md-content pre code .constant.language.null.ts, +.dark .md-content pre code .constant.language.undefined.js, +.dark .md-content pre code .constant.language.undefined.ts, +.dark .md-content pre code .support.type.builtin.ts { +color: #cba6f7; +} + +.dark .md-content pre code .variable.parameter.generic { +color: #f9e2af; +} + +.dark .md-content pre code .keyword.declaration.function.arrow.js, +.dark .md-content pre code .storage.type.function.arrow.ts { +color: #94e2d5; +} + +.dark .md-content pre code .punctuation.decorator.ts { +color: #89b4fa; +font-style: italic; +} + +.dark .md-content pre code .keyword.operator.expression.in.js, +.dark .md-content pre code .keyword.operator.expression.in.ts, +.dark .md-content pre code .keyword.operator.expression.infer.ts, +.dark .md-content pre code .keyword.operator.expression.instanceof.js, +.dark .md-content pre code .keyword.operator.expression.instanceof.ts, +.dark .md-content pre code .keyword.operator.expression.is, +.dark .md-content pre code .keyword.operator.expression.keyof.ts, +.dark .md-content pre code .keyword.operator.expression.of.js, +.dark .md-content pre code .keyword.operator.expression.of.ts, +.dark .md-content pre code .keyword.operator.expression.typeof.ts { +color: #cba6f7; +} + +.dark .md-content pre code .support.function.macro.julia { +color: #94e2d5; +font-style: italic; +} + +.dark .md-content pre code .constant.language.julia { +color: #fab387; +} + +.dark .md-content pre code .constant.other.symbol.julia { +color: #eba0ac; +} + +.dark .md-content pre code .text.tex .keyword.control.preamble { +color: #94e2d5; +} + +.dark .md-content pre code .text.tex .support.function.be { +color: #89dceb; +} + +.dark .md-content pre code .constant.other.general.math.tex { +color: #f2cdcd; +} + +.dark .md-content pre code .variable.language.liquid { +color: #f5c2e7; +} + +.dark .md-content pre code .comment.line.double-dash.documentation.lua .storage.type.annotation.lua { +color: #cba6f7; +} + +.dark .md-content pre code .comment.line.double-dash.documentation.lua .entity.name.variable.lua, +.dark .md-content pre code .comment.line.double-dash.documentation.lua .variable.lua { +color: #cdd6f4; +} + +.dark .md-content pre code .heading.\31 .markdown .punctuation.definition.heading.markdown, +.dark .md-content pre code .heading.\31 .markdown, +.dark .md-content pre code .heading.\31 .quarto .punctuation.definition.heading.quarto, +.dark .md-content pre code .heading.\31 .quarto, +.dark .md-content pre code .markup.heading.atx.\31 .mdx, +.dark .md-content pre code .markup.heading.atx.\31 .mdx .punctuation.definition.heading.mdx, +.dark .md-content pre code .markup.heading.setext.\31 .markdown, +.dark .md-content pre code .markup.heading.heading-0.asciidoc { +color: #f38ba8; +} + +.dark .md-content pre code .heading.\32 .markdown .punctuation.definition.heading.markdown, +.dark .md-content pre code .heading.\32 .markdown, +.dark .md-content pre code .heading.\32 .quarto .punctuation.definition.heading.quarto, +.dark .md-content pre code .heading.\32 .quarto, +.dark .md-content pre code .markup.heading.atx.\32 .mdx, +.dark .md-content pre code .markup.heading.atx.\32 .mdx .punctuation.definition.heading.mdx, +.dark .md-content pre code .markup.heading.setext.\32 .markdown, +.dark .md-content pre code .markup.heading.heading-1.asciidoc { +color: #fab387; +} + +.dark .md-content pre code .heading.\33 .markdown .punctuation.definition.heading.markdown, +.dark .md-content pre code .heading.\33 .markdown, +.dark .md-content pre code .heading.\33 .quarto .punctuation.definition.heading.quarto, +.dark .md-content pre code .heading.\33 .quarto, +.dark .md-content pre code .markup.heading.atx.\33 .mdx, +.dark .md-content pre code .markup.heading.atx.\33 .mdx .punctuation.definition.heading.mdx, +.dark .md-content pre code .markup.heading.heading-2.asciidoc { +color: #f9e2af; +} + +.dark .md-content pre code .heading.\34 .markdown .punctuation.definition.heading.markdown, +.dark .md-content pre code .heading.\34 .markdown, +.dark .md-content pre code .heading.\34 .quarto .punctuation.definition.heading.quarto, +.dark .md-content pre code .heading.\34 .quarto, +.dark .md-content pre code .markup.heading.atx.\34 .mdx, +.dark .md-content pre code .markup.heading.atx.\34 .mdx .punctuation.definition.heading.mdx, +.dark .md-content pre code .markup.heading.heading-3.asciidoc { +color: #a6e3a1; +} + +.dark .md-content pre code .heading.\35 .markdown .punctuation.definition.heading.markdown, +.dark .md-content pre code .heading.\35 .markdown, +.dark .md-content pre code .heading.\35 .quarto .punctuation.definition.heading.quarto, +.dark .md-content pre code .heading.\35 .quarto, +.dark .md-content pre code .markup.heading.atx.\35 .mdx, +.dark .md-content pre code .markup.heading.atx.\35 .mdx .punctuation.definition.heading.mdx, +.dark .md-content pre code .markup.heading.heading-4.asciidoc { +color: #74c7ec; +} + +.dark .md-content pre code .heading.\36 .markdown .punctuation.definition.heading.markdown, +.dark .md-content pre code .heading.\36 .markdown, +.dark .md-content pre code .heading.\36 .quarto .punctuation.definition.heading.quarto, +.dark .md-content pre code .heading.\36 .quarto, +.dark .md-content pre code .markup.heading.atx.\36 .mdx, +.dark .md-content pre code .markup.heading.atx.\36 .mdx .punctuation.definition.heading.mdx, +.dark .md-content pre code .markup.heading.heading-5.asciidoc { +color: #b4befe; +} + +.dark .md-content pre code .markup.bold { +color: #f38ba8; +font-weight: bold; +} + +.dark .md-content pre code .markup.italic { +color: #f38ba8; +font-style: italic; +} + +.dark .md-content pre code .punctuation.definition.link, +.dark .md-content pre code .markup.underline.link { +color: #89b4fa; +} + +.dark .md-content pre code .text.html.markdown .punctuation.definition.link.title, +.dark .md-content pre code .text.html.quarto .punctuation.definition.link.title, +.dark .md-content pre code .string.other.link.title.markdown, +.dark .md-content pre code .string.other.link.title.quarto, +.dark .md-content pre code .markup.link, +.dark .md-content pre code .punctuation.definition.constant.markdown, +.dark .md-content pre code .punctuation.definition.constant.quarto, +.dark .md-content pre code .constant.other.reference.link.markdown, +.dark .md-content pre code .constant.other.reference.link.quarto, +.dark .md-content pre code .markup.substitution.attribute-reference { +color: #b4befe; +} + +.dark .md-content pre code .punctuation.definition.raw.markdown, +.dark .md-content pre code .punctuation.definition.raw.quarto, +.dark .md-content pre code .markup.inline.raw.string.markdown, +.dark .md-content pre code .markup.inline.raw.string.quarto, +.dark .md-content pre code .markup.raw.block.markdown, +.dark .md-content pre code .markup.raw.block.quarto { +color: #a6e3a1; +} + +.dark .md-content pre code .fenced_code.block.language { +color: #89dceb; +} + +.dark .md-content pre code .markup.fenced_code.block .punctuation.definition, +.dark .md-content pre code .markup.raw .support.asciidoc { +color: #9399b2; +} + +.dark .md-content pre code .markup.quote, +.dark .md-content pre code .punctuation.definition.quote.begin { +color: #f5c2e7; +} + +.dark .md-content pre code .meta.separator.markdown { +color: #94e2d5; +} + +.dark .md-content pre code .punctuation.definition.list.begin.markdown, +.dark .md-content pre code .punctuation.definition.list.begin.quarto, +.dark .md-content pre code .markup.list.bullet { +color: #94e2d5; +} + +.dark .md-content pre code .markup.heading.quarto { +font-weight: bold; +} + +.dark .md-content pre code .entity.other.attribute-name.multipart.nix, +.dark .md-content pre code .entity.other.attribute-name.single.nix { +color: #89b4fa; +} + +.dark .md-content pre code .variable.parameter.name.nix { +color: #cdd6f4; +} + +.dark .md-content pre code .meta.embedded .variable.parameter.name.nix { +color: #b4befe; +} + +.dark .md-content pre code .string.unquoted.path.nix { +color: #f5c2e7; +} + +.dark .md-content pre code .support.attribute.builtin, +.dark .md-content pre code .meta.attribute.php { +color: #f9e2af; +} + +.dark .md-content pre code .meta.function.parameters.php .punctuation.definition.variable.php { +color: #eba0ac; +} + +.dark .md-content pre code .constant.language.php { +color: #cba6f7; +} + +.dark .md-content pre code .text.html.php .support.function { +color: #89dceb; +} + +.dark .md-content pre code .support.variable.magic.python, +.dark .md-content pre code .meta.function-call.arguments.python { +color: #cdd6f4; +} + +.dark .md-content pre code .support.function.magic.python { +color: #89dceb; +font-style: italic; +} + +.dark .md-content pre code .variable.parameter.function.language.special.self.python, +.dark .md-content pre code .variable.language.special.self.python { +color: #f38ba8; +font-style: italic; +} + +.dark .md-content pre code .keyword.control.flow.python, +.dark .md-content pre code .keyword.operator.logical.python { +color: #cba6f7; +} + +.dark .md-content pre code .storage.type.function.python { +color: #cba6f7; +} + +.dark .md-content pre code .support.token.decorator.python, +.dark .md-content pre code .meta.function.decorator.identifier.python { +color: #89dceb; +} + +.dark .md-content pre code .meta.function-call.python { +color: #89b4fa; +} + +.dark .md-content pre code .entity.name.function.decorator.python, +.dark .md-content pre code .punctuation.definition.decorator.python { +color: #fab387; +font-style: italic; +} + +.dark .md-content pre code .constant.character.format.placeholder.other.python { +color: #f5c2e7; +} + +.dark .md-content pre code .support.type.exception.python, +.dark .md-content pre code .support.function.builtin.python { +color: #fab387; +} + +.dark .md-content pre code .support.type.python { +color: #cba6f7; +} + +.dark .md-content pre code .constant.language.python { +color: #fab387; +} + +.dark .md-content pre code .meta.indexed-name.python, +.dark .md-content pre code .meta.item-access.python { +color: #eba0ac; +font-style: italic; +} + +.dark .md-content pre code .storage.type.string.python { +color: #a6e3a1; +font-style: italic; +} + +.dark .md-content pre code .string.regexp .punctuation.definition.string.begin, +.dark .md-content pre code .string.regexp .punctuation.definition.string.end { +color: #f5c2e7; +} + +.dark .md-content pre code .keyword.control.anchor.regexp { +color: #cba6f7; +} + +.dark .md-content pre code .string.regexp.ts { +color: #cdd6f4; +} + +.dark .md-content pre code .punctuation.definition.group.regexp, +.dark .md-content pre code .keyword.other.back-reference.regexp { +color: #a6e3a1; +} + +.dark .md-content pre code .punctuation.definition.character-class.regexp { +color: #f9e2af; +} + +.dark .md-content pre code .constant.other.character-class.regexp { +color: #f5c2e7; +} + +.dark .md-content pre code .constant.other.character-class.range.regexp { +color: #f5e0dc; +} + +.dark .md-content pre code .keyword.operator.quantifier.regexp { +color: #94e2d5; +} + +.dark .md-content pre code .constant.character.numeric.regexp { +color: #fab387; +} + +.dark .md-content pre code .punctuation.definition.group.no-capture.regexp, +.dark .md-content pre code .meta.assertion.look-ahead.regexp, +.dark .md-content pre code .meta.assertion.negative-look-ahead.regexp { +color: #89b4fa; +} + +.dark .md-content pre code .meta.annotation.rust, +.dark .md-content pre code .meta.annotation.rust .punctuation, +.dark .md-content pre code .meta.attribute.rust, +.dark .md-content pre code .punctuation.definition.attribute.rust { +color: #f9e2af; +font-style: italic; +} + +.dark .md-content pre code .entity.name.function.macro.rules.rust, +.dark .md-content pre code .storage.type.module.rust, +.dark .md-content pre code .storage.modifier.rust, +.dark .md-content pre code .storage.type.struct.rust, +.dark .md-content pre code .storage.type.enum.rust, +.dark .md-content pre code .storage.type.trait.rust, +.dark .md-content pre code .storage.type.union.rust, +.dark .md-content pre code .storage.type.impl.rust, +.dark .md-content pre code .storage.type.rust, +.dark .md-content pre code .storage.type.function.rust, +.dark .md-content pre code .storage.type.type.rust { +color: #cba6f7; +} + +.dark .md-content pre code .entity.name.type.numeric.rust { +color: #cba6f7; +} + +.dark .md-content pre code .meta.generic.rust { +color: #fab387; +} + +.dark .md-content pre code .entity.name.impl.rust { +color: #f9e2af; +font-style: italic; +} + +.dark .md-content pre code .entity.name.module.rust { +color: #fab387; +} + +.dark .md-content pre code .entity.name.trait.rust { +color: #f9e2af; +font-style: italic; +} + +.dark .md-content pre code .storage.type.source.rust { +color: #f9e2af; +} + +.dark .md-content pre code .entity.name.union.rust { +color: #f9e2af; +} + +.dark .md-content pre code .meta.enum.rust .storage.type.source.rust { +color: #94e2d5; +} + +.dark .md-content pre code .support.macro.rust, +.dark .md-content pre code .meta.macro.rust .support.function.rust, +.dark .md-content pre code .entity.name.function.macro.rust { +color: #89b4fa; +font-style: italic; +} + +.dark .md-content pre code .storage.modifier.lifetime.rust, +.dark .md-content pre code .entity.name.type.lifetime { +color: #89b4fa; +font-style: italic; +} + +.dark .md-content pre code .string.quoted.double.rust .constant.other.placeholder.rust { +color: #f5c2e7; +} + +.dark .md-content pre code .meta.function.return-type.rust .meta.generic.rust .storage.type.rust { +color: #cdd6f4; +} + +.dark .md-content pre code .meta.function.call.rust { +color: #89b4fa; +} + +.dark .md-content pre code .punctuation.brackets.angle.rust { +color: #89dceb; +} + +.dark .md-content pre code .constant.other.caps.rust { +color: #fab387; +} + +.dark .md-content pre code .meta.function.definition.rust .variable.other.rust { +color: #eba0ac; +} + +.dark .md-content pre code .meta.function.call.rust .variable.other.rust { +color: #cdd6f4; +} + +.dark .md-content pre code .variable.language.self.rust { +color: #f38ba8; +} + +.dark .md-content pre code .variable.other.metavariable.name.rust, +.dark .md-content pre code .meta.macro.metavariable.rust .keyword.operator.macro.dollar.rust { +color: #f5c2e7; +} + +.dark .md-content pre code .comment.line.shebang, +.dark .md-content pre code .comment.line.shebang .punctuation.definition.comment, +.dark .md-content pre code .comment.line.shebang, +.dark .md-content pre code .punctuation.definition.comment.shebang.shell, +.dark .md-content pre code .meta.shebang.shell { +color: #f5c2e7; +font-style: italic; +} + +.dark .md-content pre code .comment.line.shebang .constant.language { +color: #94e2d5; +font-style: italic; +} + +.dark .md-content pre code .meta.function-call.arguments.shell .punctuation.definition.variable.shell, +.dark .md-content pre code .meta.function-call.arguments.shell .punctuation.section.interpolation, +.dark .md-content pre code .meta.function-call.arguments.shell .punctuation.definition.variable.shell, +.dark .md-content pre code .meta.function-call.arguments.shell .punctuation.section.interpolation { +color: #f38ba8; +} + +.dark .md-content pre code .meta.string .meta.interpolation.parameter.shell .variable.other.readwrite { +color: #fab387; +font-style: italic; +} + +.dark .md-content pre code .source.shell .punctuation.section.interpolation, +.dark .md-content pre code .punctuation.definition.evaluation.backticks.shell { +color: #94e2d5; +} + +.dark .md-content pre code .entity.name.tag.heredoc.shell { +color: #cba6f7; +} + +.dark .md-content pre code .string.quoted.double.shell .variable.other.normal.shell { +color: #cdd6f4; +} + +.dark .md-content pre code .markup.heading.typst { +color: #f38ba8; +} + +.dark .md-content pre code .source.json .meta.mapping.key .string { +color: #89b4fa; +} + +.dark .md-content pre code .source.json .meta.mapping.key .punctuation.definition.string.begin, +.dark .md-content pre code .source.json .meta.mapping.key .punctuation.definition.string.end { +color: #9399b2; +} + +.dark .md-content pre code .markup.heading.synopsis.man, +.dark .md-content pre code .markup.heading.title.man, +.dark .md-content pre code .markup.heading.other.man, +.dark .md-content pre code .markup.heading.env.man { +color: #cba6f7; +} + +.dark .md-content pre code .markup.heading.commands.man { +color: #89b4fa; +} + +.dark .md-content pre code .markup.heading.env.man { +color: #f5c2e7; +} + +.dark .md-content pre code .entity.name { +color: #94e2d5; +} + +.dark .md-content pre code .markup.heading.\31 .markdown { +color: #f38ba8; +} + +.dark .md-content pre code .markup.heading.\32 .markdown { +color: #fab387; +} + +.dark .md-content pre code .markup.heading.markdown { +color: #f9e2af; +} + diff --git a/input.css b/input.css index 2e25764..cd2f548 100644 --- a/input.css +++ b/input.css @@ -1,4 +1,5 @@ @import "tailwindcss"; +@import "./generated/highlight.css"; @custom-variant dark (&:where(.dark, .dark *)); @@ -342,7 +343,6 @@ .md-content pre { position: relative; margin-bottom: var(--content-gap-paper); - background: var(--color-paper-code-block); border-radius: var(--radius-paper); overflow-x: auto; } @@ -350,7 +350,6 @@ .md-content pre code { display: block; padding: 16px; - color: rgb(213, 213, 214); background: transparent; border-radius: 0; overflow-x: auto; diff --git a/src/api/posts.rs b/src/api/posts.rs index 725a178..a1abda0 100644 --- a/src/api/posts.rs +++ b/src/api/posts.rs @@ -172,10 +172,13 @@ async fn ensure_unique_slug( fn clean_html(input: &str) -> String { let mut builder = ammonia::Builder::default(); builder - .add_generic_attributes(&["class", "aria-hidden", "aria-label", "id", "role", "accesskey", "title"]) + .add_generic_attributes(&["class", "style", "aria-hidden", "aria-label", "id", "role", "accesskey", "title"]) .add_tags(&["details", "summary"]) .url_relative(ammonia::UrlRelative::PassThrough) .add_tag_attributes("a", &["class", "aria-hidden", "aria-label"]) + .add_tag_attributes("span", &["class", "style"]) + .add_tag_attributes("pre", &["class", "style"]) + .add_tag_attributes("code", &["class", "style"]) .add_tag_attributes("h1", &["id", "class"]) .add_tag_attributes("h2", &["id", "class"]) .add_tag_attributes("h3", &["id", "class"]) @@ -243,12 +246,14 @@ fn render_markdown_enhanced(md: &str) -> RenderedContent { let mut html = String::new(); let mut heading_idx = 0; let mut in_heading = false; + let mut in_codeblock = false; + let mut code_lang: Option = None; + let mut code_buffer = String::new(); let mut non_heading_events: Vec = Vec::new(); for event in parser { match event { Event::Start(Tag::Heading { level, .. }) => { - // Flush non-heading events first if !non_heading_events.is_empty() { pulldown_cmark::html::push_html(&mut html, non_heading_events.into_iter()); non_heading_events = Vec::new(); @@ -286,9 +291,39 @@ fn render_markdown_enhanced(md: &str) -> RenderedContent { } in_heading = false; } + Event::Start(Tag::CodeBlock(kind)) => { + if !non_heading_events.is_empty() { + pulldown_cmark::html::push_html(&mut html, non_heading_events.into_iter()); + non_heading_events = Vec::new(); + } + in_codeblock = true; + code_lang = match kind { + pulldown_cmark::CodeBlockKind::Fenced(lang) => { + if lang.is_empty() { + None + } else { + Some(lang.to_string()) + } + } + _ => None, + }; + code_buffer.clear(); + } + Event::Text(text) if in_codeblock => { + code_buffer.push_str(&text); + } + Event::End(TagEnd::CodeBlock) => { + let highlighted = + crate::highlight::server::highlight_code(&code_buffer, code_lang.as_deref()); + html.push_str("
");
+                html.push_str(&highlighted);
+                html.push_str("
"); + in_codeblock = false; + code_lang = None; + code_buffer.clear(); + } _ => { if in_heading { - // Manually render heading content match event { Event::Text(text) => html.push_str(&clean_html(&text)), Event::Code(code) => { @@ -298,7 +333,7 @@ fn render_markdown_enhanced(md: &str) -> RenderedContent { } _ => {} } - } else { + } else if !in_codeblock { non_heading_events.push(event); } } diff --git a/src/bin/generate_highlight_css.rs b/src/bin/generate_highlight_css.rs new file mode 100644 index 0000000..b954978 --- /dev/null +++ b/src/bin/generate_highlight_css.rs @@ -0,0 +1,104 @@ +use syntect::highlighting::ThemeSet; +use syntect::html::{css_for_theme_with_class_style, ClassStyle}; + +fn main() { + let latte = ThemeSet::get_theme("themes/Catppuccin Latte.tmTheme") + .expect("Failed to load Catppuccin Latte theme"); + let mocha = ThemeSet::get_theme("themes/Catppuccin Mocha.tmTheme") + .expect("Failed to load Catppuccin Mocha theme"); + + let latte_css = css_for_theme_with_class_style(&latte, ClassStyle::Spaced) + .expect("Failed to generate Latte CSS"); + let mocha_css = css_for_theme_with_class_style(&mocha, ClassStyle::Spaced) + .expect("Failed to generate Mocha CSS"); + + let latte_clean = strip_comments(&latte_css); + let mocha_clean = strip_comments(&mocha_css); + + let latte_rewritten = rewrite_rules(&latte_clean, ".md-content pre code", ""); + let mocha_rewritten = rewrite_rules(&mocha_clean, ".md-content pre code", ".dark "); + + let mut output = String::new(); + output.push_str("/* Auto-generated by generate_highlight_css — DO NOT EDIT */\n\n"); + output.push_str("/* Catppuccin Latte (light) */\n"); + output.push_str(&latte_rewritten); + output.push_str("\n/* Catppuccin Mocha (dark) */\n"); + output.push_str(&mocha_rewritten); + + std::fs::create_dir_all("generated").expect("Failed to create generated/"); + std::fs::write("generated/highlight.css", output) + .expect("Failed to write generated/highlight.css"); + + println!("Generated generated/highlight.css"); +} + +fn strip_comments(css: &str) -> String { + let mut result = String::with_capacity(css.len()); + let chars: Vec = css.chars().collect(); + let mut i = 0; + while i < chars.len() { + if i + 1 < chars.len() && chars[i] == '/' && chars[i + 1] == '*' { + while i + 1 < chars.len() && !(chars[i] == '*' && chars[i + 1] == '/') { + i += 1; + } + i += 2; + } else { + result.push(chars[i]); + i += 1; + } + } + result +} + +fn rewrite_rules(css: &str, base: &str, prefix: &str) -> String { + let mut out = String::new(); + let mut pos = 0; + let bytes = css.as_bytes(); + + while pos < bytes.len() { + let rest = &css[pos..]; + + let open = match rest.find('{') { + Some(i) => i, + None => break, + }; + + let selector = rest[..open].trim(); + if selector.is_empty() { + pos += open + 1; + continue; + } + + let after_open = pos + open + 1; + let mut depth = 1usize; + let mut close = after_open; + while close < bytes.len() && depth > 0 { + if bytes[close] == b'{' { + depth += 1; + } else if bytes[close] == b'}' { + depth -= 1; + } + close += 1; + } + + let body = css[after_open..close - 1].trim(); + pos = close; + + if body.is_empty() { + continue; + } + + if selector == ".code" { + out.push_str(&format!("{}{} {{\n{}\n}}\n\n", prefix, base, body)); + } else { + let rewritten = selector + .split(',') + .map(|s| format!("{}{} {}", prefix, base, s.trim())) + .collect::>() + .join(",\n"); + out.push_str(&format!("{} {{\n{}\n}}\n\n", rewritten, body)); + } + } + + out +} diff --git a/src/highlight.rs b/src/highlight.rs new file mode 100644 index 0000000..84de021 --- /dev/null +++ b/src/highlight.rs @@ -0,0 +1,68 @@ +#[cfg(feature = "server")] +pub mod server { + use std::sync::{LazyLock, OnceLock}; + + use syntect::highlighting::{Theme, ThemeSet}; + use syntect::html::{ClassedHTMLGenerator, ClassStyle}; + use syntect::parsing::{SyntaxReference, SyntaxSet}; + use syntect::util::LinesWithEndings; + + static SYNTAX_SET: LazyLock = + LazyLock::new(|| SyntaxSet::load_defaults_newlines()); + + static LATTE_THEME: LazyLock = LazyLock::new(|| { + ThemeSet::get_theme("themes/Catppuccin Latte.tmTheme") + .expect("Failed to load Catppuccin Latte theme") + }); + + static MOCHA_THEME: LazyLock = LazyLock::new(|| { + ThemeSet::get_theme("themes/Catppuccin Mocha.tmTheme") + .expect("Failed to load Catppuccin Mocha theme") + }); + + static FALLBACK_SYNTAX: OnceLock = OnceLock::new(); + + fn find_syntax(lang: Option<&str>) -> &'static SyntaxReference { + let ss = &*SYNTAX_SET; + if let Some(lang) = lang { + if !lang.is_empty() { + if let Some(s) = ss.find_syntax_by_extension(lang) { + return s; + } + if let Some(s) = ss.find_syntax_by_name(lang) { + return s; + } + } + } + let plain = ss + .find_syntax_by_extension("txt") + .or_else(|| ss.find_syntax_by_name("Plain Text")) + .expect("no plain text syntax"); + FALLBACK_SYNTAX.get_or_init(|| plain.clone()) + } + + pub fn highlight_code(code: &str, lang: Option<&str>) -> String { + let syntax = find_syntax(lang); + let ss = &*SYNTAX_SET; + let mut generator = + ClassedHTMLGenerator::new_with_class_style(syntax, ss, ClassStyle::Spaced); + + for line in LinesWithEndings::from(code) { + let _ = generator.parse_html_for_line_which_includes_newline(line); + } + + generator.finalize() + } + + pub fn get_latte_theme() -> &'static Theme { + &*LATTE_THEME + } + + pub fn get_mocha_theme() -> &'static Theme { + &*MOCHA_THEME + } + + pub fn get_syntax_set() -> &'static SyntaxSet { + &*SYNTAX_SET + } +} diff --git a/src/main.rs b/src/main.rs index bcd5483..c309de1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod auth; mod components; mod context; mod db; +mod highlight; mod hooks; mod models; mod pages;