diff --git a/Cargo.lock b/Cargo.lock
index 8ed0897ac..1d5ecb602 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -942,7 +942,7 @@ dependencies = [
"log",
"num-format",
"once_cell",
- "quick-xml",
+ "quick-xml 0.26.0",
"rgb",
"str_stack",
]
@@ -1122,6 +1122,15 @@ version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
+[[package]]
+name = "line-wrap"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
+dependencies = [
+ "safemem",
+]
+
[[package]]
name = "linked-hash-map"
version = "0.5.6"
@@ -1450,6 +1459,20 @@ dependencies = [
"ttf-parser",
]
+[[package]]
+name = "plist"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590"
+dependencies = [
+ "base64",
+ "indexmap",
+ "line-wrap",
+ "quick-xml 0.28.2",
+ "serde",
+ "time",
+]
+
[[package]]
name = "png"
version = "0.17.8"
@@ -1518,6 +1541,15 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "quick-xml"
+version = "0.28.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "quote"
version = "1.0.27"
@@ -1783,6 +1815,12 @@ version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
+[[package]]
+name = "safemem"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
+
[[package]]
name = "same-file"
version = "1.0.6"
@@ -2053,6 +2091,7 @@ dependencies = [
"fnv",
"lazy_static",
"once_cell",
+ "plist",
"regex-syntax 0.6.29",
"serde",
"serde_derive",
diff --git a/NOTICE b/NOTICE
index 93a412b45..8cfa6b61a 100644
--- a/NOTICE
+++ b/NOTICE
@@ -25,6 +25,10 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
================================================================================
The MIT License applies to:
+* The tmTheme in `assets/files/halcyon.tmTheme`
+ Copyright (c) 2018 Brittany Chiang
+ in the Sublime Text package `Halcyon` (https://github.com/bchiang7/Halcyon)
+
* The default color set defined in `crates/typst/src/geom/color.rs` which is
adapted from the colors.css project
(https://clrs.cc/)
diff --git a/assets/files/halcyon.tmTheme b/assets/files/halcyon.tmTheme
new file mode 100644
index 000000000..36f2d66a1
--- /dev/null
+++ b/assets/files/halcyon.tmTheme
@@ -0,0 +1,865 @@
+
+
+
+
+ author
+ Brittany Chiang
+ colorSpaceName
+ sRGB
+ name
+ ayu
+ semanticClass
+ halcyon
+ settings
+
+
+ settings
+
+ background
+ #1d2433
+ foreground
+ #a2aabc
+ caret
+ #FFCC66
+ findHighlight
+ #8695b7
+ findHighlightForeground
+ #d7dce2
+ guide
+ #2f3b54
+ activeGuide
+ #2f3b54
+ stackGuide
+ #2f3b54
+ gutter
+ #1d2433
+ gutterForeground
+ #8695b755
+ inactiveBackground
+ #1d2433
+ inactiveSelection
+ #2f3b54
+ invisibles
+ #6679a4
+ lineHighlight
+ #2f3b54
+ popupCss
+
+ html, body {
+ background-color: #1d2433;
+ font-size: 12px;
+ color: #a2aabc;
+ padding: 0;
+ }
+ body {
+ padding: 5px;
+ }
+ div {
+ padding-bottom: -3px;
+ }
+ b, strong {
+ font-weight: normal;
+ }
+ a {
+ color: rgba(92, 207, 230, .7);
+ line-height: 16px;
+ }
+ .type {
+ color: #ef6b73;
+ }
+ .name {
+ color: #ffd580;
+ }
+ .param {
+ color: #FFD580;
+ }
+ .current {
+ text-decoration: underline;
+ }
+
+ selection
+ #2f3b54
+ selectionBorder
+ #a2aabc35
+ shadow
+ #00000010
+
+
+
+ name
+ Comments
+ scope
+ comment, punctuation.definition.comment
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #8695b799
+
+
+
+ name
+ Variable
+ scope
+ variable
+ settings
+
+ foreground
+ #a2aabc
+
+
+
+ name
+ Keyword
+ scope
+ keyword, keyword.operator
+ settings
+
+ foreground
+ #FFAE57
+
+
+
+ name
+ Storage
+ scope
+ storage.type, storage.modifier
+ settings
+
+ foreground
+ #c3a6ff
+
+
+
+ name
+ Operator, Misc
+ scope
+ constant.other.color, meta.tag, punctuation.separator.inheritance.php, punctuation.section.embedded, keyword.other.substitution
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ Tag
+ scope
+ entity.name.tag, meta.tag.sgml
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ Git Gutter Deleted
+ scope
+ markup.deleted.git_gutter
+ settings
+
+ foreground
+ #ef6b73
+
+
+
+ name
+ Function, Special Method, Block Level
+ scope
+ entity.name, entity.name.class, entity.other.inherited-class, variable.function, support.function, keyword.other.special-method, meta.block-level
+ settings
+
+ foreground
+ #FFD580
+
+
+
+ name
+ Other Variable, String Link
+ scope
+ support.other.variable, string.other.link
+ settings
+
+ foreground
+ #ef6b73
+
+
+
+ name
+ Number, Constant, Function Argument, Tag Attribute, Embedded
+ scope
+ constant.numeric, constant.language, constant.character, keyword.other.unit
+ settings
+
+ foreground
+ #c3a6ff
+
+
+
+ name
+ Number, Constant, Function Argument, Tag Attribute, Embedded
+ scope
+ support.constant, meta.jsx.js, punctuation.section, string.unquoted.label
+ settings
+
+ foreground
+ #a2aabc
+
+
+
+ name
+ String, Symbols, Inherited Class, Markup Heading
+ scope
+ string, keyword.other.template, constant.other.symbol, constant.other.key, entity.other.inherited-class, markup.heading, markup.inserted.git_gutter, meta.group.braces.curly
+ settings
+
+ fontStyle
+ normal
+ foreground
+ #bae67e
+
+
+
+ name
+ Class, Support
+ scope
+ entity.name.type.class, support.type, support.class, support.orther.namespace.use.php, meta.use.php, support.other.namespace.php, markup.changed.git_gutter
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ Sub-methods
+ scope
+ entity.name.module.js, variable.import.parameter.js, variable.other.class.js
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ Language methods
+ scope
+ variable.language
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #5ccfe6
+
+
+
+ name
+ Invalid
+ scope
+ invalid, invalid.illegal
+ settings
+
+ foreground
+ #ef6b73
+
+
+
+ name
+ Deprecated
+ scope
+ invalid.deprecated
+ settings
+
+ background
+ #FFAE57
+ foreground
+ #d7dce2
+
+
+
+ name
+ Html punctuations tags
+ scope
+ punctuation.definition.tag.end, punctuation.definition.tag.begin, punctuation.definition.tag, meta.group.braces.curly.js, meta.property-value, meta.jsx.js
+ settings
+
+ foreground
+ #a2aabc
+
+
+
+ name
+ Attributes
+ scope
+ entity.other.attribute-name, meta.attribute-with-value.style, constant.other.color.rgb-value, meta.at-rule.media, support.constant.mathematical-symbols,
+ punctuation.separator.key-value
+ settings
+
+ foreground
+ #FFAE57
+
+
+
+ name
+ Inserted
+ scope
+ markup.inserted
+ settings
+
+ foreground
+ #bae67e
+
+
+
+ name
+ Deleted
+ scope
+ markup.deleted
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ Changed
+ scope
+ markup.changed
+ settings
+
+ foreground
+ #FFAE57
+
+
+
+ name
+ Regular Expressions and Escape Characters
+ scope
+ string.regexp, constant.character.escape
+ settings
+
+ foreground
+ #95E6CB
+
+
+
+ name
+ URL
+ scope
+ *url*, *link*, *uri*
+ settings
+
+ fontStyle
+ underline
+
+
+
+ name
+ Search Results Nums
+ scope
+ constant.numeric.line-number.find-in-files - match
+ settings
+
+ foreground
+ #8695b7
+
+
+
+ name
+ Search Results Lines
+ scope
+ entity.name.filename.find-in-files
+ settings
+
+ foreground
+ #bae67e
+
+
+
+ name
+ Decorators
+ scope
+ tag.decorator.js entity.name.tag.js, tag.decorator.js punctuation.definition.tag.js
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #ffd580
+
+
+
+ name
+ ES7 Bind Operator
+ scope
+ constant.other.object.key
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ entity.name.method
+ scope
+ entity.name.method
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #ffd580
+
+
+
+ name
+ meta.method.js
+ scope
+ entity.name.function, variable.function.constructor
+ settings
+
+ foreground
+ #ffd580
+
+
+
+ name
+ Markup - Italic
+ scope
+ markup.italic
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #ef6b73
+
+
+
+ name
+ Markup - Bold
+ scope
+ markup.bold
+ settings
+
+ fontStyle
+ bold
+ foreground
+ #ef6b73
+
+
+
+ name
+ Markup - Underline
+ scope
+ markup.underline
+ settings
+
+ fontStyle
+ underline
+ foreground
+ #c3a6ff
+
+
+
+ name
+ Markup - Strike
+ scope
+ markup.strike
+ settings
+
+ fontStyle
+ strike
+ foreground
+ #ffd580
+
+
+
+ name
+ Markup - Quote
+ scope
+ markup.quote
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #80D4FF
+
+
+
+ name
+ Markup - Raw Block
+ scope
+ markup.raw.block
+ settings
+
+ foreground
+ #FFAE57
+
+
+
+ name
+ Markup - Table
+ scope
+ markup.table
+ settings
+
+ background
+ #1d2433aa
+ foreground
+ #5ccfe6
+
+
+
+ name
+ Markdown - Plain
+ scope
+ text.html.markdown, punctuation.definition.list_item.markdown
+ settings
+
+ foreground
+ #a2aabc
+
+
+
+ name
+ Markdown - Markup Raw Inline
+ scope
+ text.html.markdown markup.raw.inline
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ Markdown - Line Break
+ scope
+ text.html.markdown meta.dummy.line-break
+ settings
+
+ foreground
+ #8695b7
+
+
+
+ name
+ Markdown - Heading
+ scope
+ markdown.heading, markup.heading | markup.heading entity.name, markup.heading.markdown punctuation.definition.heading.markdown
+ settings
+
+ foreground
+ #bae67e
+
+
+
+ name
+ Markdown - Blockquote
+ scope
+ markup.quote, punctuation.definition.blockquote.markdown
+ settings
+
+ fontStyle
+ italic
+ foreground
+ #80D4FF
+
+
+
+ name
+ Markdown - Link
+ scope
+ string.other.link.title.markdown
+ settings
+
+ fontStyle
+ underline
+ foreground
+ #ffd580
+
+
+
+ name
+ Markdown - Raw Block Fenced
+ scope
+ markup.raw.block.fenced.markdown
+ settings
+
+ background
+ #d7dce210
+ foreground
+ #a2aabc
+
+
+
+ name
+ Markdown - Fenced Bode Block
+ scope
+ punctuation.definition.fenced.markdown, variable.language.fenced.markdown
+ settings
+
+ background
+ #d7dce210
+ foreground
+ #8695b7
+
+
+
+ name
+ Markdown - Fenced Language
+ scope
+ variable.language.fenced.markdown
+ settings
+
+ fontStyle
+
+ foreground
+ #8695b7
+
+
+
+ name
+ Markdown - Separator
+ scope
+ meta.separator
+ settings
+
+ background
+ #d7dce210
+ fontStyle
+ bold
+ foreground
+ #8695b7
+
+
+
+ name
+ JSON Key - Level 0
+ scope
+ source.json meta.structure.dictionary.json string.quoted.double.json - meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json, source.json meta.structure.dictionary.json punctuation.definition.string - meta.structure.dictionary.json meta.structure.dictionary.value.json punctuation.definition.string
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ JSON Key - Level 1
+ scope
+ source.json meta meta.structure.dictionary.json string.quoted.double.json - meta meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json, source.json meta meta.structure.dictionary.json punctuation.definition.string - meta meta.structure.dictionary.json meta.structure.dictionary.value.json punctuation.definition.string
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ JSON Key - Level 2
+ scope
+ source.json meta meta meta meta.structure.dictionary.json string.quoted.double.json - meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json, source.json meta meta meta meta.structure.dictionary.json punctuation.definition.string - meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json punctuation.definition.string
+ settings
+
+ foreground
+ #ffae57
+
+
+
+ name
+ JSON Key - Level 3
+ scope
+ source.json meta meta meta meta meta meta.structure.dictionary.json string.quoted.double.json - meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json, source.json meta meta meta meta meta meta.structure.dictionary.json punctuation.definition.string - meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json punctuation.definition.string
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ JSON Key - Level 4
+ scope
+ source.json meta meta meta meta meta meta meta meta.structure.dictionary.json string.quoted.double.json - meta meta meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json, source.json meta meta meta meta meta meta meta meta.structure.dictionary.json punctuation.definition.string - meta meta meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json punctuation.definition.string
+ settings
+
+ foreground
+ #ffae57
+
+
+
+ name
+ JSON Key - Level 5
+ scope
+ source.json meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json string.quoted.double.json - meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json, source.json meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json punctuation.definition.string - meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json punctuation.definition.string
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ JSON Key - Level 6
+ scope
+ source.json meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json string.quoted.double.json - meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json, source.json meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json punctuation.definition.string - meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json punctuation.definition.string
+ settings
+
+ foreground
+ #ffae57
+
+
+
+ name
+ JSON Key - Level 7
+ scope
+ source.json meta meta meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json string.quoted.double.json - meta meta meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json, source.json meta meta meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json punctuation.definition.string - meta meta meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json punctuation.definition.string
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ JSON Key - Level 8
+ scope
+ source.json meta meta meta meta meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json string.quoted.double.json - meta meta meta meta meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json, source.json meta meta meta meta meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json punctuation.definition.string - meta meta meta meta meta meta meta meta meta meta meta meta meta meta meta meta.structure.dictionary.json meta.structure.dictionary.value.json punctuation.definition.string
+ settings
+
+ foreground
+ #ffae57
+
+
+
+ name
+ AceJump Label - Blue
+ scope
+ acejump.label.blue
+ settings
+
+ background
+ #5ccfe6
+ foreground
+ #d7dce2
+
+
+
+ name
+ AceJump Label - Green
+ scope
+ acejump.label.green
+ settings
+
+ background
+ #bae67e
+ foreground
+ #d7dce2
+
+
+
+ name
+ AceJump Label - Orange
+ scope
+ acejump.label.orange
+ settings
+
+ background
+ #FFAE57
+ foreground
+ #d7dce2
+
+
+
+ name
+ AceJump Label - Purple
+ scope
+ acejump.label.purple
+ settings
+
+ background
+ #ef6b73
+ foreground
+ #d7dce2
+
+
+
+ name
+ SublimeLinter Warning
+ scope
+ sublimelinter.mark.warning
+ settings
+
+ foreground
+ #5ccfe6
+
+
+
+ name
+ SublimeLinter Gutter Mark
+ scope
+ sublimelinter.gutter-mark
+ settings
+
+ foreground
+ #d7dce2
+
+
+
+ name
+ SublimeLinter Error
+ scope
+ sublimelinter.mark.error
+ settings
+
+ foreground
+ #ef6b73
+
+
+
+ name
+ GitGutter Ignored
+ scope
+ markup.ignored.git_gutter
+ settings
+
+ foreground
+ #8695b7
+
+
+
+ name
+ GitGutter Untracked
+ scope
+ markup.untracked.git_gutter
+ settings
+
+ foreground
+ #8695b7
+
+
+
+ name
+ GutterColor
+ scope
+ gutter_color
+ settings
+
+ foreground
+ #d7dce2
+
+
+
+ uuid
+ 0e709986-46a0-40a0-b3bf-c8dfe525c455
+
+
diff --git a/crates/typst-library/Cargo.toml b/crates/typst-library/Cargo.toml
index 86c3ab5aa..da0fae5fa 100644
--- a/crates/typst-library/Cargo.toml
+++ b/crates/typst-library/Cargo.toml
@@ -39,7 +39,7 @@ rustybuzz = "0.7"
serde_json = "1"
serde_yaml = "0.8"
smallvec = "1.10"
-syntect = { version = "5", default-features = false, features = ["parsing", "regex-fancy", "yaml-load"] }
+syntect = { version = "5", default-features = false, features = ["parsing", "regex-fancy", "plist-load", "yaml-load"] }
time = { version = "0.3.20", features = ["formatting"] }
toml = { version = "0.7.3", default-features = false, features = ["parse"] }
tracing = "0.1.37"
diff --git a/crates/typst-library/src/text/raw.rs b/crates/typst-library/src/text/raw.rs
index 4d4cb7102..af1607ab3 100644
--- a/crates/typst-library/src/text/raw.rs
+++ b/crates/typst-library/src/text/raw.rs
@@ -149,17 +149,39 @@ pub struct RawElem {
/// ```
/// ````
#[parse(
- let (syntaxes, data) = parse_syntaxes(vm, args)?;
+ let (syntaxes, syntaxes_data) = parse_syntaxes(vm, args)?;
syntaxes
)]
#[fold]
pub syntaxes: SyntaxPaths,
- /// The raw file buffers.
+ /// The raw file buffers of syntax definition files.
#[internal]
- #[parse(data)]
+ #[parse(syntaxes_data)]
#[fold]
- pub data: Vec,
+ pub syntaxes_data: Vec,
+
+ /// The theme to use for syntax highlighting. Theme files should be in the in the
+ /// `tmTheme` file format.
+ ///
+ /// ````example
+ /// #set raw(theme: "halcyon.tmTheme")
+ ///
+ /// ```typ
+ /// = Chapter 1
+ /// #let hi = "Hello World"
+ /// ```
+ /// ````
+ #[parse(
+ let (theme_path, theme_data) = parse_theme(vm, args)?;
+ theme_path.map(Some)
+ )]
+ pub theme: Option,
+
+ /// The raw file buffer of syntax theme file.
+ #[internal]
+ #[parse(theme_data.map(Some))]
+ pub theme_data: Option,
}
impl RawElem {
@@ -190,16 +212,28 @@ impl Show for RawElem {
#[tracing::instrument(name = "RawElem::show", skip_all)]
fn show(&self, _: &mut Vt, styles: StyleChain) -> SourceResult {
let text = self.text();
- let lang = self.lang(styles).as_ref().map(|s| s.to_lowercase());
- let foreground = THEME
+ let lang = self
+ .lang(styles)
+ .as_ref()
+ .map(|s| s.to_lowercase())
+ .or(Some("txt".into()));
+
+ let extra_syntaxes = UnsyncLazy::new(|| {
+ load_syntaxes(&self.syntaxes(styles), &self.syntaxes_data(styles)).unwrap()
+ });
+
+ let theme = self.theme(styles).map(|theme_path| {
+ load_theme(theme_path, self.theme_data(styles).unwrap()).unwrap()
+ });
+
+ let theme = theme.as_deref().unwrap_or(&THEME);
+
+ let foreground = theme
.settings
.foreground
.map(to_typst)
.map_or(Color::BLACK, Color::from);
- let extra_syntaxes =
- UnsyncLazy::new(|| load(&self.syntaxes(styles), &self.data(styles)).unwrap());
-
let mut realized = if matches!(lang.as_deref(), Some("typ" | "typst" | "typc")) {
let root = match lang.as_deref() {
Some("typc") => syntax::parse_code(&text),
@@ -207,7 +241,7 @@ impl Show for RawElem {
};
let mut seq = vec![];
- let highlighter = synt::Highlighter::new(&THEME);
+ let highlighter = synt::Highlighter::new(theme);
highlight_themed(
&LinkedNode::new(&root),
vec![],
@@ -229,7 +263,7 @@ impl Show for RawElem {
})
}) {
let mut seq = vec![];
- let mut highlighter = syntect::easy::HighlightLines::new(syntax, &THEME);
+ let mut highlighter = syntect::easy::HighlightLines::new(syntax, theme);
for (i, line) in text.lines().enumerate() {
if i != 0 {
seq.push(LinebreakElem::new().pack());
@@ -385,7 +419,7 @@ impl Fold for SyntaxPaths {
/// Load a syntax set from a list of syntax file paths.
#[comemo::memoize]
-fn load(paths: &SyntaxPaths, bytes: &[Bytes]) -> StrResult> {
+fn load_syntaxes(paths: &SyntaxPaths, bytes: &[Bytes]) -> StrResult> {
let mut out = SyntaxSetBuilder::new();
// We might have multiple sublime-syntax/yaml files
@@ -423,11 +457,42 @@ fn parse_syntaxes(
.collect::>>()?;
// Check that parsing works.
- let _ = load(&paths, &data).at(span)?;
+ let _ = load_syntaxes(&paths, &data).at(span)?;
Ok((Some(paths), Some(data)))
}
+#[comemo::memoize]
+fn load_theme(path: EcoString, bytes: Bytes) -> StrResult> {
+ let mut cursor = std::io::Cursor::new(bytes.as_slice());
+
+ synt::ThemeSet::load_from_reader(&mut cursor)
+ .map(Arc::new)
+ .map_err(|e| eco_format!("failed to parse theme file `{path}`: {e}"))
+}
+
+/// Function to parse the theme argument.
+/// Much nicer than having it be part of the `element` macro.
+fn parse_theme(
+ vm: &mut Vm,
+ args: &mut Args,
+) -> SourceResult<(Option, Option)> {
+ let Some(Spanned { v: path, span }) =
+ args.named::>("theme")?
+ else {
+ return Ok((None, None));
+ };
+
+ // Load theme file.
+ let id = vm.location().join(&path).at(span)?;
+ let data = vm.world().file(id).at(span)?;
+
+ // Check that parsing works.
+ let _ = load_theme(path.clone(), data.clone()).at(span)?;
+
+ Ok((Some(path), Some(data)))
+}
+
/// The syntect syntax definitions.
///
/// Code for syntax set generation is below. The `syntaxes` directory is from
diff --git a/tests/ref/text/raw-theme.png b/tests/ref/text/raw-theme.png
new file mode 100644
index 000000000..0ce177605
Binary files /dev/null and b/tests/ref/text/raw-theme.png differ
diff --git a/tests/typ/text/raw-theme.typ b/tests/typ/text/raw-theme.typ
new file mode 100644
index 000000000..71b59688b
--- /dev/null
+++ b/tests/typ/text/raw-theme.typ
@@ -0,0 +1,24 @@
+// Test code highlighting with custom theme.
+
+---
+#set page(width: 180pt)
+#set text(6pt)
+#set raw(theme: "/files/halcyon.tmTheme")
+#show raw: it => {
+ set text(fill: rgb("a2aabc"))
+ rect(
+ width: 100%,
+ inset: (x: 4pt, y: 5pt),
+ radius: 4pt,
+ fill: rgb("1d2433"),
+ place(right, text(luma(240), it.lang)) + it,
+ )
+}
+
+```typ
+= Chapter 1
+#lorem(100)
+
+#let hi = "Hello World"
+#show heading: emph
+```