summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-05-04 22:14:57 +0200
committerLaurenz <laurmaedje@gmail.com>2022-05-04 22:14:57 +0200
commite674fd7e909c273c36952f01829544a2efc11c92 (patch)
treec74218ce4a546de06b28aad2f73ba460338252b7 /src
parent75472fee1a2377f56551fc856cf7511bd55091f0 (diff)
New raw theme & nicer debug representation
Diffstat (limited to 'src')
-rw-r--r--src/eval/func.rs10
-rw-r--r--src/eval/value.rs22
-rw-r--r--src/geom/paint.rs5
-rw-r--r--src/library/text/raw.rs76
-rw-r--r--src/parse/mod.rs30
-rw-r--r--src/syntax/highlight.rs6
6 files changed, 101 insertions, 48 deletions
diff --git a/src/eval/func.rs b/src/eval/func.rs
index 7e4040b6..b72e9f18 100644
--- a/src/eval/func.rs
+++ b/src/eval/func.rs
@@ -1,4 +1,4 @@
-use std::fmt::{self, Debug, Formatter, Write};
+use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
@@ -119,12 +119,10 @@ impl Func {
impl Debug for Func {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
- f.write_str("<function")?;
- if let Some(name) = self.name() {
- f.write_char(' ')?;
- f.write_str(name)?;
+ match self.name() {
+ Some(name) => f.write_str(name),
+ None => f.write_str("(..) => {..}"),
}
- f.write_char('>')
}
}
diff --git a/src/eval/value.rs b/src/eval/value.rs
index fc54cbce..b5607cfd 100644
--- a/src/eval/value.rs
+++ b/src/eval/value.rs
@@ -122,8 +122,9 @@ impl Value {
Value::Content(v) => v,
// For values which can't be shown "naturally", we return the raw
- // representation.
- v => Content::show(RawNode { text: v.repr(), block: false }),
+ // representation with typst code syntax highlighting.
+ v => Content::show(RawNode { text: v.repr(), block: false })
+ .styled(RawNode::LANG, Some("typc".into())),
}
}
}
@@ -149,7 +150,7 @@ impl Debug for Value {
Self::Fraction(v) => Debug::fmt(v, f),
Self::Color(v) => Debug::fmt(v, f),
Self::Str(v) => Debug::fmt(v, f),
- Self::Content(_) => f.pad("<content>"),
+ Self::Content(_) => f.pad("[...]"),
Self::Array(v) => Debug::fmt(v, f),
Self::Dict(v) => Debug::fmt(v, f),
Self::Func(v) => Debug::fmt(v, f),
@@ -720,7 +721,10 @@ mod tests {
"30% + 56.69pt",
);
test(Fraction::one() * 7.55, "7.55fr");
- test(Color::Rgba(RgbaColor::new(1, 1, 1, 0xff)), "#010101");
+ test(
+ Color::Rgba(RgbaColor::new(1, 1, 1, 0xff)),
+ "rgb(\"#010101\")",
+ );
// Collections.
test("hello", r#""hello""#);
@@ -734,13 +738,9 @@ mod tests {
test(dict!["one" => 1], "(one: 1)");
test(dict!["two" => false, "one" => 1], "(one: 1, two: false)");
- // Functions.
- test(
- Func::from_fn("nil", |_, _| Ok(Value::None)),
- "<function nil>",
- );
-
- // Dynamics.
+ // Functions, content and dynamics.
+ test(Content::Text("a".into()), "[...]");
+ test(Func::from_fn("nil", |_, _| Ok(Value::None)), "nil");
test(Dynamic::new(1), "1");
}
}
diff --git a/src/geom/paint.rs b/src/geom/paint.rs
index 351ef443..9b310249 100644
--- a/src/geom/paint.rs
+++ b/src/geom/paint.rs
@@ -154,7 +154,7 @@ impl FromStr for RgbaColor {
impl From<SynColor> for RgbaColor {
fn from(color: SynColor) -> Self {
- Self::new(color.r, color.b, color.g, color.a)
+ Self::new(color.r, color.g, color.b, color.a)
}
}
@@ -167,10 +167,11 @@ impl Debug for RgbaColor {
self.r, self.g, self.b, self.a,
)?;
} else {
- write!(f, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b)?;
+ write!(f, "rgb(\"#{:02x}{:02x}{:02x}", self.r, self.g, self.b)?;
if self.a != 255 {
write!(f, "{:02x}", self.a)?;
}
+ write!(f, "\")")?;
}
Ok(())
}
diff --git a/src/library/text/raw.rs b/src/library/text/raw.rs
index c711aa16..d5a3aa95 100644
--- a/src/library/text/raw.rs
+++ b/src/library/text/raw.rs
@@ -1,20 +1,17 @@
+use std::sync::Arc;
+
use once_cell::sync::Lazy;
use syntect::easy::HighlightLines;
-use syntect::highlighting::{FontStyle, Highlighter, Style, Theme, ThemeSet};
+use syntect::highlighting::{
+ Color, FontStyle, Highlighter, Style, StyleModifier, Theme, ThemeItem, ThemeSettings,
+};
use syntect::parsing::SyntaxSet;
use super::{FontFamily, Hyphenate, TextNode, Toggle};
use crate::library::layout::BlockSpacing;
use crate::library::prelude::*;
use crate::source::SourceId;
-use crate::syntax::{self, RedNode};
-
-/// The lazily-loaded theme used for syntax highlighting.
-static THEME: Lazy<Theme> =
- Lazy::new(|| ThemeSet::load_defaults().themes.remove("InspiredGitHub").unwrap());
-
-/// The lazily-loaded syntect syntax definitions.
-static SYNTAXES: Lazy<SyntaxSet> = Lazy::new(|| SyntaxSet::load_defaults_newlines());
+use crate::syntax::{self, GreenNode, NodeKind, RedNode};
/// Monospaced text with optional syntax highlighting.
#[derive(Debug, Hash)]
@@ -63,7 +60,7 @@ impl Show for RawNode {
}
fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult<Content> {
- let lang = styles.get(Self::LANG).as_ref();
+ let lang = styles.get(Self::LANG).as_ref().map(|s| s.to_lowercase());
let foreground = THEME
.settings
.foreground
@@ -71,15 +68,19 @@ impl Show for RawNode {
.unwrap_or(Color::BLACK)
.into();
- let mut realized = if matches!(
- lang.map(|s| s.to_lowercase()).as_deref(),
- Some("typ" | "typst")
- ) {
- let mut seq = vec![];
- let green = crate::parse::parse(&self.text);
- let red = RedNode::from_root(green, SourceId::from_raw(0));
+ let mut realized = if matches!(lang.as_deref(), Some("typ" | "typst" | "typc")) {
+ let root = match lang.as_deref() {
+ Some("typc") => {
+ let children = crate::parse::parse_code(&self.text);
+ Arc::new(GreenNode::with_children(NodeKind::CodeBlock, children))
+ }
+ _ => crate::parse::parse(&self.text),
+ };
+
+ let red = RedNode::from_root(root, SourceId::from_raw(0));
let highlighter = Highlighter::new(&THEME);
+ let mut seq = vec![];
syntax::highlight_syntect(red.as_ref(), &highlighter, &mut |range, style| {
seq.push(styled(&self.text[range], foreground, style));
});
@@ -159,3 +160,44 @@ fn styled(piece: &str, foreground: Paint, style: Style) -> Content {
body.styled_with_map(styles)
}
+
+/// The lazily-loaded syntect syntax definitions.
+static SYNTAXES: Lazy<SyntaxSet> = Lazy::new(|| SyntaxSet::load_defaults_newlines());
+
+/// The lazily-loaded theme used for syntax highlighting.
+#[rustfmt::skip]
+static THEME: Lazy<Theme> = Lazy::new(|| Theme {
+ name: Some("Typst Light".into()),
+ author: Some("The Typst Project Developers".into()),
+ settings: ThemeSettings::default(),
+ scopes: vec![
+ item("markup.bold", None, Some(FontStyle::BOLD)),
+ item("markup.italic", None, Some(FontStyle::ITALIC)),
+ item("markup.heading, entity.name.section", None, Some(FontStyle::BOLD)),
+ item("markup.raw", Some("#818181"), None),
+ item("markup.list", Some("#8b41b1"), None),
+ item("comment", Some("#8a8a8a"), None),
+ item("keyword, constant.language, variable.language", Some("#d73a49"), None),
+ item("storage.type, storage.modifier", Some("#d73a49"), None),
+ item("entity.other", Some("#8b41b1"), None),
+ item("entity.name, variable.function, support", Some("#4b69c6"), None),
+ item("support.macro", Some("#16718d"), None),
+ item("meta.annotation", Some("#301414"), None),
+ item("constant", Some("#b60157"), None),
+ item("string", Some("#298e0d"), None),
+ item("punctuation.shortcut", Some("#1d6c76"), None),
+ item("constant.character.escape", Some("#1d6c76"), None),
+ ],
+});
+
+/// Create a syntect theme item.
+fn item(scope: &str, color: Option<&str>, font_style: Option<FontStyle>) -> ThemeItem {
+ ThemeItem {
+ scope: scope.parse().unwrap(),
+ style: StyleModifier {
+ foreground: color.map(|s| s.parse().unwrap()),
+ background: None,
+ font_style,
+ },
+ }
+}
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index 9f4860e7..7811482b 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -26,6 +26,13 @@ pub fn parse(src: &str) -> Arc<GreenNode> {
}
}
+/// Parse code directly, only used for syntax highlighting.
+pub fn parse_code(src: &str) -> Vec<Green> {
+ let mut p = Parser::new(src, TokenMode::Code);
+ code(&mut p);
+ p.finish()
+}
+
/// Reparse a code block.
///
/// Returns `Some` if all of the input was consumed.
@@ -696,18 +703,23 @@ fn params(p: &mut Parser, marker: Marker) {
fn code_block(p: &mut Parser) {
p.perform(NodeKind::CodeBlock, |p| {
p.start_group(Group::Brace);
- while !p.eof() {
- p.start_group(Group::Expr);
- if expr(p).is_ok() && !p.eof() {
- p.expected("semicolon or line break");
- }
- p.end_group();
+ code(p);
+ p.end_group();
+ });
+}
- // Forcefully skip over newlines since the group's contents can't.
- p.eat_while(|t| matches!(t, NodeKind::Space(_)));
+/// Parse expressions.
+fn code(p: &mut Parser) {
+ while !p.eof() {
+ p.start_group(Group::Expr);
+ if expr(p).is_ok() && !p.eof() {
+ p.expected("semicolon or line break");
}
p.end_group();
- });
+
+ // Forcefully skip over newlines since the group's contents can't.
+ p.eat_while(|t| matches!(t, NodeKind::Space(_)));
+ }
}
// Parse a content block: `[...]`.
diff --git a/src/syntax/highlight.rs b/src/syntax/highlight.rs
index 8e62424f..dae379ac 100644
--- a/src/syntax/highlight.rs
+++ b/src/syntax/highlight.rs
@@ -95,7 +95,7 @@ pub enum Category {
/// A function.
Function,
/// An interpolated variable in markup.
- Variable,
+ Interpolated,
/// An invalid node.
Invalid,
}
@@ -178,7 +178,7 @@ impl Category {
NodeKind::None => Some(Category::None),
NodeKind::Auto => Some(Category::Auto),
NodeKind::Ident(_) => match parent.kind() {
- NodeKind::Markup(_) => Some(Category::Variable),
+ NodeKind::Markup(_) => Some(Category::Interpolated),
NodeKind::FuncCall => Some(Category::Function),
NodeKind::MethodCall if i > 0 => Some(Category::Function),
NodeKind::ClosureExpr if i == 0 => Some(Category::Function),
@@ -263,7 +263,7 @@ impl Category {
Self::Number => "constant.numeric.typst",
Self::String => "string.quoted.double.typst",
Self::Function => "entity.name.function.typst",
- Self::Variable => "variable.parameter.typst",
+ Self::Interpolated => "entity.other.interpolated.typst",
Self::Invalid => "invalid.typst",
}
}