text_view: Add syntax highlight to CodeBlock. (#684)
<img width="1712" alt="image" src="https://github.com/user-attachments/assets/e7539df4-20db-431b-9bbc-52e08e9de062" /> <img width="1712" alt="image" src="https://github.com/user-attachments/assets/85d52319-1029-4306-8629-ec0321d0571b" />
This commit is contained in:
parent
8c4884d881
commit
c3f08d52b9
15 changed files with 1547 additions and 158 deletions
99
Cargo.lock
generated
99
Cargo.lock
generated
|
|
@ -543,6 +543,15 @@ dependencies = [
|
|||
"simd-abstraction",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.69.5"
|
||||
|
|
@ -552,7 +561,7 @@ dependencies = [
|
|||
"bitflags 2.6.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.10.5",
|
||||
"itertools 0.12.1",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
|
|
@ -575,7 +584,7 @@ dependencies = [
|
|||
"bitflags 2.6.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.10.5",
|
||||
"itertools 0.13.0",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
|
|
@ -2657,6 +2666,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"smallvec",
|
||||
"smol 1.3.0",
|
||||
"syntect",
|
||||
"unicode-segmentation",
|
||||
"usvg",
|
||||
"uuid",
|
||||
|
|
@ -3482,6 +3492,12 @@ dependencies = [
|
|||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[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.3.8"
|
||||
|
|
@ -4035,7 +4051,7 @@ version = "0.7.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
|
||||
dependencies = [
|
||||
"proc-macro-crate 1.3.1",
|
||||
"proc-macro-crate 3.2.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.96",
|
||||
|
|
@ -4283,6 +4299,28 @@ version = "1.20.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "onig"
|
||||
version = "6.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"onig_sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "onig_sys"
|
||||
version = "69.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oo7"
|
||||
version = "0.4.0"
|
||||
|
|
@ -4700,6 +4738,19 @@ version = "0.3.31"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"indexmap 2.7.1",
|
||||
"quick-xml 0.32.0",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.14"
|
||||
|
|
@ -4919,6 +4970,15 @@ version = "2.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.36.2"
|
||||
|
|
@ -6409,6 +6469,28 @@ dependencies = [
|
|||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syntect"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags 1.3.2",
|
||||
"flate2",
|
||||
"fnv",
|
||||
"once_cell",
|
||||
"onig",
|
||||
"plist",
|
||||
"regex-syntax",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"thiserror 1.0.66",
|
||||
"walkdir",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sys-locale"
|
||||
version = "0.3.1"
|
||||
|
|
@ -7350,7 +7432,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quick-xml",
|
||||
"quick-xml 0.36.2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
|
|
@ -8067,6 +8149,15 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
|
||||
|
||||
[[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 = "yazi"
|
||||
version = "0.1.6"
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ UI components for building fantastic desktop application by using [GPUI](https:/
|
|||
- Sidebar
|
||||
- Breadcrumb
|
||||
- Badge
|
||||
- TextView (Markdown, Simple HTML) to native rendering.
|
||||
- TextView (Markdown, Simple HTML) to native rendering, syntax highlighting.
|
||||
|
||||
## Showcase
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,23 @@ This is an additional demonstration paragraph in English demonstrating more cont
|
|||
|
||||
这是一个中文演示段落,用于展示更多的 [Markdown GFM](https://github.github.com/gfm/) 内容。您可以在此尝试使用使用**粗体**、*斜体*和`代码`等样式。これは日本語のデモ段落です。Markdown の多言語サポートを示すためのテキストが含まれています。例えば、、**ボールド**、_イタリック_、および`コード`のスタイルなどを試すことができます。
|
||||
|
||||
### Code block
|
||||
|
||||
```rust
|
||||
struct Repository {
|
||||
/// Name of the repository.
|
||||
name: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = Repository {
|
||||
name: "GPUI Component".to_string(),
|
||||
};
|
||||
|
||||
println!("Hello, World!");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Heading for [Links](https://www.google.com)
|
||||
|
|
@ -61,14 +78,6 @@ Here is a link to [Google](https://www.google.com), and another to [Rust](https:
|
|||
- [ ] Task 2, going to do something if there is a long text that needs to be wrapped to the next line.
|
||||
- [ ] Task 3
|
||||
|
||||
#### Heading for Code
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
println!("Hello, World!");
|
||||
}
|
||||
```
|
||||
|
||||
### HTML
|
||||
|
||||
#### Paragraph and Text
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use gpui::*;
|
||||
use gpui_component::{input::TextInput, text::TextView, ActiveTheme as _};
|
||||
use gpui_component::{
|
||||
highlighter::HighlightTheme,
|
||||
input::TextInput,
|
||||
text::{TextView, TextViewStyle},
|
||||
ActiveTheme as _,
|
||||
};
|
||||
use story::Assets;
|
||||
|
||||
pub struct Example {
|
||||
|
|
@ -39,6 +46,12 @@ impl Example {
|
|||
|
||||
impl Render for Example {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let theme = if cx.theme().mode.is_dark() {
|
||||
HighlightTheme::default_dark()
|
||||
} else {
|
||||
HighlightTheme::default_light()
|
||||
};
|
||||
|
||||
div()
|
||||
.flex()
|
||||
.flex_row()
|
||||
|
|
@ -61,10 +74,14 @@ impl Render for Example {
|
|||
.p_5()
|
||||
.flex_1()
|
||||
.overflow_y_scroll()
|
||||
.child(TextView::markdown(
|
||||
"preview",
|
||||
self.text_input.read(cx).text(),
|
||||
)),
|
||||
.child(
|
||||
TextView::markdown("preview", self.text_input.read(cx).text()).style(
|
||||
TextViewStyle {
|
||||
highlight_theme: Rc::new(theme),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ markup5ever_rcdom = "0.3.0"
|
|||
minify-html = "0.15.0"
|
||||
# Calendar
|
||||
chrono = "0.4.38"
|
||||
syntect = { version = "5.2", features = ["plist-load"] }
|
||||
|
||||
[dev-dependencies]
|
||||
indoc = "2"
|
||||
|
|
|
|||
150
crates/ui/src/highlighter/highlight.rs
Normal file
150
crates/ui/src/highlighter/highlight.rs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
use gpui::{HighlightStyle, Hsla, SharedString};
|
||||
use std::{
|
||||
ops::Range,
|
||||
sync::{Arc, LazyLock},
|
||||
};
|
||||
use syntect::{highlighting, parsing};
|
||||
|
||||
static SYNTAXES: LazyLock<parsing::SyntaxSet> =
|
||||
LazyLock::new(parsing::SyntaxSet::load_defaults_nonewlines);
|
||||
|
||||
static DEFAULT_LIGHT: LazyLock<Arc<highlighting::Theme>> = LazyLock::new(|| {
|
||||
let mut cursor = std::io::Cursor::new(include_bytes!("./themes/light.tmTheme"));
|
||||
Arc::new(highlighting::ThemeSet::load_from_reader(&mut cursor).unwrap())
|
||||
});
|
||||
|
||||
static DEFAULT_DARK: LazyLock<Arc<highlighting::Theme>> = LazyLock::new(|| {
|
||||
let mut cursor = std::io::Cursor::new(include_bytes!("./themes/dark.tmTheme"));
|
||||
Arc::new(highlighting::ThemeSet::load_from_reader(&mut cursor).unwrap())
|
||||
});
|
||||
|
||||
/// Represents a theme for syntax highlighting.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct HighlightTheme {
|
||||
name: SharedString,
|
||||
inner: Arc<highlighting::Theme>,
|
||||
}
|
||||
|
||||
impl HighlightTheme {
|
||||
/// Default light theme.
|
||||
pub fn default_light() -> Self {
|
||||
Self {
|
||||
name: "default-light".into(),
|
||||
inner: DEFAULT_LIGHT.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Default dark theme.
|
||||
pub fn default_dark() -> Self {
|
||||
Self {
|
||||
name: "default-dark".into(),
|
||||
inner: DEFAULT_DARK.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a theme from a string (tmTheme)
|
||||
pub fn parse(name: &str, theme_str: &str) -> anyhow::Result<Self> {
|
||||
let mut cursor = std::io::Cursor::new(theme_str);
|
||||
let theme = highlighting::ThemeSet::load_from_reader(&mut cursor)?;
|
||||
|
||||
Ok(Self {
|
||||
name: SharedString::from(name.to_string()),
|
||||
inner: Arc::new(theme),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Inspired by the `iced` crate's `Highlighter` struct.
|
||||
///
|
||||
/// https://github.com/iced-rs/iced/blob/master/highlighter/src/lib.rs#L24
|
||||
pub struct Highlighter<'a> {
|
||||
syntax: &'static parsing::SyntaxReference,
|
||||
highlighter: highlighting::Highlighter<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Highlighter<'a> {
|
||||
pub fn new(lang: Option<&str>, theme: &'a HighlightTheme) -> Self {
|
||||
let syntax = lang
|
||||
.and_then(|lang| SYNTAXES.find_syntax_by_token(&lang))
|
||||
.unwrap_or_else(|| SYNTAXES.find_syntax_plain_text());
|
||||
let highlighter = highlighting::Highlighter::new(&theme.inner);
|
||||
|
||||
Self {
|
||||
syntax,
|
||||
highlighter,
|
||||
}
|
||||
}
|
||||
|
||||
/// Highlight a text and returns a vector of ranges and highlight styles
|
||||
pub fn highlight(&self, text: &str) -> Vec<(Range<usize>, HighlightStyle)> {
|
||||
let mut parser = parsing::ParseState::new(self.syntax);
|
||||
let mut stack = parsing::ScopeStack::new();
|
||||
|
||||
let ops = parser.parse_line(text, &SYNTAXES).unwrap_or_default();
|
||||
|
||||
ScopeRangeIterator {
|
||||
ops,
|
||||
line_length: text.len(),
|
||||
index: 0,
|
||||
last_str_index: 0,
|
||||
}
|
||||
.filter_map(move |(range, scope)| {
|
||||
let _ = stack.apply(&scope);
|
||||
if range.is_empty() {
|
||||
return None;
|
||||
} else {
|
||||
let style_mod = self.highlighter.style_mod_for_stack(&stack.scopes);
|
||||
let mut style = HighlightStyle::default();
|
||||
style.color = style_mod.foreground.map(color_to_hsla);
|
||||
style.background_color = style_mod.background.map(color_to_hsla);
|
||||
Some((range, style))
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn color_to_hsla(color: highlighting::Color) -> Hsla {
|
||||
gpui::Rgba {
|
||||
r: color.r as f32 / 255.,
|
||||
g: color.g as f32 / 255.,
|
||||
b: color.b as f32 / 255.,
|
||||
a: color.a as f32 / 100.,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
struct ScopeRangeIterator {
|
||||
ops: Vec<(usize, parsing::ScopeStackOp)>,
|
||||
line_length: usize,
|
||||
index: usize,
|
||||
last_str_index: usize,
|
||||
}
|
||||
|
||||
impl Iterator for ScopeRangeIterator {
|
||||
type Item = (std::ops::Range<usize>, parsing::ScopeStackOp);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.index > self.ops.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let next_str_i = if self.index == self.ops.len() {
|
||||
self.line_length
|
||||
} else {
|
||||
self.ops[self.index].0
|
||||
};
|
||||
|
||||
let range = self.last_str_index..next_str_i;
|
||||
self.last_str_index = next_str_i;
|
||||
|
||||
let op = if self.index == 0 {
|
||||
parsing::ScopeStackOp::Noop
|
||||
} else {
|
||||
self.ops[self.index - 1].1.clone()
|
||||
};
|
||||
|
||||
self.index += 1;
|
||||
Some((range, op))
|
||||
}
|
||||
}
|
||||
3
crates/ui/src/highlighter/mod.rs
Normal file
3
crates/ui/src/highlighter/mod.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
mod highlight;
|
||||
|
||||
pub use highlight::*;
|
||||
1
crates/ui/src/highlighter/themes/README.md
Normal file
1
crates/ui/src/highlighter/themes/README.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
https://github.com/textmate/themes.tmbundle/tree/master/Themes
|
||||
597
crates/ui/src/highlighter/themes/dark.tmTheme
Normal file
597
crates/ui/src/highlighter/themes/dark.tmTheme
Normal file
|
|
@ -0,0 +1,597 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>author</key>
|
||||
<string>Michael Sheets</string>
|
||||
<key>gutterSettings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#2F2F31</string>
|
||||
<key>divider</key>
|
||||
<string>#414143</string>
|
||||
<key>foreground</key>
|
||||
<string>#8F8F8F</string>
|
||||
<key>selectionBackground</key>
|
||||
<string>#414143</string>
|
||||
<key>selectionBorder</key>
|
||||
<string>#484848</string>
|
||||
<key>selectionForeground</key>
|
||||
<string>#BABABA</string>
|
||||
</dict>
|
||||
<key>name</key>
|
||||
<string>Twilight</string>
|
||||
<key>semanticClass</key>
|
||||
<string>theme.dark.twilight</string>
|
||||
<key>settings</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#181818</string>
|
||||
<key>caret</key>
|
||||
<string>#A7A7A7</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
<key>invisibles</key>
|
||||
<string>#FFFFFF40</string>
|
||||
<key>lineHighlight</key>
|
||||
<string>#FFFFFF08</string>
|
||||
<key>selection</key>
|
||||
<string>#DDF0FF33</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Foldings</string>
|
||||
<key>scope</key>
|
||||
<string>deco.folding</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#5A6A65</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Comment</string>
|
||||
<key>scope</key>
|
||||
<string>comment</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#5F5A60</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Constant</string>
|
||||
<key>scope</key>
|
||||
<string>constant</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CF6A4C</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Entity</string>
|
||||
<key>scope</key>
|
||||
<string>entity</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#9B703F</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Keyword</string>
|
||||
<key>scope</key>
|
||||
<string>keyword</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#CDA869</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Storage</string>
|
||||
<key>scope</key>
|
||||
<string>storage</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#F9EE98</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>String</string>
|
||||
<key>scope</key>
|
||||
<string>string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#8F9D6A</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Support</string>
|
||||
<key>scope</key>
|
||||
<string>support</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#9B859D</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Variable</string>
|
||||
<key>scope</key>
|
||||
<string>variable</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#7587A6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Invalid – Deprecated</string>
|
||||
<key>scope</key>
|
||||
<string>invalid.deprecated</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic underline</string>
|
||||
<key>foreground</key>
|
||||
<string>#D2A8A1</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Invalid – Illegal</string>
|
||||
<key>scope</key>
|
||||
<string>invalid.illegal</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#562D56BF</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>-----------------------------------</string>
|
||||
<key>settings</key>
|
||||
<dict/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ Embedded Source</string>
|
||||
<key>scope</key>
|
||||
<string>meta.embedded.block, punctuation.whitespace.embedded</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#B0B3BA14</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ Embedded Source (Bright)</string>
|
||||
<key>scope</key>
|
||||
<string>meta.embedded.line</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#B1B3BA21</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ Entity inherited-class</string>
|
||||
<key>scope</key>
|
||||
<string>entity.other.inherited-class</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#9B5C2E</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ String embedded-source</string>
|
||||
<key>scope</key>
|
||||
<string>string meta.embedded</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#DAEFA3</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ String constant</string>
|
||||
<key>scope</key>
|
||||
<string>string constant</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#DDF2A4</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ String.regexp</string>
|
||||
<key>scope</key>
|
||||
<string>string.regexp</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#E9C062</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ String.regexp.«special»</string>
|
||||
<key>scope</key>
|
||||
<string>string.regexp constant.character.escape, string.regexp source.ruby.embedded, string.regexp string.regexp.arbitrary-repetition</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CF7D34</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ String variable</string>
|
||||
<key>scope</key>
|
||||
<string>string variable</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8A9A95</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ Support.function</string>
|
||||
<key>scope</key>
|
||||
<string>support.function</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#DAD085</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>♦ Support.constant</string>
|
||||
<key>scope</key>
|
||||
<string>support.constant</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#CF6A4C</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>c C/C++ Preprocessor Line</string>
|
||||
<key>scope</key>
|
||||
<string>meta.preprocessor.c, source.swift meta.preprocessor</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8996A8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>c C/C++ Preprocessor Directive</string>
|
||||
<key>scope</key>
|
||||
<string>meta.preprocessor.c keyword, source.swift meta.preprocessor keyword</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#AFC4DB</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>✘ Doctype/XML Processing</string>
|
||||
<key>scope</key>
|
||||
<string>meta.tag.metadata.doctype, meta.tag.metadata.doctype entity, meta.tag.metadata.doctype string, meta.tag.metadata.processing.xml, meta.tag.metadata.processing.xml entity, meta.tag.metadata.processing.xml string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#494949</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>✘ Meta.tag.«all»</string>
|
||||
<key>scope</key>
|
||||
<string>declaration.tag, declaration.tag entity, meta.tag, meta.tag entity</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#AC885B</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>✘ Meta.tag.inline</string>
|
||||
<key>scope</key>
|
||||
<string>declaration.tag.inline, declaration.tag.inline entity, meta.tag.inline, meta.tag.inline entity</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#E0C589</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css tag-name</string>
|
||||
<key>scope</key>
|
||||
<string>meta.selector.css entity.name.tag</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CDA869</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css:pseudo-class</string>
|
||||
<key>scope</key>
|
||||
<string>meta.selector.css entity.other.attribute-name.tag.pseudo-class</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8F9D6A</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css#id</string>
|
||||
<key>scope</key>
|
||||
<string>meta.selector.css entity.other.attribute-name.id</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8B98AB</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css.class</string>
|
||||
<key>scope</key>
|
||||
<string>meta.selector.css entity.other.attribute-name.class</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#9B703F</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css property-name:</string>
|
||||
<key>scope</key>
|
||||
<string>support.type.property-name.css</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#C5AF75</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css property-value;</string>
|
||||
<key>scope</key>
|
||||
<string>meta.property-group support.constant.property-value.css, meta.property-value support.constant.property-value.css</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#F9EE98</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css @at-rule</string>
|
||||
<key>scope</key>
|
||||
<string>meta.preprocessor.at-rule keyword.control.at-rule</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8693A5</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css additional-constants</string>
|
||||
<key>scope</key>
|
||||
<string>meta.property-value support.constant.named-color.css, meta.property-value constant</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CA7840</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>§ css constructor.argument</string>
|
||||
<key>scope</key>
|
||||
<string>meta.constructor.argument.css</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#8F9D6A</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>⎇ diff.header</string>
|
||||
<key>scope</key>
|
||||
<string>meta.diff, meta.diff.header, meta.separator, meta.diff.range, meta.diff.index</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#0E2231</string>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>⎇ diff.deleted</string>
|
||||
<key>scope</key>
|
||||
<string>markup.deleted</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#420E09</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>⎇ diff.changed</string>
|
||||
<key>scope</key>
|
||||
<string>markup.changed</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#4A410D</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>⎇ diff.inserted</string>
|
||||
<key>scope</key>
|
||||
<string>markup.inserted</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#253B22</string>
|
||||
<key>foreground</key>
|
||||
<string>#F8F8F8</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: List</string>
|
||||
<key>scope</key>
|
||||
<string>markup.list</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#F9EE98</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: Heading</string>
|
||||
<key>scope</key>
|
||||
<string>markup.heading</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#CF6A4C</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: Raw Block</string>
|
||||
<key>scope</key>
|
||||
<string>markup.raw.block</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#B0B3BA14</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Test: 1</string>
|
||||
<key>scope</key>
|
||||
<string>meta.test1</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#0E2231C5</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Test: 2</string>
|
||||
<key>scope</key>
|
||||
<string>meta.test2</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#420E0990</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Test: 3</string>
|
||||
<key>scope</key>
|
||||
<string>meta.test3</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#4A410D90</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Test: 4</string>
|
||||
<key>scope</key>
|
||||
<string>meta.test4</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#253B2290</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
<key>uuid</key>
|
||||
<string>766026CB-703D-4610-B070-8DE07D967C5F</string>
|
||||
</dict>
|
||||
</plist>
|
||||
467
crates/ui/src/highlighter/themes/light.tmTheme
Normal file
467
crates/ui/src/highlighter/themes/light.tmTheme
Normal file
|
|
@ -0,0 +1,467 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>author</key>
|
||||
<string>Chris Thomas</string>
|
||||
<key>name</key>
|
||||
<string>Mac Classic</string>
|
||||
<key>semanticClass</key>
|
||||
<string>theme.light.mac-classic</string>
|
||||
<key>settings</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#FFFFFF</string>
|
||||
<key>caret</key>
|
||||
<string>#000000</string>
|
||||
<key>foreground</key>
|
||||
<string>#000000</string>
|
||||
<key>invisibles</key>
|
||||
<string>#BFBFBF</string>
|
||||
<key>lineHighlight</key>
|
||||
<string>#00000012</string>
|
||||
<key>selection</key>
|
||||
<string>#4D97FF54</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Comment</string>
|
||||
<key>scope</key>
|
||||
<string>comment</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#0066FF</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Foldings</string>
|
||||
<key>scope</key>
|
||||
<string>deco.folding</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#BFBFBF</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Keyword</string>
|
||||
<key>scope</key>
|
||||
<string>keyword, storage</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
<key>foreground</key>
|
||||
<string>#0000FF</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Number</string>
|
||||
<key>scope</key>
|
||||
<string>constant.numeric</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#0000CD</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>User-defined constant</string>
|
||||
<key>scope</key>
|
||||
<string>constant</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
<key>foreground</key>
|
||||
<string>#C5060B</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Built-in constant</string>
|
||||
<key>scope</key>
|
||||
<string>constant.language</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
<key>foreground</key>
|
||||
<string>#585CF6</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Variable</string>
|
||||
<key>scope</key>
|
||||
<string>variable.language, variable.other</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#318495</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>String</string>
|
||||
<key>scope</key>
|
||||
<string>string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#036A07</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>String interpolation</string>
|
||||
<key>scope</key>
|
||||
<string>constant.character.escape, string meta.embedded</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#26B31A</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Preprocessor line</string>
|
||||
<key>scope</key>
|
||||
<string>meta.preprocessor</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#1A921C</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Preprocessor directive</string>
|
||||
<key>scope</key>
|
||||
<string>keyword.control.import</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
<key>foreground</key>
|
||||
<string>#0C450D</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Function name</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.function, support.function.any-method</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
<key>foreground</key>
|
||||
<string>#0000A2</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Type name</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.type</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>underline</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Inherited class name</string>
|
||||
<key>scope</key>
|
||||
<string>entity.other.inherited-class</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Function parameter</string>
|
||||
<key>scope</key>
|
||||
<string>variable.parameter</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Function argument and result types</string>
|
||||
<key>scope</key>
|
||||
<string>storage.type.method</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#70727E</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Section</string>
|
||||
<key>scope</key>
|
||||
<string>meta.section entity.name.section, declaration.section entity.name.section</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Library function</string>
|
||||
<key>scope</key>
|
||||
<string>support.function</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
<key>foreground</key>
|
||||
<string>#3C4C72</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Library object</string>
|
||||
<key>scope</key>
|
||||
<string>support.class, support.type</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
<key>foreground</key>
|
||||
<string>#6D79DE</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Library constant</string>
|
||||
<key>scope</key>
|
||||
<string>support.constant</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
<key>foreground</key>
|
||||
<string>#06960E</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Library variable</string>
|
||||
<key>scope</key>
|
||||
<string>support.variable</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
<key>foreground</key>
|
||||
<string>#21439C</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>JS: Operator</string>
|
||||
<key>scope</key>
|
||||
<string>keyword.operator.js</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#687687</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Invalid</string>
|
||||
<key>scope</key>
|
||||
<string>invalid</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#990000</string>
|
||||
<key>caret</key>
|
||||
<string>#FFFFFF</string>
|
||||
<key>foreground</key>
|
||||
<string>#FFFFFF</string>
|
||||
<key>selection</key>
|
||||
<string>#4D97FF</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Invalid trailing whitespace</string>
|
||||
<key>scope</key>
|
||||
<string>invalid.deprecated.trailing-whitespace</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#FFD0D0</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Embedded source</string>
|
||||
<key>scope</key>
|
||||
<string>text source, string.unquoted, meta.embedded</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#0000000D</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Embedded embedded source</string>
|
||||
<key>scope</key>
|
||||
<string>text source string.unquoted, text source text source</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>background</key>
|
||||
<string>#0000000F</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup XML declaration</string>
|
||||
<key>scope</key>
|
||||
<string>meta.tag.preprocessor.xml</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#68685B</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup DOCTYPE</string>
|
||||
<key>scope</key>
|
||||
<string>meta.tag.metadata.doctype, meta.tag.metadata.doctype entity, meta.tag.metadata.doctype string, meta.tag.metadata.processing.xml, meta.tag.metadata.processing.xml entity, meta.tag.metadata.processing.xml string</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#888888</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup DTD</string>
|
||||
<key>scope</key>
|
||||
<string>meta.tag.metadata.doctype string.quoted</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup tag</string>
|
||||
<key>scope</key>
|
||||
<string>meta.tag, declaration.tag</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string></string>
|
||||
<key>foreground</key>
|
||||
<string>#1C02FF</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup name of tag</string>
|
||||
<key>scope</key>
|
||||
<string>entity.name.tag</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup tag attribute</string>
|
||||
<key>scope</key>
|
||||
<string>entity.other.attribute-name</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: Heading</string>
|
||||
<key>scope</key>
|
||||
<string>markup.heading</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>bold</string>
|
||||
<key>foreground</key>
|
||||
<string>#0C07FF</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: Quote</string>
|
||||
<key>scope</key>
|
||||
<string>markup.quote</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>fontStyle</key>
|
||||
<string>italic</string>
|
||||
<key>foreground</key>
|
||||
<string>#000000</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Markup: List</string>
|
||||
<key>scope</key>
|
||||
<string>markup.list</string>
|
||||
<key>settings</key>
|
||||
<dict>
|
||||
<key>foreground</key>
|
||||
<string>#B90690</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
<key>uuid</key>
|
||||
<string>71D40D9D-AE48-11D9-920A-000D93589AF6</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -25,6 +25,7 @@ pub mod dock;
|
|||
pub mod drawer;
|
||||
pub mod dropdown;
|
||||
pub mod form;
|
||||
pub mod highlighter;
|
||||
pub mod history;
|
||||
pub mod indicator;
|
||||
pub mod input;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use std::ops::Range;
|
||||
|
||||
use gpui::{
|
||||
div, img, prelude::FluentBuilder as _, px, relative, rems, App, DefiniteLength, ElementId,
|
||||
FontStyle, FontWeight, Half, HighlightStyle, InteractiveElement as _, InteractiveText,
|
||||
IntoElement, Length, ObjectFit, ParentElement, RenderOnce, SharedString, SharedUri, Styled,
|
||||
StyledImage as _, StyledText, Window,
|
||||
div, img, prelude::FluentBuilder as _, px, relative, rems, AnyElement, App, DefiniteLength,
|
||||
ElementId, FontStyle, FontWeight, Half, HighlightStyle, InteractiveElement as _,
|
||||
InteractiveText, IntoElement, Length, ObjectFit, ParentElement, Rems, RenderOnce, SharedString,
|
||||
SharedUri, Styled, StyledImage as _, StyledText, Window,
|
||||
};
|
||||
use markdown::mdast;
|
||||
|
||||
use crate::{h_flex, v_flex, ActiveTheme as _, Icon, IconName};
|
||||
use crate::{h_flex, highlighter::Highlighter, v_flex, ActiveTheme as _, Icon, IconName};
|
||||
|
||||
use super::{utils::list_item_prefix, TextViewStyle};
|
||||
|
||||
|
|
@ -199,6 +199,28 @@ impl Paragraph {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct CodeBlock {
|
||||
code: SharedString,
|
||||
lang: Option<SharedString>,
|
||||
styles: Vec<(Range<usize>, HighlightStyle)>,
|
||||
}
|
||||
|
||||
impl CodeBlock {
|
||||
pub fn new(
|
||||
code: SharedString,
|
||||
lang: Option<SharedString>,
|
||||
text_view_style: &TextViewStyle,
|
||||
) -> Self {
|
||||
let highlight = Highlighter::new(
|
||||
lang.as_ref().map(|v| v.as_ref()),
|
||||
text_view_style.highlight_theme.as_ref(),
|
||||
);
|
||||
let styles = highlight.highlight(code.as_ref());
|
||||
Self { code, lang, styles }
|
||||
}
|
||||
}
|
||||
|
||||
/// Ref:
|
||||
/// https://ui.shadcn.com/docs/components/typography
|
||||
#[allow(unused)]
|
||||
|
|
@ -224,10 +246,7 @@ pub enum Node {
|
|||
/// Whether the list item is checked, if None, it's not a checkbox
|
||||
checked: Option<bool>,
|
||||
},
|
||||
CodeBlock {
|
||||
code: SharedString,
|
||||
lang: Option<SharedString>,
|
||||
},
|
||||
CodeBlock(CodeBlock),
|
||||
Table(Table),
|
||||
Break {
|
||||
html: bool,
|
||||
|
|
@ -548,6 +567,24 @@ impl Node {
|
|||
}
|
||||
}
|
||||
|
||||
fn render_codeblock(
|
||||
code_block: CodeBlock,
|
||||
mb: Rems,
|
||||
_: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> AnyElement {
|
||||
div()
|
||||
.mb(mb)
|
||||
.p_3()
|
||||
.rounded(cx.theme().radius)
|
||||
.bg(cx.theme().secondary)
|
||||
.font_family("Menlo, Monaco, Consolas, monospace")
|
||||
.text_size(rems(0.875))
|
||||
.relative()
|
||||
.child(StyledText::new(code_block.code.clone()).with_highlights(code_block.styles))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
pub(crate) fn render(
|
||||
self,
|
||||
list_state: Option<ListState>,
|
||||
|
|
@ -634,15 +671,7 @@ impl Node {
|
|||
items
|
||||
})
|
||||
.into_any_element(),
|
||||
Node::CodeBlock { code, .. } => div()
|
||||
.mb(mb)
|
||||
.rounded(cx.theme().radius)
|
||||
.bg(cx.theme().secondary)
|
||||
.p_3()
|
||||
.text_size(rems(0.875))
|
||||
.relative()
|
||||
.child(code)
|
||||
.into_any_element(),
|
||||
Node::CodeBlock(code_block) => Self::render_codeblock(code_block, mb, window, cx),
|
||||
Node::Table { .. } => Self::render_table(&self, window, cx).into_any_element(),
|
||||
Node::Divider => div()
|
||||
.bg(cx.theme().border)
|
||||
|
|
@ -765,8 +794,12 @@ impl Node {
|
|||
.join("\n")
|
||||
)
|
||||
}
|
||||
Node::CodeBlock { code, lang } => {
|
||||
format!("```{}\n{}\n```", lang.clone().unwrap_or_default(), code)
|
||||
Node::CodeBlock(code_block) => {
|
||||
format!(
|
||||
"```{}\n{}\n```",
|
||||
code_block.lang.clone().unwrap_or_default(),
|
||||
code_block.code
|
||||
)
|
||||
}
|
||||
Node::Table(table) => {
|
||||
let header = table
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ use markdown::{
|
|||
use crate::v_flex;
|
||||
|
||||
use super::{
|
||||
element::{self, ImageNode, InlineTextStyle, LinkMark, Paragraph, Span, Table, TableRow},
|
||||
element::{
|
||||
self, CodeBlock, ImageNode, InlineTextStyle, LinkMark, Paragraph, Span, Table, TableRow,
|
||||
},
|
||||
html::parse_html,
|
||||
TextViewStyle,
|
||||
};
|
||||
|
|
@ -54,18 +56,20 @@ impl MarkdownElement {
|
|||
pub struct MarkdownState {
|
||||
raw: SharedString,
|
||||
root: Option<Result<element::Node, SharedString>>,
|
||||
style: TextViewStyle,
|
||||
}
|
||||
|
||||
impl MarkdownState {
|
||||
fn parse_if_needed(&mut self, new_text: SharedString) {
|
||||
let is_changed = self.raw != new_text;
|
||||
fn parse_if_needed(&mut self, new_text: SharedString, style: &TextViewStyle) {
|
||||
let is_changed = self.raw != new_text || self.style != *style;
|
||||
|
||||
if self.root.is_some() && !is_changed {
|
||||
return;
|
||||
}
|
||||
|
||||
self.raw = new_text;
|
||||
self.root = Some(parse_markdown(&self.raw));
|
||||
self.root = Some(parse_markdown(&self.raw, &style));
|
||||
self.style = style.clone();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +97,7 @@ impl Element for MarkdownElement {
|
|||
) -> (gpui::LayoutId, Self::RequestLayoutState) {
|
||||
window.with_element_state(id.unwrap(), |state, window| {
|
||||
let mut state: MarkdownState = state.unwrap_or_default();
|
||||
state.parse_if_needed(self.text.clone());
|
||||
state.parse_if_needed(self.text.clone(), &self.style);
|
||||
|
||||
let root = state
|
||||
.root
|
||||
|
|
@ -143,9 +147,9 @@ impl Element for MarkdownElement {
|
|||
}
|
||||
|
||||
/// Parse Markdown into a tree of nodes.
|
||||
fn parse_markdown(raw: &str) -> Result<element::Node, SharedString> {
|
||||
fn parse_markdown(raw: &str, style: &TextViewStyle) -> Result<element::Node, SharedString> {
|
||||
markdown::to_mdast(&raw, &ParseOptions::gfm())
|
||||
.map(|n| n.into())
|
||||
.map(|n| ast_to_node(n, style))
|
||||
.map_err(|e| e.to_string().into())
|
||||
}
|
||||
|
||||
|
|
@ -335,137 +339,144 @@ fn parse_paragraph(paragraph: &mut Paragraph, node: &mdast::Node) -> String {
|
|||
text
|
||||
}
|
||||
|
||||
impl From<mdast::Node> for element::Node {
|
||||
fn from(value: Node) -> Self {
|
||||
match value {
|
||||
Node::Root(val) => {
|
||||
let children = val.children.into_iter().map(|c| c.into()).collect();
|
||||
element::Node::Root { children }
|
||||
}
|
||||
Node::Paragraph(val) => {
|
||||
let mut paragraph = Paragraph::default();
|
||||
val.children.iter().for_each(|c| {
|
||||
parse_paragraph(&mut paragraph, c);
|
||||
});
|
||||
fn ast_to_node(value: mdast::Node, style: &TextViewStyle) -> element::Node {
|
||||
match value {
|
||||
Node::Root(val) => {
|
||||
let children = val
|
||||
.children
|
||||
.into_iter()
|
||||
.map(|c| ast_to_node(c, style))
|
||||
.collect();
|
||||
element::Node::Root { children }
|
||||
}
|
||||
Node::Paragraph(val) => {
|
||||
let mut paragraph = Paragraph::default();
|
||||
val.children.iter().for_each(|c| {
|
||||
parse_paragraph(&mut paragraph, c);
|
||||
});
|
||||
|
||||
element::Node::Paragraph(paragraph)
|
||||
}
|
||||
Node::Blockquote(val) => {
|
||||
let mut paragraph = Paragraph::default();
|
||||
val.children.iter().for_each(|c| {
|
||||
parse_paragraph(&mut paragraph, c);
|
||||
});
|
||||
element::Node::Paragraph(paragraph)
|
||||
}
|
||||
Node::Blockquote(val) => {
|
||||
let mut paragraph = Paragraph::default();
|
||||
val.children.iter().for_each(|c| {
|
||||
parse_paragraph(&mut paragraph, c);
|
||||
});
|
||||
|
||||
element::Node::Blockquote(paragraph)
|
||||
element::Node::Blockquote(paragraph)
|
||||
}
|
||||
Node::List(list) => {
|
||||
let children = list
|
||||
.children
|
||||
.into_iter()
|
||||
.map(|c| ast_to_node(c, style))
|
||||
.collect();
|
||||
element::Node::List {
|
||||
ordered: list.ordered,
|
||||
children,
|
||||
}
|
||||
Node::List(list) => {
|
||||
let children = list.children.into_iter().map(|c| c.into()).collect();
|
||||
element::Node::List {
|
||||
ordered: list.ordered,
|
||||
children,
|
||||
}
|
||||
}
|
||||
Node::ListItem(val) => {
|
||||
let children = val
|
||||
.children
|
||||
.into_iter()
|
||||
.map(|c| ast_to_node(c, style))
|
||||
.collect();
|
||||
element::Node::ListItem {
|
||||
children,
|
||||
spread: val.spread,
|
||||
checked: val.checked,
|
||||
}
|
||||
Node::ListItem(val) => {
|
||||
let children = val.children.into_iter().map(|c| c.into()).collect();
|
||||
element::Node::ListItem {
|
||||
children,
|
||||
spread: val.spread,
|
||||
checked: val.checked,
|
||||
}
|
||||
}
|
||||
Node::Break(_) => element::Node::Break { html: false },
|
||||
Node::Code(raw) => element::Node::CodeBlock {
|
||||
code: raw.value.into(),
|
||||
lang: raw.lang.map(|s| s.into()),
|
||||
},
|
||||
Node::Heading(val) => {
|
||||
let mut paragraph = Paragraph::default();
|
||||
val.children.iter().for_each(|c| {
|
||||
parse_paragraph(&mut paragraph, c);
|
||||
});
|
||||
}
|
||||
Node::Break(_) => element::Node::Break { html: false },
|
||||
Node::Code(raw) => element::Node::CodeBlock(CodeBlock::new(
|
||||
raw.value.into(),
|
||||
raw.lang.map(|s| s.into()),
|
||||
style,
|
||||
)),
|
||||
Node::Heading(val) => {
|
||||
let mut paragraph = Paragraph::default();
|
||||
val.children.iter().for_each(|c| {
|
||||
parse_paragraph(&mut paragraph, c);
|
||||
});
|
||||
|
||||
element::Node::Heading {
|
||||
level: val.depth,
|
||||
children: paragraph,
|
||||
}
|
||||
element::Node::Heading {
|
||||
level: val.depth,
|
||||
children: paragraph,
|
||||
}
|
||||
Node::Math(val) => element::Node::CodeBlock {
|
||||
code: val.value.into(),
|
||||
lang: Some("math".into()),
|
||||
},
|
||||
Node::Html(val) => match parse_html(&val.value) {
|
||||
Ok(el) => el,
|
||||
Err(err) => {
|
||||
if cfg!(debug_assertions) {
|
||||
eprintln!("[markdown] error parsing html: {:#?}", err);
|
||||
}
|
||||
|
||||
element::Node::Paragraph(val.value.into())
|
||||
}
|
||||
},
|
||||
Node::MdxFlowExpression(val) => element::Node::CodeBlock {
|
||||
code: val.value.into(),
|
||||
lang: Some("mdx".into()),
|
||||
},
|
||||
Node::Yaml(val) => element::Node::CodeBlock {
|
||||
code: val.value.into(),
|
||||
lang: Some("yaml".into()),
|
||||
},
|
||||
Node::Toml(val) => element::Node::CodeBlock {
|
||||
code: val.value.into(),
|
||||
lang: Some("toml".into()),
|
||||
},
|
||||
Node::MdxJsxTextElement(val) => {
|
||||
println!("MdxJsxTextElement: {:#?}", val);
|
||||
let mut paragraph = Paragraph::default();
|
||||
val.children.iter().for_each(|c| {
|
||||
parse_paragraph(&mut paragraph, c);
|
||||
});
|
||||
element::Node::Paragraph(paragraph)
|
||||
}
|
||||
Node::MdxJsxFlowElement(val) => {
|
||||
println!("MdxJsxFlowElement: {:#?}", val);
|
||||
let mut paragraph = Paragraph::default();
|
||||
val.children.iter().for_each(|c| {
|
||||
parse_paragraph(&mut paragraph, c);
|
||||
});
|
||||
element::Node::Paragraph(paragraph)
|
||||
}
|
||||
Node::ThematicBreak(_) => element::Node::Divider,
|
||||
Node::Table(val) => {
|
||||
let mut table = Table::default();
|
||||
table.column_aligns = val
|
||||
.align
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|align| align.into())
|
||||
.collect();
|
||||
val.children.iter().for_each(|c| {
|
||||
if let Node::TableRow(row) = c {
|
||||
parse_table_row(&mut table, row);
|
||||
}
|
||||
});
|
||||
|
||||
element::Node::Table(table)
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
Node::Math(val) => element::Node::CodeBlock(CodeBlock::new(val.value.into(), None, style)),
|
||||
Node::Html(val) => match parse_html(&val.value) {
|
||||
Ok(el) => el,
|
||||
Err(err) => {
|
||||
if cfg!(debug_assertions) {
|
||||
eprintln!("[markdown] unsupported node: {:#?}", value);
|
||||
eprintln!("[markdown] error parsing html: {:#?}", err);
|
||||
}
|
||||
element::Node::Unknown
|
||||
|
||||
element::Node::Paragraph(val.value.into())
|
||||
}
|
||||
},
|
||||
Node::MdxFlowExpression(val) => {
|
||||
element::Node::CodeBlock(CodeBlock::new(val.value.into(), Some("mdx".into()), style))
|
||||
}
|
||||
Node::Yaml(val) => {
|
||||
element::Node::CodeBlock(CodeBlock::new(val.value.into(), Some("yml".into()), style))
|
||||
}
|
||||
Node::Toml(val) => {
|
||||
element::Node::CodeBlock(CodeBlock::new(val.value.into(), Some("toml".into()), style))
|
||||
}
|
||||
Node::MdxJsxTextElement(val) => {
|
||||
println!("MdxJsxTextElement: {:#?}", val);
|
||||
let mut paragraph = Paragraph::default();
|
||||
val.children.iter().for_each(|c| {
|
||||
parse_paragraph(&mut paragraph, c);
|
||||
});
|
||||
element::Node::Paragraph(paragraph)
|
||||
}
|
||||
Node::MdxJsxFlowElement(val) => {
|
||||
println!("MdxJsxFlowElement: {:#?}", val);
|
||||
let mut paragraph = Paragraph::default();
|
||||
val.children.iter().for_each(|c| {
|
||||
parse_paragraph(&mut paragraph, c);
|
||||
});
|
||||
element::Node::Paragraph(paragraph)
|
||||
}
|
||||
Node::ThematicBreak(_) => element::Node::Divider,
|
||||
Node::Table(val) => {
|
||||
let mut table = Table::default();
|
||||
table.column_aligns = val
|
||||
.align
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|align| align.into())
|
||||
.collect();
|
||||
val.children.iter().for_each(|c| {
|
||||
if let Node::TableRow(row) = c {
|
||||
parse_table_row(&mut table, row);
|
||||
}
|
||||
});
|
||||
|
||||
element::Node::Table(table)
|
||||
}
|
||||
_ => {
|
||||
if cfg!(debug_assertions) {
|
||||
eprintln!("[markdown] unsupported node: {:#?}", value);
|
||||
}
|
||||
element::Node::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::text::TextViewStyle;
|
||||
|
||||
use super::parse_markdown;
|
||||
|
||||
#[test]
|
||||
fn test_parse_br() {
|
||||
let raw = "Row 1<br/>Row 2<br>[Link](https://github.com)";
|
||||
let node = parse_markdown(&raw).unwrap();
|
||||
let node = parse_markdown(&raw, &TextViewStyle::default()).unwrap();
|
||||
assert_eq!(
|
||||
node.to_markdown(),
|
||||
"Row 1\nRow 2\n[Link](https://github.com)"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use gpui::{px, rems, App, ElementId, IntoElement, Pixels, Rems, RenderOnce, SharedString, Window};
|
||||
|
||||
use crate::highlighter::HighlightTheme;
|
||||
|
||||
use super::{html::HtmlElement, markdown::MarkdownElement};
|
||||
|
||||
/// A text view that can render Markdown or HTML.
|
||||
|
|
@ -65,12 +69,14 @@ impl RenderOnce for Text {
|
|||
}
|
||||
|
||||
/// TextViewStyle used to customize the style for [`TextView`].
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct TextViewStyle {
|
||||
/// Gap of each paragraphs, default is 1 rem.
|
||||
pub paragraph_gap: Rems,
|
||||
/// Base font size for headings, default is 14px.
|
||||
pub heading_base_font_size: Pixels,
|
||||
/// Highlight theme for code blocks. Default: [`HighlightTheme::default_light()`]
|
||||
pub highlight_theme: Rc<HighlightTheme>,
|
||||
}
|
||||
|
||||
impl Default for TextViewStyle {
|
||||
|
|
@ -78,6 +84,7 @@ impl Default for TextViewStyle {
|
|||
Self {
|
||||
paragraph_gap: rems(1.),
|
||||
heading_base_font_size: px(14.),
|
||||
highlight_theme: Rc::new(HighlightTheme::default_light()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -541,8 +541,9 @@ impl Theme {
|
|||
|
||||
impl From<ThemeColor> for Theme {
|
||||
fn from(colors: ThemeColor) -> Self {
|
||||
let mode = ThemeMode::default();
|
||||
Theme {
|
||||
mode: ThemeMode::default(),
|
||||
mode,
|
||||
transparent: Hsla::transparent_black(),
|
||||
font_size: px(16.),
|
||||
font_family: if cfg!(target_os = "macos") {
|
||||
|
|
|
|||
Loading…
Reference in a new issue