Compare commits

...
Sign in to create a new pull request.

8 commits

Author SHA1 Message Date
Joseph T. Lyons
b83baeae40 v0.98.x stable 2023-08-09 12:30:16 -04:00
Mikayla Maki
0be3cdaa83 Fix two mouse event bugs (#2835)
This PR fixes two bugs we discovered in Zed's mouse event handling while
investigating an interesting and mysterious bug we we were seeing, where
spurious `MouseMoved` events would continuously be dispatched after
control-clicking.

Release Notes:

- Fixed a rendering glitch that could occur after control-clicking
certain elements.
2023-08-09 12:13:38 -04:00
Max Brunsfeld
6cb8613a6f zed 0.98.2 2023-08-08 12:32:38 -07:00
Piotr Osiewicz
dff0d5898f Piotr/optimize search selections with a limit (#2831)
/cc @nathansobo @maxbrunsfeld 

Release Notes:
- Fixed scrollbar selections causing noticeable slowdowns with large
quantities of selections.
2023-08-08 12:32:09 -07:00
Max Brunsfeld
06ae1a5ec0 Make LspAdapter::process_diagnostics synchronous (#2829)
When editing rust code, the project diagnostics view sometimes fails to
update, so that you have to close the view and re-open it to see the
correct state.

This PR fixes one possible cause of that problem. There was an async
step in between *receiving* diagnostics from the language server and
updating the diagnostics, due to an async call to
`LspAdapter::process_diagnostics`. This could cause the following
sequence of events to happen:

1. Rust-analyzer sends us new diagnostics for a file `a.rs`
2. We call `process_diagnostics` with those diagnostics
3. Rust-analyzer sends us a `WorkDoneProgress` message, indicating that
the "flycheck" (aka `cargo check`) process has completed
4. We update the project diagnostics view due to this message.
5. The `process_diagnostics` call for `a.rs` completes
6. 💥 We have the new diagnostics for `a.rs`, but do not update the
project diagnostics view again.

This PR fixes this bug by simply making `process_diagnostics`
synchronous. There is no I/O or expensive computation happening in that
method. If we need to make it asynchronous in the future, we need to
introduce a queue that ensures that `publishDiagnostics` and
`workDoneProgress` messages are processed serially.

Release Notes:

- Fixed a bug where the project diagnostics view would sometimes fail to
update properly when using Rust-analyzer.
2023-08-07 14:32:26 -07:00
Max Brunsfeld
d6edcee989 zed 0.98.1 2023-08-02 12:20:57 -07:00
Max Brunsfeld
fa05c5422d Revert "Extract syntax highlighting properties from tree-sitter highlight queries (#2797)"
This reverts commit 45c635872b, reversing
changes made to f2b82369f2.
2023-08-02 12:19:31 -07:00
Joseph T. Lyons
8f7cdca729 v0.98.x preview 2023-08-02 13:50:08 -04:00
68 changed files with 683 additions and 713 deletions

2
Cargo.lock generated
View file

@ -9815,7 +9815,7 @@ dependencies = [
[[package]] [[package]]
name = "zed" name = "zed"
version = "0.98.0" version = "0.98.2"
dependencies = [ dependencies = [
"activity_indicator", "activity_indicator",
"ai", "ai",

View file

@ -89,7 +89,7 @@ use std::{
cmp::{self, Ordering, Reverse}, cmp::{self, Ordering, Reverse},
mem, mem,
num::NonZeroU32, num::NonZeroU32,
ops::{ControlFlow, Deref, DerefMut, Range}, ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
path::Path, path::Path,
sync::Arc, sync::Arc,
time::{Duration, Instant}, time::{Duration, Instant},
@ -7443,6 +7443,78 @@ impl Editor {
results results
} }
pub fn background_highlight_row_ranges<T: 'static>(
&self,
search_range: Range<Anchor>,
display_snapshot: &DisplaySnapshot,
count: usize,
) -> Vec<RangeInclusive<DisplayPoint>> {
let mut results = Vec::new();
let buffer = &display_snapshot.buffer_snapshot;
let Some((_, ranges)) = self.background_highlights
.get(&TypeId::of::<T>()) else {
return vec![];
};
let start_ix = match ranges.binary_search_by(|probe| {
let cmp = probe.end.cmp(&search_range.start, buffer);
if cmp.is_gt() {
Ordering::Greater
} else {
Ordering::Less
}
}) {
Ok(i) | Err(i) => i,
};
let mut push_region = |start: Option<Point>, end: Option<Point>| {
if let (Some(start_display), Some(end_display)) = (start, end) {
results.push(
start_display.to_display_point(display_snapshot)
..=end_display.to_display_point(display_snapshot),
);
}
};
let mut start_row: Option<Point> = None;
let mut end_row: Option<Point> = None;
if ranges.len() > count {
return vec![];
}
for range in &ranges[start_ix..] {
if range.start.cmp(&search_range.end, buffer).is_ge() {
break;
}
let end = range.end.to_point(buffer);
if let Some(current_row) = &end_row {
if end.row == current_row.row {
continue;
}
}
let start = range.start.to_point(buffer);
if start_row.is_none() {
assert_eq!(end_row, None);
start_row = Some(start);
end_row = Some(end);
continue;
}
if let Some(current_end) = end_row.as_mut() {
if start.row > current_end.row + 1 {
push_region(start_row, end_row);
start_row = Some(start);
end_row = Some(end);
} else {
// Merge two hunks.
*current_end = end;
}
} else {
unreachable!();
}
}
// We might still have a hunk that was not rendered (if there was a search hit on the last line)
push_region(start_row, end_row);
results
}
pub fn highlight_text<T: 'static>( pub fn highlight_text<T: 'static>(
&mut self, &mut self,
ranges: Vec<Range<Anchor>>, ranges: Vec<Range<Anchor>>,

View file

@ -1107,8 +1107,6 @@ impl EditorElement {
if layout.is_singleton && scrollbar_settings.selections { if layout.is_singleton && scrollbar_settings.selections {
let start_anchor = Anchor::min(); let start_anchor = Anchor::min();
let end_anchor = Anchor::max(); let end_anchor = Anchor::max();
let mut start_row = None;
let mut end_row = None;
let color = scrollbar_theme.selections; let color = scrollbar_theme.selections;
let border = Border { let border = Border {
width: 1., width: 1.,
@ -1119,54 +1117,32 @@ impl EditorElement {
bottom: false, bottom: false,
left: true, left: true,
}; };
let mut push_region = |start, end| { let mut push_region = |start: DisplayPoint, end: DisplayPoint| {
if let (Some(start_display), Some(end_display)) = (start, end) { let start_y = y_for_row(start.row() as f32);
let start_y = y_for_row(start_display as f32); let mut end_y = y_for_row(end.row() as f32);
let mut end_y = y_for_row(end_display as f32); if end_y - start_y < 1. {
if end_y - start_y < 1. { end_y = start_y + 1.;
end_y = start_y + 1.;
}
let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y));
scene.push_quad(Quad {
bounds,
background: Some(color),
border,
corner_radius: style.thumb.corner_radius,
})
} }
let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y));
scene.push_quad(Quad {
bounds,
background: Some(color),
border,
corner_radius: style.thumb.corner_radius,
})
}; };
for (row, _) in &editor let background_ranges = editor
.background_highlights_in_range_for::<crate::items::BufferSearchHighlights>( .background_highlight_row_ranges::<crate::items::BufferSearchHighlights>(
start_anchor..end_anchor, start_anchor..end_anchor,
&layout.position_map.snapshot, &layout.position_map.snapshot,
&theme, 50000,
) );
{ for row in background_ranges {
let start_display = row.start; let start = row.start();
let end_display = row.end; let end = row.end();
push_region(*start, *end);
if start_row.is_none() {
assert_eq!(end_row, None);
start_row = Some(start_display.row());
end_row = Some(end_display.row());
continue;
}
if let Some(current_end) = end_row.as_mut() {
if start_display.row() > *current_end + 1 {
push_region(start_row, end_row);
start_row = Some(start_display.row());
end_row = Some(end_display.row());
} else {
// Merge two hunks.
*current_end = end_display.row();
}
} else {
unreachable!();
}
} }
// We might still have a hunk that was not rendered (if there was a search hit on the last line)
push_region(start_row, end_row);
} }
if layout.is_singleton && scrollbar_settings.git_diff { if layout.is_singleton && scrollbar_settings.git_diff {

View file

@ -51,8 +51,8 @@ pub struct Window {
cursor_regions: Vec<CursorRegion>, cursor_regions: Vec<CursorRegion>,
mouse_regions: Vec<(MouseRegion, usize)>, mouse_regions: Vec<(MouseRegion, usize)>,
last_mouse_moved_event: Option<Event>, last_mouse_moved_event: Option<Event>,
pub(crate) hovered_region_ids: HashSet<MouseRegionId>, pub(crate) hovered_region_ids: Vec<MouseRegionId>,
pub(crate) clicked_region_ids: HashSet<MouseRegionId>, pub(crate) clicked_region_ids: Vec<MouseRegionId>,
pub(crate) clicked_region: Option<(MouseRegionId, MouseButton)>, pub(crate) clicked_region: Option<(MouseRegionId, MouseButton)>,
mouse_position: Vector2F, mouse_position: Vector2F,
text_layout_cache: TextLayoutCache, text_layout_cache: TextLayoutCache,
@ -658,6 +658,7 @@ impl<'a> WindowContext<'a> {
let mut highest_z_index = None; let mut highest_z_index = None;
let mouse_position = self.window.mouse_position.clone(); let mouse_position = self.window.mouse_position.clone();
let window = &mut *self.window; let window = &mut *self.window;
let prev_hovered_regions = mem::take(&mut window.hovered_region_ids);
for (region, z_index) in window.mouse_regions.iter().rev() { for (region, z_index) in window.mouse_regions.iter().rev() {
// Allow mouse regions to appear transparent to hovers // Allow mouse regions to appear transparent to hovers
if !region.hoverable { if !region.hoverable {
@ -676,7 +677,11 @@ impl<'a> WindowContext<'a> {
// highest_z_index is set. // highest_z_index is set.
if contains_mouse && z_index == highest_z_index.unwrap() { if contains_mouse && z_index == highest_z_index.unwrap() {
//Ensure that hover entrance events aren't sent twice //Ensure that hover entrance events aren't sent twice
if window.hovered_region_ids.insert(region.id()) { if let Err(ix) = window.hovered_region_ids.binary_search(&region.id()) {
window.hovered_region_ids.insert(ix, region.id());
}
// window.hovered_region_ids.insert(region.id());
if !prev_hovered_regions.contains(&region.id()) {
valid_regions.push(region.clone()); valid_regions.push(region.clone());
if region.notify_on_hover { if region.notify_on_hover {
notified_views.insert(region.id().view_id()); notified_views.insert(region.id().view_id());
@ -684,7 +689,7 @@ impl<'a> WindowContext<'a> {
} }
} else { } else {
// Ensure that hover exit events aren't sent twice // Ensure that hover exit events aren't sent twice
if window.hovered_region_ids.remove(&region.id()) { if prev_hovered_regions.contains(&region.id()) {
valid_regions.push(region.clone()); valid_regions.push(region.clone());
if region.notify_on_hover { if region.notify_on_hover {
notified_views.insert(region.id().view_id()); notified_views.insert(region.id().view_id());

View file

@ -1086,7 +1086,10 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
button: MouseButton::Left, button: MouseButton::Left,
modifiers: Modifiers { ctrl: true, .. }, modifiers: Modifiers { ctrl: true, .. },
.. ..
}) => return, }) => {
window_state_borrow.synthetic_drag_counter += 1;
return;
}
_ => None, _ => None,
}; };

View file

@ -177,7 +177,7 @@ impl MouseRegion {
} }
} }
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
pub struct MouseRegionId { pub struct MouseRegionId {
view_id: usize, view_id: usize,
tag: TypeId, tag: TypeId,

View file

@ -182,8 +182,8 @@ impl CachedLspAdapter {
self.adapter.workspace_configuration(cx) self.adapter.workspace_configuration(cx)
} }
pub async fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) { pub fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
self.adapter.process_diagnostics(params).await self.adapter.process_diagnostics(params)
} }
pub async fn process_completion(&self, completion_item: &mut lsp::CompletionItem) { pub async fn process_completion(&self, completion_item: &mut lsp::CompletionItem) {
@ -262,7 +262,7 @@ pub trait LspAdapter: 'static + Send + Sync {
container_dir: PathBuf, container_dir: PathBuf,
) -> Option<LanguageServerBinary>; ) -> Option<LanguageServerBinary>;
async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
async fn process_completion(&self, _: &mut lsp::CompletionItem) {} async fn process_completion(&self, _: &mut lsp::CompletionItem) {}
@ -1487,12 +1487,6 @@ impl Language {
None None
} }
pub async fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams) {
for adapter in &self.adapters {
adapter.process_diagnostics(diagnostics).await;
}
}
pub async fn process_completion(self: &Arc<Self>, completion: &mut lsp::CompletionItem) { pub async fn process_completion(self: &Arc<Self>, completion: &mut lsp::CompletionItem) {
for adapter in &self.adapters { for adapter in &self.adapters {
adapter.process_completion(completion).await; adapter.process_completion(completion).await;
@ -1756,7 +1750,7 @@ impl LspAdapter for Arc<FakeLspAdapter> {
unreachable!(); unreachable!();
} }
async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
async fn disk_based_diagnostic_sources(&self) -> Vec<String> { async fn disk_based_diagnostic_sources(&self) -> Vec<String> {
self.disk_based_diagnostics_sources.clone() self.disk_based_diagnostics_sources.clone()

View file

@ -2769,24 +2769,21 @@ impl Project {
language_server language_server
.on_notification::<lsp::notification::PublishDiagnostics, _>({ .on_notification::<lsp::notification::PublishDiagnostics, _>({
let adapter = adapter.clone(); let adapter = adapter.clone();
move |mut params, cx| { move |mut params, mut cx| {
let this = this; let this = this;
let adapter = adapter.clone(); let adapter = adapter.clone();
cx.spawn(|mut cx| async move { adapter.process_diagnostics(&mut params);
adapter.process_diagnostics(&mut params).await; if let Some(this) = this.upgrade(&cx) {
if let Some(this) = this.upgrade(&cx) { this.update(&mut cx, |this, cx| {
this.update(&mut cx, |this, cx| { this.update_diagnostics(
this.update_diagnostics( server_id,
server_id, params,
params, &adapter.disk_based_diagnostic_sources,
&adapter.disk_based_diagnostic_sources, cx,
cx, )
) .log_err();
.log_err(); });
}); }
}
})
.detach();
} }
}) })
.detach(); .detach();

View file

@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathansobo@gmail.com>"]
description = "The fast, collaborative code editor." description = "The fast, collaborative code editor."
edition = "2021" edition = "2021"
name = "zed" name = "zed"
version = "0.98.0" version = "0.98.2"
publish = false publish = false
[lib] [lib]

View file

@ -1 +1 @@
dev stable

View file

@ -54,5 +54,5 @@
( (
(command (_) @constant) (command (_) @constant)
(.match? @constant "^-") (#match? @constant "^-")
) )

View file

@ -86,7 +86,7 @@
(identifier) @variable (identifier) @variable
((identifier) @constant ((identifier) @constant
(.match? @constant "^_*[A-Z][A-Z\\d_]*$")) (#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
(call_expression (call_expression
function: (identifier) @function) function: (identifier) @function)
@ -106,3 +106,4 @@
(primitive_type) (primitive_type)
(sized_type_specifier) (sized_type_specifier)
] @type ] @type

View file

@ -1,7 +1,7 @@
(preproc_def (preproc_def
value: (preproc_arg) @content value: (preproc_arg) @content
(.set! "language" "c")) (#set! "language" "c"))
(preproc_function_def (preproc_function_def
value: (preproc_arg) @content value: (preproc_arg) @content
(.set! "language" "c")) (#set! "language" "c"))

View file

@ -31,13 +31,13 @@
declarator: (field_identifier) @function) declarator: (field_identifier) @function)
((namespace_identifier) @type ((namespace_identifier) @type
(.match? @type "^[A-Z]")) (#match? @type "^[A-Z]"))
(auto) @type (auto) @type
(type_identifier) @type (type_identifier) @type
((identifier) @constant ((identifier) @constant
(.match? @constant "^_*[A-Z][A-Z\\d_]*$")) (#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
(field_identifier) @property (field_identifier) @property
(statement_identifier) @label (statement_identifier) @label

View file

@ -1,7 +1,7 @@
(preproc_def (preproc_def
value: (preproc_arg) @content value: (preproc_arg) @content
(.set! "language" "c++")) (#set! "language" "c++"))
(preproc_function_def (preproc_function_def
value: (preproc_arg) @content value: (preproc_arg) @content
(.set! "language" "c++")) (#set! "language" "c++"))

View file

@ -46,7 +46,7 @@
(property_name) (property_name)
(plain_value) (plain_value)
] @variable.special ] @variable.special
(.match? @variable.special "^--") (#match? @variable.special "^--")
) )
[ [

View file

@ -3,7 +3,7 @@
operator: "@" operator: "@"
operand: (call operand: (call
target: (identifier) @unary target: (identifier) @unary
(.match? @unary "^(doc)$")) (#match? @unary "^(doc)$"))
) @context ) @context
. .
(call (call
@ -18,10 +18,10 @@
target: (identifier) @name) target: (identifier) @name)
operator: "when") operator: "when")
]) ])
(.match? @name "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item (#match? @name "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item
) )
(call (call
target: (identifier) @name target: (identifier) @name
(arguments (alias) @name) (arguments (alias) @name)
(.match? @name "^(defmodule|defprotocol)$")) @item (#match? @name "^(defmodule|defprotocol)$")) @item

View file

@ -54,13 +54,13 @@
(sigil_name) @__name__ (sigil_name) @__name__
quoted_start: _ @string quoted_start: _ @string
quoted_end: _ @string quoted_end: _ @string
(.match? @__name__ "^[sS]$")) @string (#match? @__name__ "^[sS]$")) @string
(sigil (sigil
(sigil_name) @__name__ (sigil_name) @__name__
quoted_start: _ @string.regex quoted_start: _ @string.regex
quoted_end: _ @string.regex quoted_end: _ @string.regex
(.match? @__name__ "^[rR]$")) @string.regex (#match? @__name__ "^[rR]$")) @string.regex
(sigil (sigil
(sigil_name) @__name__ (sigil_name) @__name__
@ -69,7 +69,7 @@
( (
(identifier) @comment.unused (identifier) @comment.unused
(.match? @comment.unused "^_") (#match? @comment.unused "^_")
) )
(call (call
@ -91,7 +91,7 @@
operator: "|>" operator: "|>"
right: (identifier)) right: (identifier))
]) ])
(.match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$")) (#match? @keyword "^(def|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp|defp)$"))
(binary_operator (binary_operator
operator: "|>" operator: "|>"
@ -99,15 +99,15 @@
(call (call
target: (identifier) @keyword target: (identifier) @keyword
(.match? @keyword "^(def|defdelegate|defexception|defguard|defguardp|defimpl|defmacro|defmacrop|defmodule|defn|defnp|defoverridable|defp|defprotocol|defstruct)$")) (#match? @keyword "^(def|defdelegate|defexception|defguard|defguardp|defimpl|defmacro|defmacrop|defmodule|defn|defnp|defoverridable|defp|defprotocol|defstruct)$"))
(call (call
target: (identifier) @keyword target: (identifier) @keyword
(.match? @keyword "^(alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$")) (#match? @keyword "^(alias|case|cond|else|for|if|import|quote|raise|receive|require|reraise|super|throw|try|unless|unquote|unquote_splicing|use|with)$"))
( (
(identifier) @constant.builtin (identifier) @constant.builtin
(.match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$") (#match? @constant.builtin "^(__MODULE__|__DIR__|__ENV__|__CALLER__|__STACKTRACE__)$")
) )
(unary_operator (unary_operator
@ -121,7 +121,7 @@
(sigil) (sigil)
(boolean) (boolean)
] @comment.doc)) ] @comment.doc))
(.match? @__attribute__ "^(moduledoc|typedoc|doc)$")) (#match? @__attribute__ "^(moduledoc|typedoc|doc)$"))
(comment) @comment (comment) @comment
@ -150,4 +150,4 @@
((sigil ((sigil
(sigil_name) @_sigil_name (sigil_name) @_sigil_name
(quoted_content) @embedded) (quoted_content) @embedded)
(.eq? @_sigil_name "H")) (#eq? @_sigil_name "H"))

View file

@ -3,5 +3,5 @@
((sigil ((sigil
(sigil_name) @_sigil_name (sigil_name) @_sigil_name
(quoted_content) @content) (quoted_content) @content)
(.eq? @_sigil_name "H") (#eq? @_sigil_name "H")
(.set! language "heex")) (#set! language "heex"))

View file

@ -1,7 +1,7 @@
(call (call
target: (identifier) @context target: (identifier) @context
(arguments (alias) @name) (arguments (alias) @name)
(.match? @context "^(defmodule|defprotocol)$")) @item (#match? @context "^(defmodule|defprotocol)$")) @item
(call (call
target: (identifier) @context target: (identifier) @context
@ -23,4 +23,4 @@
")" @context.extra)) ")" @context.extra))
operator: "when") operator: "when")
]) ])
(.match? @context "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item (#match? @context "^(def|defp|defdelegate|defguard|defguardp|defmacro|defmacrop|defn|defnp)$")) @item

View file

@ -1,2 +1,2 @@
((glsl_content) @content ((glsl_content) @content
(.set! "language" "glsl")) (#set! "language" "glsl"))

View file

@ -1,7 +1,7 @@
((code) @content ((code) @content
(.set! "language" "ruby") (#set! "language" "ruby")
(.set! "combined")) (#set! "combined"))
((content) @content ((content) @content
(.set! "language" "html") (#set! "language" "html")
(.set! "combined")) (#set! "combined"))

View file

@ -74,7 +74,7 @@
(sized_type_specifier) @type (sized_type_specifier) @type
((identifier) @constant ((identifier) @constant
(.match? @constant "^[A-Z][A-Z\\d_]*$")) (#match? @constant "^[A-Z][A-Z\\d_]*$"))
(identifier) @variable (identifier) @variable
@ -114,5 +114,5 @@
( (
(identifier) @variable.builtin (identifier) @variable.builtin
(.match? @variable.builtin "^gl_") (#match? @variable.builtin "^gl_")
) )

View file

@ -5,9 +5,9 @@
(expression_value) (expression_value)
(ending_expression_value) (ending_expression_value)
] @content) ] @content)
(.set! language "elixir") (#set! language "elixir")
(.set! combined) (#set! combined)
) )
((expression (expression_value) @content) ((expression (expression_value) @content)
(.set! language "elixir")) (#set! language "elixir"))

View file

@ -1,7 +1,7 @@
(script_element (script_element
(raw_text) @content (raw_text) @content
(.set! "language" "javascript")) (#set! "language" "javascript"))
(style_element (style_element
(raw_text) @content (raw_text) @content
(.set! "language" "css")) (#set! "language" "css"))

View file

@ -44,7 +44,7 @@
; Special identifiers ; Special identifiers
((identifier) @type ((identifier) @type
(.match? @type "^[A-Z]")) (#match? @type "^[A-Z]"))
(type_identifier) @type (type_identifier) @type
(predefined_type) @type.builtin (predefined_type) @type.builtin
@ -53,7 +53,7 @@
(shorthand_property_identifier) (shorthand_property_identifier)
(shorthand_property_identifier_pattern) (shorthand_property_identifier_pattern)
] @constant ] @constant
(.match? @constant "^_*[A-Z_][A-Z\\d_]*$")) (#match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
; Literals ; Literals
@ -214,4 +214,4 @@
"type" "type"
"readonly" "readonly"
"override" "override"
] @keyword ] @keyword

View file

@ -127,7 +127,7 @@
(identifier) @variable (identifier) @variable
((identifier) @variable.special ((identifier) @variable.special
(.eq? @variable.special "self")) (#eq? @variable.special "self"))
(variable_list (variable_list
attribute: (attribute attribute: (attribute
@ -137,7 +137,7 @@
;; Constants ;; Constants
((identifier) @constant ((identifier) @constant
(.match? @constant "^[A-Z][A-Z_0-9]*$")) (#match? @constant "^[A-Z][A-Z_0-9]*$"))
(vararg_expression) @constant (vararg_expression) @constant
@ -158,7 +158,7 @@
[ [
"{" "{"
"}" "}"
] @method.constructor) ] @constructor)
;; Functions ;; Functions
@ -180,7 +180,7 @@
(function_call (function_call
(identifier) @function.builtin (identifier) @function.builtin
(.any-of? @function.builtin (#any-of? @function.builtin
;; built-in functions in Lua 5.1 ;; built-in functions in Lua 5.1
"assert" "collectgarbage" "dofile" "error" "getfenv" "getmetatable" "ipairs" "assert" "collectgarbage" "dofile" "error" "getfenv" "getmetatable" "ipairs"
"load" "loadfile" "loadstring" "module" "next" "pairs" "pcall" "print" "load" "loadfile" "loadstring" "module" "next" "pairs" "pcall" "print"
@ -195,4 +195,4 @@
(number) @number (number) @number
(string) @string (string) @string

View file

@ -43,15 +43,15 @@
(relative_scope) @variable.builtin (relative_scope) @variable.builtin
((name) @constant ((name) @constant
(.match? @constant "^_?[A-Z][A-Z\\d_]+$")) (#match? @constant "^_?[A-Z][A-Z\\d_]+$"))
((name) @constant.builtin ((name) @constant.builtin
(.match? @constant.builtin "^__[A-Z][A-Z\d_]+__$")) (#match? @constant.builtin "^__[A-Z][A-Z\d_]+__$"))
((name) @method.constructor ((name) @constructor
(.match? @method.constructor "^[A-Z]")) (#match? @constructor "^[A-Z]"))
((name) @variable.builtin ((name) @variable.builtin
(.eq? @variable.builtin "this")) (#eq? @variable.builtin "this"))
(variable_name) @variable (variable_name) @variable

View file

@ -1,3 +1,3 @@
((text) @content ((text) @content
(.set! "language" "html") (#set! "language" "html")
(.set! "combined")) (#set! "combined"))

View file

@ -18,16 +18,16 @@
; Identifier naming conventions ; Identifier naming conventions
((identifier) @type ((identifier) @type
(.match? @type "^[A-Z]")) (#match? @type "^[A-Z]"))
((identifier) @constant ((identifier) @constant
(.match? @constant "^_*[A-Z][A-Z\\d_]*$")) (#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
; Builtin functions ; Builtin functions
((call ((call
function: (identifier) @function.builtin) function: (identifier) @function.builtin)
(.match? (#match?
@function.builtin @function.builtin
"^(abs|all|any|ascii|bin|bool|breakpoint|bytearray|bytes|callable|chr|classmethod|compile|complex|delattr|dict|dir|divmod|enumerate|eval|exec|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|isinstance|issubclass|iter|len|list|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|vars|zip|__import__)$")) "^(abs|all|any|ascii|bin|bool|breakpoint|bytearray|bytes|callable|chr|classmethod|compile|complex|delattr|dict|dir|divmod|enumerate|eval|exec|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|isinstance|issubclass|iter|len|list|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|vars|zip|__import__)$"))
@ -122,4 +122,4 @@
"yield" "yield"
"match" "match"
"case" "case"
] @keyword ] @keyword

File diff suppressed because one or more lines are too long

View file

@ -6,5 +6,5 @@
(symbol) @name (symbol) @name
(list . (symbol) @name) (list . (symbol) @name)
] ]
(.match? @start-symbol "^define") (#match? @start-symbol "^define")
) @item ) @item

View file

@ -11,4 +11,4 @@
(begin "begin" @open "end" @close) (begin "begin" @open "end" @close)
(module "module" @open "end" @close) (module "module" @open "end" @close)
(_ . "def" @open "end" @close) (_ . "def" @open "end" @close)
(_ . "class" @open "end" @close) (_ . "class" @open "end" @close)

View file

@ -33,12 +33,12 @@
(identifier) @variable (identifier) @variable
((identifier) @keyword ((identifier) @keyword
(.match? @keyword "^(private|protected|public)$")) (#match? @keyword "^(private|protected|public)$"))
; Function calls ; Function calls
((identifier) @function.method.builtin ((identifier) @function.method.builtin
(.eq? @function.method.builtin "require")) (#eq? @function.method.builtin "require"))
"defined?" @function.method.builtin "defined?" @function.method.builtin
@ -60,7 +60,7 @@
] @property ] @property
((identifier) @constant.builtin ((identifier) @constant.builtin
(.match? @constant.builtin "^__(FILE|LINE|ENCODING)__$")) (#match? @constant.builtin "^__(FILE|LINE|ENCODING)__$"))
(file) @constant.builtin (file) @constant.builtin
(line) @constant.builtin (line) @constant.builtin
@ -71,7 +71,7 @@
) @constant.builtin ) @constant.builtin
((constant) @constant ((constant) @constant
(.match? @constant "^[A-Z\\d_]+$")) (#match? @constant "^[A-Z\\d_]+$"))
(constant) @type (constant) @type

View file

@ -102,7 +102,7 @@ impl LspAdapter for RustLspAdapter {
Some("rust-analyzer/flycheck".into()) Some("rust-analyzer/flycheck".into())
} }
async fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) { fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
lazy_static! { lazy_static! {
static ref REGEX: Regex = Regex::new("(?m)`([^`]+)\n`$").unwrap(); static ref REGEX: Regex = Regex::new("(?m)`([^`]+)\n`$").unwrap();
} }
@ -310,7 +310,7 @@ mod tests {
}, },
], ],
}; };
RustLspAdapter.process_diagnostics(&mut params).await; RustLspAdapter.process_diagnostics(&mut params);
assert_eq!(params.diagnostics[0].message, "use of moved value `a`"); assert_eq!(params.diagnostics[0].message, "use of moved value `a`");

View file

@ -38,11 +38,11 @@
; Assume uppercase names are types/enum-constructors ; Assume uppercase names are types/enum-constructors
((identifier) @type ((identifier) @type
(.match? @type "^[A-Z]")) (#match? @type "^[A-Z]"))
; Assume all-caps names are constants ; Assume all-caps names are constants
((identifier) @constant ((identifier) @constant
(.match? @constant "^_*[A-Z][A-Z\\d_]*$")) (#match? @constant "^_*[A-Z][A-Z\\d_]*$"))
[ [
"(" "("

View file

@ -1,7 +1,7 @@
(macro_invocation (macro_invocation
(token_tree) @content (token_tree) @content
(.set! "language" "rust")) (#set! "language" "rust"))
(macro_rule (macro_rule
(token_tree) @content (token_tree) @content
(.set! "language" "rust")) (#set! "language" "rust"))

View file

@ -14,7 +14,7 @@
(directive)] @comment (directive)] @comment
((symbol) @operator ((symbol) @operator
(.match? @operator "^(\\+|-|\\*|/|=|>|<|>=|<=)$")) (#match? @operator "^(\\+|-|\\*|/|=|>|<|>=|<=)$"))
(list (list
. .
@ -23,6 +23,6 @@
(list (list
. .
(symbol) @keyword (symbol) @keyword
(.match? @keyword (#match? @keyword
"^(define-syntax|let\\*|lambda|λ|case|=>|quote-splicing|unquote-splicing|set!|let|letrec|letrec-syntax|let-values|let\\*-values|do|else|define|cond|syntax-rules|unquote|begin|quote|let-syntax|and|if|quasiquote|letrec|delay|or|when|unless|identifier-syntax|assert|library|export|import|rename|only|except|prefix)$" "^(define-syntax|let\\*|lambda|λ|case|=>|quote-splicing|unquote-splicing|set!|let|letrec|letrec-syntax|let-values|let\\*-values|do|else|define|cond|syntax-rules|unquote|begin|quote|let-syntax|and|if|quasiquote|letrec|delay|or|when|unless|identifier-syntax|assert|library|export|import|rename|only|except|prefix)$"
)) ))

View file

@ -6,5 +6,5 @@
(symbol) @name (symbol) @name
(list . (symbol) @name) (list . (symbol) @name)
] ]
(.match? @start-symbol "^define") (#match? @start-symbol "^define")
) @item ) @item

View file

@ -2,27 +2,27 @@
; -------------- ; --------------
(script_element (script_element
(raw_text) @content (raw_text) @content
(.set! "language" "javascript")) (#set! "language" "javascript"))
((script_element ((script_element
(start_tag (start_tag
(attribute (attribute
(quoted_attribute_value (attribute_value) @_language))) (quoted_attribute_value (attribute_value) @_language)))
(raw_text) @content) (raw_text) @content)
(.eq? @_language "ts") (#eq? @_language "ts")
(.set! "language" "typescript")) (#set! "language" "typescript"))
((script_element ((script_element
(start_tag (start_tag
(attribute (attribute
(quoted_attribute_value (attribute_value) @_language))) (quoted_attribute_value (attribute_value) @_language)))
(raw_text) @content) (raw_text) @content)
(.eq? @_language "typescript") (#eq? @_language "typescript")
(.set! "language" "typescript")) (#set! "language" "typescript"))
(style_element (style_element
(raw_text) @content (raw_text) @content
(.set! "language" "css")) (#set! "language" "css"))
((raw_text_expr) @content ((raw_text_expr) @content
(.set! "language" "javascript")) (#set! "language" "javascript"))

View file

@ -43,11 +43,11 @@
; Special identifiers ; Special identifiers
((identifier) @method.constructor ((identifier) @constructor
(.match? @method.constructor "^[A-Z]")) (#match? @constructor "^[A-Z]"))
((identifier) @type ((identifier) @type
(.match? @type "^[A-Z]")) (#match? @type "^[A-Z]"))
(type_identifier) @type (type_identifier) @type
(predefined_type) @type.builtin (predefined_type) @type.builtin
@ -56,7 +56,7 @@
(shorthand_property_identifier) (shorthand_property_identifier)
(shorthand_property_identifier_pattern) (shorthand_property_identifier_pattern)
] @constant ] @constant
(.match? @constant "^_*[A-Z_][A-Z\\d_]*$")) (#match? @constant "^_*[A-Z_][A-Z\\d_]*$"))
; Literals ; Literals
@ -218,4 +218,4 @@
"type" "type"
"readonly" "readonly"
"override" "override"
] @keyword ] @keyword

View file

@ -8,7 +8,6 @@
"build-licenses": "ts-node ./src/build_licenses.ts", "build-licenses": "ts-node ./src/build_licenses.ts",
"build-tokens": "ts-node ./src/build_tokens.ts", "build-tokens": "ts-node ./src/build_tokens.ts",
"build-types": "ts-node ./src/build_types.ts", "build-types": "ts-node ./src/build_types.ts",
"generate-syntax": "ts-node ./src/types/extract_syntax_types.ts",
"test": "vitest" "test": "vitest"
}, },
"author": "Zed Industries (https://github.com/zed-industries/)", "author": "Zed Industries (https://github.com/zed-industries/)",

View file

@ -21,7 +21,9 @@ function clear_themes(theme_directory: string) {
} }
} }
const all_themes: Theme[] = themes.map((theme) => create_theme(theme)) const all_themes: Theme[] = themes.map((theme) =>
create_theme(theme)
)
function write_themes(themes: Theme[], output_directory: string) { function write_themes(themes: Theme[], output_directory: string) {
clear_themes(output_directory) clear_themes(output_directory)
@ -32,7 +34,10 @@ function write_themes(themes: Theme[], output_directory: string) {
const style_tree = app() const style_tree = app()
const style_tree_json = JSON.stringify(style_tree, null, 2) const style_tree_json = JSON.stringify(style_tree, null, 2)
const temp_path = path.join(temp_directory, `${theme.name}.json`) const temp_path = path.join(temp_directory, `${theme.name}.json`)
const out_path = path.join(output_directory, `${theme.name}.json`) const out_path = path.join(
output_directory,
`${theme.name}.json`
)
fs.writeFileSync(temp_path, style_tree_json) fs.writeFileSync(temp_path, style_tree_json)
fs.renameSync(temp_path, out_path) fs.renameSync(temp_path, out_path)
console.log(`- ${out_path} created`) console.log(`- ${out_path} created`)

View file

@ -83,6 +83,8 @@ function write_tokens(themes: Theme[], tokens_directory: string) {
console.log(`- ${METADATA_FILE} created`) console.log(`- ${METADATA_FILE} created`)
} }
const all_themes: Theme[] = themes.map((theme) => create_theme(theme)) const all_themes: Theme[] = themes.map((theme) =>
create_theme(theme)
)
write_tokens(all_themes, TOKENS_DIRECTORY) write_tokens(all_themes, TOKENS_DIRECTORY)

View file

@ -10,7 +10,10 @@ export type Margin = {
} }
interface IconButtonOptions { interface IconButtonOptions {
layer?: Theme["lowest"] | Theme["middle"] | Theme["highest"] layer?:
| Theme["lowest"]
| Theme["middle"]
| Theme["highest"]
color?: keyof Theme["lowest"] color?: keyof Theme["lowest"]
margin?: Partial<Margin> margin?: Partial<Margin>
} }

View file

@ -12,47 +12,44 @@ type TabBarButtonProps = TabBarButtonOptions & {
state?: Partial<Record<InteractiveState, Partial<TabBarButtonOptions>>> state?: Partial<Record<InteractiveState, Partial<TabBarButtonOptions>>>
} }
export function tab_bar_button( export function tab_bar_button(theme: Theme, { icon, color = "base" }: TabBarButtonProps) {
theme: Theme,
{ icon, color = "base" }: TabBarButtonProps
) {
const button_spacing = 8 const button_spacing = 8
return interactive({ return (
base: { interactive({
icon: { base: {
color: foreground(theme.middle, color), icon: {
asset: icon, color: foreground(theme.middle, color),
dimensions: { asset: icon,
width: 15, dimensions: {
height: 15, width: 15,
height: 15,
},
}, },
},
container: {
corner_radius: 4,
padding: {
top: 4,
bottom: 4,
left: 4,
right: 4,
},
margin: {
left: button_spacing / 2,
right: button_spacing / 2,
},
},
},
state: {
hovered: {
container: { container: {
background: background(theme.middle, color, "hovered"), corner_radius: 4,
padding: {
top: 4, bottom: 4, left: 4, right: 4
},
margin: {
left: button_spacing / 2,
right: button_spacing / 2,
},
}, },
}, },
clicked: { state: {
container: { hovered: {
background: background(theme.middle, color, "pressed"), container: {
background: background(theme.middle, color, "hovered"),
}
},
clicked: {
container: {
background: background(theme.middle, color, "pressed"),
}
}, },
}, },
}, })
}) )
} }

View file

@ -9,7 +9,10 @@ import { useTheme, Theme } from "../theme"
import { Margin } from "./icon_button" import { Margin } from "./icon_button"
interface TextButtonOptions { interface TextButtonOptions {
layer?: Theme["lowest"] | Theme["middle"] | Theme["highest"] layer?:
| Theme["lowest"]
| Theme["middle"]
| Theme["highest"]
color?: keyof Theme["lowest"] color?: keyof Theme["lowest"]
margin?: Partial<Margin> margin?: Partial<Margin>
text_properties?: TextProperties text_properties?: TextProperties

View file

@ -57,6 +57,6 @@ export default function app(): any {
tooltip: tooltip(), tooltip: tooltip(),
terminal: terminal(), terminal: terminal(),
assistant: assistant(), assistant: assistant(),
feedback: feedback(), feedback: feedback()
} }
} }

View file

@ -8,48 +8,50 @@ type RoleCycleButton = TextStyle & {
} }
// TODO: Replace these with zed types // TODO: Replace these with zed types
type RemainingTokens = TextStyle & { type RemainingTokens = TextStyle & {
background: string background: string,
margin: { top: number; right: number } margin: { top: number, right: number },
padding: { padding: {
right: number right: number,
left: number left: number,
top: number top: number,
bottom: number bottom: number,
} },
corner_radius: number corner_radius: number,
} }
export default function assistant(): any { export default function assistant(): any {
const theme = useTheme() const theme = useTheme()
const interactive_role = ( const interactive_role = (color: StyleSets): Interactive<RoleCycleButton> => {
color: StyleSets return (
): Interactive<RoleCycleButton> => { interactive({
return interactive({ base: {
base: {
...text(theme.highest, "sans", color, { size: "sm" }),
},
state: {
hovered: {
...text(theme.highest, "sans", color, { size: "sm" }), ...text(theme.highest, "sans", color, { size: "sm" }),
background: background(theme.highest, color, "hovered"),
}, },
clicked: { state: {
...text(theme.highest, "sans", color, { size: "sm" }), hovered: {
background: background(theme.highest, color, "pressed"), ...text(theme.highest, "sans", color, { size: "sm" }),
background: background(theme.highest, color, "hovered"),
},
clicked: {
...text(theme.highest, "sans", color, { size: "sm" }),
background: background(theme.highest, color, "pressed"),
}
}, },
}, })
}) )
} }
const tokens_remaining = (color: StyleSets): RemainingTokens => { const tokens_remaining = (color: StyleSets): RemainingTokens => {
return { return (
...text(theme.highest, "mono", color, { size: "xs" }), {
background: background(theme.highest, "on", "default"), ...text(theme.highest, "mono", color, { size: "xs" }),
margin: { top: 12, right: 20 }, background: background(theme.highest, "on", "default"),
padding: { right: 4, left: 4, top: 1, bottom: 1 }, margin: { top: 12, right: 20 },
corner_radius: 6, padding: { right: 4, left: 4, top: 1, bottom: 1 },
} corner_radius: 6,
}
)
} }
return { return {
@ -91,10 +93,7 @@ export default function assistant(): any {
base: { base: {
background: background(theme.middle), background: background(theme.middle),
padding: { top: 4, bottom: 4 }, padding: { top: 4, bottom: 4 },
border: border(theme.middle, "default", { border: border(theme.middle, "default", { top: true, overlay: true }),
top: true,
overlay: true,
}),
}, },
state: { state: {
hovered: { hovered: {
@ -102,7 +101,7 @@ export default function assistant(): any {
}, },
clicked: { clicked: {
background: background(theme.middle, "pressed"), background: background(theme.middle, "pressed"),
}, }
}, },
}), }),
saved_at: { saved_at: {

View file

@ -9,9 +9,9 @@ import {
} from "./components" } from "./components"
import hover_popover from "./hover_popover" import hover_popover from "./hover_popover"
import { build_syntax } from "../theme/syntax"
import { interactive, toggleable } from "../element" import { interactive, toggleable } from "../element"
import { useTheme } from "../theme" import { useTheme } from "../theme"
import chroma from "chroma-js"
export default function editor(): any { export default function editor(): any {
const theme = useTheme() const theme = useTheme()
@ -48,28 +48,16 @@ export default function editor(): any {
} }
} }
const syntax = build_syntax()
return { return {
text_color: theme.syntax.primary.color, text_color: syntax.primary.color,
background: background(layer), background: background(layer),
active_line_background: with_opacity(background(layer, "on"), 0.75), active_line_background: with_opacity(background(layer, "on"), 0.75),
highlighted_line_background: background(layer, "on"), highlighted_line_background: background(layer, "on"),
// Inline autocomplete suggestions, Co-pilot suggestions, etc. // Inline autocomplete suggestions, Co-pilot suggestions, etc.
hint: chroma hint: syntax.hint,
.mix( suggestion: syntax.predictive,
theme.ramps.neutral(0.6).hex(),
theme.ramps.blue(0.4).hex(),
0.45,
"lch"
)
.hex(),
suggestion: chroma
.mix(
theme.ramps.neutral(0.4).hex(),
theme.ramps.blue(0.4).hex(),
0.45,
"lch"
)
.hex(),
code_actions: { code_actions: {
indicator: toggleable({ indicator: toggleable({
base: interactive({ base: interactive({
@ -267,8 +255,8 @@ export default function editor(): any {
invalid_warning_diagnostic: diagnostic(theme.middle, "base"), invalid_warning_diagnostic: diagnostic(theme.middle, "base"),
hover_popover: hover_popover(), hover_popover: hover_popover(),
link_definition: { link_definition: {
color: theme.syntax.link_uri.color, color: syntax.link_uri.color,
underline: theme.syntax.link_uri.underline, underline: syntax.link_uri.underline,
}, },
jump_icon: interactive({ jump_icon: interactive({
base: { base: {
@ -318,7 +306,7 @@ export default function editor(): any {
? with_opacity(theme.ramps.green(0.5).hex(), 0.8) ? with_opacity(theme.ramps.green(0.5).hex(), 0.8)
: with_opacity(theme.ramps.green(0.4).hex(), 0.8), : with_opacity(theme.ramps.green(0.4).hex(), 0.8),
}, },
selections: foreground(layer, "accent"), selections: foreground(layer, "accent")
}, },
composition_mark: { composition_mark: {
underline: { underline: {
@ -326,6 +314,6 @@ export default function editor(): any {
color: border_color(layer), color: border_color(layer),
}, },
}, },
syntax: theme.syntax, syntax,
} }
} }

View file

@ -37,7 +37,7 @@ export default function feedback(): any {
...text(theme.highest, "mono", "on", "disabled"), ...text(theme.highest, "mono", "on", "disabled"),
background: background(theme.highest, "on", "disabled"), background: background(theme.highest, "on", "disabled"),
border: border(theme.highest, "on", "disabled"), border: border(theme.highest, "on", "disabled"),
}, }
}, },
}), }),
button_margin: 8, button_margin: 8,

View file

@ -152,7 +152,7 @@ export default function picker(): any {
0.5 0.5
), ),
}, },
}, }
}), }),
} }
} }

View file

@ -64,17 +64,17 @@ export default function project_panel(): any {
const unselected_default_style = merge( const unselected_default_style = merge(
base_properties, base_properties,
unselected?.default ?? {}, unselected?.default ?? {},
{} {},
) )
const unselected_hovered_style = merge( const unselected_hovered_style = merge(
base_properties, base_properties,
{ background: background(theme.middle, "hovered") }, { background: background(theme.middle, "hovered") },
unselected?.hovered ?? {} unselected?.hovered ?? {},
) )
const unselected_clicked_style = merge( const unselected_clicked_style = merge(
base_properties, base_properties,
{ background: background(theme.middle, "pressed") }, { background: background(theme.middle, "pressed") },
unselected?.clicked ?? {} unselected?.clicked ?? {},
) )
const selected_default_style = merge( const selected_default_style = merge(
base_properties, base_properties,
@ -82,7 +82,7 @@ export default function project_panel(): any {
background: background(theme.lowest), background: background(theme.lowest),
text: text(theme.lowest, "sans", { size: "sm" }), text: text(theme.lowest, "sans", { size: "sm" }),
}, },
selected_style?.default ?? {} selected_style?.default ?? {},
) )
const selected_hovered_style = merge( const selected_hovered_style = merge(
base_properties, base_properties,
@ -90,7 +90,7 @@ export default function project_panel(): any {
background: background(theme.lowest, "hovered"), background: background(theme.lowest, "hovered"),
text: text(theme.lowest, "sans", { size: "sm" }), text: text(theme.lowest, "sans", { size: "sm" }),
}, },
selected_style?.hovered ?? {} selected_style?.hovered ?? {},
) )
const selected_clicked_style = merge( const selected_clicked_style = merge(
base_properties, base_properties,
@ -98,7 +98,7 @@ export default function project_panel(): any {
background: background(theme.lowest, "pressed"), background: background(theme.lowest, "pressed"),
text: text(theme.lowest, "sans", { size: "sm" }), text: text(theme.lowest, "sans", { size: "sm" }),
}, },
selected_style?.clicked ?? {} selected_style?.clicked ?? {},
) )
return toggleable({ return toggleable({
@ -175,7 +175,7 @@ export default function project_panel(): any {
default: { default: {
icon_color: foreground(theme.middle, "variant"), icon_color: foreground(theme.middle, "variant"),
}, },
} },
), ),
cut_entry: entry( cut_entry: entry(
{ {
@ -190,7 +190,7 @@ export default function project_panel(): any {
size: "sm", size: "sm",
}), }),
}, },
} },
), ),
filename_editor: { filename_editor: {
background: background(theme.middle, "on"), background: background(theme.middle, "on"),

View file

@ -34,14 +34,10 @@ export default function status_bar(): any {
...text(layer, "mono", "variant", { size: "xs" }), ...text(layer, "mono", "variant", { size: "xs" }),
}, },
active_language: text_button({ active_language: text_button({
color: "variant", color: "variant"
}),
auto_update_progress_message: text(layer, "sans", "variant", {
size: "xs",
}),
auto_update_done_message: text(layer, "sans", "variant", {
size: "xs",
}), }),
auto_update_progress_message: text(layer, "sans", "variant", { size: "xs" }),
auto_update_done_message: text(layer, "sans", "variant", { size: "xs" }),
lsp_status: interactive({ lsp_status: interactive({
base: { base: {
...diagnostic_status_container, ...diagnostic_status_container,

View file

@ -183,10 +183,10 @@ export function titlebar(): any {
project_name_divider: text(theme.lowest, "sans", "variant"), project_name_divider: text(theme.lowest, "sans", "variant"),
project_menu_button: toggleable_text_button(theme, { project_menu_button: toggleable_text_button(theme, {
color: "base", color: 'base',
}), }),
git_menu_button: toggleable_text_button(theme, { git_menu_button: toggleable_text_button(theme, {
color: "variant", color: 'variant',
}), }),
// Collaborators // Collaborators

View file

@ -1,28 +1,28 @@
import { Scale, Color } from "chroma-js" import { Scale, Color } from "chroma-js"
import { Syntax, ThemeSyntax, SyntaxHighlightStyle } from "./syntax"
export { Syntax, ThemeSyntax, SyntaxHighlightStyle }
import { import {
ThemeConfig, ThemeConfig,
ThemeAppearance, ThemeAppearance,
ThemeConfigInputColors, ThemeConfigInputColors,
} from "./theme_config" } from "./theme_config"
import { get_ramps } from "./ramps" import { get_ramps } from "./ramps"
import { syntaxStyle } from "./syntax"
import { Syntax } from "../types/syntax"
export interface Theme { export interface Theme {
name: string name: string
is_light: boolean is_light: boolean
/** /**
* App background, other elements that should sit directly on top of the background. * App background, other elements that should sit directly on top of the background.
*/ */
lowest: Layer lowest: Layer
/** /**
* Panels, tabs, other UI surfaces that sit on top of the background. * Panels, tabs, other UI surfaces that sit on top of the background.
*/ */
middle: Layer middle: Layer
/** /**
* Editors like code buffers, conversation editors, etc. * Editors like code buffers, conversation editors, etc.
*/ */
highest: Layer highest: Layer
ramps: RampSet ramps: RampSet
@ -31,7 +31,7 @@ export interface Theme {
modal_shadow: Shadow modal_shadow: Shadow
players: Players players: Players
syntax: Syntax syntax?: Partial<ThemeSyntax>
} }
export interface Meta { export interface Meta {
@ -115,7 +115,12 @@ export interface Style {
} }
export function create_theme(theme: ThemeConfig): Theme { export function create_theme(theme: ThemeConfig): Theme {
const { name, appearance, input_color } = theme const {
name,
appearance,
input_color,
override: { syntax },
} = theme
const is_light = appearance === ThemeAppearance.Light const is_light = appearance === ThemeAppearance.Light
const color_ramps: ThemeConfigInputColors = input_color const color_ramps: ThemeConfigInputColors = input_color
@ -157,11 +162,6 @@ export function create_theme(theme: ThemeConfig): Theme {
"7": player(ramps.yellow), "7": player(ramps.yellow),
} }
const syntax = syntaxStyle(
ramps,
theme.override.syntax ? theme.override.syntax : {}
)
return { return {
name, name,
is_light, is_light,

View file

@ -1,45 +1,325 @@
import deepmerge from "deepmerge" import deepmerge from "deepmerge"
import { font_weights, ThemeConfigInputSyntax, RampSet } from "../common" import { FontWeight, font_weights, useTheme } from "../common"
import { Syntax, SyntaxHighlightStyle, allSyntaxKeys } from "../types/syntax" import chroma from "chroma-js"
// Apply defaults to any missing syntax properties that are not defined manually export interface SyntaxHighlightStyle {
function apply_defaults( color?: string
ramps: RampSet, weight?: FontWeight
syntax_highlights: Partial<Syntax> underline?: boolean
): Syntax { italic?: boolean
const restKeys: (keyof Syntax)[] = allSyntaxKeys.filter( }
(key) => !syntax_highlights[key]
)
const completeSyntax: Syntax = {} as Syntax export interface Syntax {
// == Text Styles ====== /
comment: SyntaxHighlightStyle
// elixir: doc comment
"comment.doc": SyntaxHighlightStyle
primary: SyntaxHighlightStyle
predictive: SyntaxHighlightStyle
hint: SyntaxHighlightStyle
const defaults: SyntaxHighlightStyle = { // === Formatted Text ====== /
color: ramps.neutral(1).hex(), emphasis: SyntaxHighlightStyle
} "emphasis.strong": SyntaxHighlightStyle
title: SyntaxHighlightStyle
link_uri: SyntaxHighlightStyle
link_text: SyntaxHighlightStyle
/** md: indented_code_block, fenced_code_block, code_span */
"text.literal": SyntaxHighlightStyle
for (const key of restKeys) { // == Punctuation ====== /
{ punctuation: SyntaxHighlightStyle
completeSyntax[key] = { /** Example: `(`, `[`, `{`...*/
...defaults, "punctuation.bracket": SyntaxHighlightStyle
} /**., ;*/
"punctuation.delimiter": SyntaxHighlightStyle
// js, ts: ${, } in a template literal
// yaml: *, &, ---, ...
"punctuation.special": SyntaxHighlightStyle
// md: list_marker_plus, list_marker_dot, etc
"punctuation.list_marker": SyntaxHighlightStyle
// == Strings ====== /
string: SyntaxHighlightStyle
// css: color_value
// js: this, super
// toml: offset_date_time, local_date_time...
"string.special": SyntaxHighlightStyle
// elixir: atom, quoted_atom, keyword, quoted_keyword
// ruby: simple_symbol, delimited_symbol...
"string.special.symbol"?: SyntaxHighlightStyle
// elixir, python, yaml...: escape_sequence
"string.escape"?: SyntaxHighlightStyle
// Regular expressions
"string.regex"?: SyntaxHighlightStyle
// == Types ====== /
// We allow Function here because all JS objects literals have this property
constructor: SyntaxHighlightStyle | Function // eslint-disable-line @typescript-eslint/ban-types
variant: SyntaxHighlightStyle
type: SyntaxHighlightStyle
// js: predefined_type
"type.builtin"?: SyntaxHighlightStyle
// == Values
variable: SyntaxHighlightStyle
// this, ...
// css: -- (var(--foo))
// lua: self
"variable.special"?: SyntaxHighlightStyle
// c: statement_identifier,
label: SyntaxHighlightStyle
// css: tag_name, nesting_selector, universal_selector...
tag: SyntaxHighlightStyle
// css: attribute, pseudo_element_selector (tag_name),
attribute: SyntaxHighlightStyle
// css: class_name, property_name, namespace_name...
property: SyntaxHighlightStyle
// true, false, null, nullptr
constant: SyntaxHighlightStyle
// css: @media, @import, @supports...
// js: declare, implements, interface, keyof, public...
keyword: SyntaxHighlightStyle
// note: js enum is currently defined as a keyword
enum: SyntaxHighlightStyle
// -, --, ->, !=, &&, ||, <=...
operator: SyntaxHighlightStyle
number: SyntaxHighlightStyle
boolean: SyntaxHighlightStyle
// elixir: __MODULE__, __DIR__, __ENV__, etc
// go: nil, iota
"constant.builtin"?: SyntaxHighlightStyle
// == Functions ====== /
function: SyntaxHighlightStyle
// lua: assert, error, loadfile, tostring, unpack...
"function.builtin"?: SyntaxHighlightStyle
// go: call_expression, method_declaration
// js: call_expression, method_definition, pair (key, arrow function)
// rust: function_item name: (identifier)
"function.definition"?: SyntaxHighlightStyle
// rust: macro_definition name: (identifier)
"function.special.definition"?: SyntaxHighlightStyle
"function.method"?: SyntaxHighlightStyle
// ruby: identifier/"defined?" // Nate note: I don't fully understand this one.
"function.method.builtin"?: SyntaxHighlightStyle
// == Unsorted ====== /
// lua: hash_bang_line
preproc: SyntaxHighlightStyle
// elixir, python: interpolation (ex: foo in ${foo})
// js: template_substitution
embedded: SyntaxHighlightStyle
}
export type ThemeSyntax = Partial<Syntax>
const default_syntax_highlight_style: Omit<SyntaxHighlightStyle, "color"> = {
weight: "normal",
underline: false,
italic: false,
}
function build_default_syntax(): Syntax {
const theme = useTheme()
// Make a temporary object that is allowed to be missing
// the "color" property for each style
const syntax: {
[key: string]: Omit<SyntaxHighlightStyle, "color">
} = {}
// then spread the default to each style
for (const key of Object.keys({} as Syntax)) {
syntax[key as keyof Syntax] = {
...default_syntax_highlight_style,
} }
} }
const mergedBaseSyntax = Object.assign(completeSyntax, syntax_highlights) // Mix the neutral and blue colors to get a
// predictive color distinct from any other color in the theme
const predictive = chroma
.mix(
theme.ramps.neutral(0.4).hex(),
theme.ramps.blue(0.4).hex(),
0.45,
"lch"
)
.hex()
// Mix the neutral and green colors to get a
// hint color distinct from any other color in the theme
const hint = chroma
.mix(
theme.ramps.neutral(0.6).hex(),
theme.ramps.blue(0.4).hex(),
0.45,
"lch"
)
.hex()
return mergedBaseSyntax const color = {
primary: theme.ramps.neutral(1).hex(),
comment: theme.ramps.neutral(0.71).hex(),
punctuation: theme.ramps.neutral(0.86).hex(),
predictive: predictive,
hint: hint,
emphasis: theme.ramps.blue(0.5).hex(),
string: theme.ramps.orange(0.5).hex(),
function: theme.ramps.yellow(0.5).hex(),
type: theme.ramps.cyan(0.5).hex(),
constructor: theme.ramps.blue(0.5).hex(),
variant: theme.ramps.blue(0.5).hex(),
property: theme.ramps.blue(0.5).hex(),
enum: theme.ramps.orange(0.5).hex(),
operator: theme.ramps.orange(0.5).hex(),
number: theme.ramps.green(0.5).hex(),
boolean: theme.ramps.green(0.5).hex(),
constant: theme.ramps.green(0.5).hex(),
keyword: theme.ramps.blue(0.5).hex(),
}
// Then assign colors and use Syntax to enforce each style getting it's own color
const default_syntax: Syntax = {
...syntax,
comment: {
color: color.comment,
},
"comment.doc": {
color: color.comment,
},
primary: {
color: color.primary,
},
predictive: {
color: color.predictive,
italic: true,
},
hint: {
color: color.hint,
weight: font_weights.bold,
},
emphasis: {
color: color.emphasis,
},
"emphasis.strong": {
color: color.emphasis,
weight: font_weights.bold,
},
title: {
color: color.primary,
weight: font_weights.bold,
},
link_uri: {
color: theme.ramps.green(0.5).hex(),
underline: true,
},
link_text: {
color: theme.ramps.orange(0.5).hex(),
italic: true,
},
"text.literal": {
color: color.string,
},
punctuation: {
color: color.punctuation,
},
"punctuation.bracket": {
color: color.punctuation,
},
"punctuation.delimiter": {
color: color.punctuation,
},
"punctuation.special": {
color: theme.ramps.neutral(0.86).hex(),
},
"punctuation.list_marker": {
color: color.punctuation,
},
string: {
color: color.string,
},
"string.special": {
color: color.string,
},
"string.special.symbol": {
color: color.string,
},
"string.escape": {
color: color.comment,
},
"string.regex": {
color: color.string,
},
constructor: {
color: theme.ramps.blue(0.5).hex(),
},
variant: {
color: theme.ramps.blue(0.5).hex(),
},
type: {
color: color.type,
},
variable: {
color: color.primary,
},
label: {
color: theme.ramps.blue(0.5).hex(),
},
tag: {
color: theme.ramps.blue(0.5).hex(),
},
attribute: {
color: theme.ramps.blue(0.5).hex(),
},
property: {
color: theme.ramps.blue(0.5).hex(),
},
constant: {
color: color.constant,
},
keyword: {
color: color.keyword,
},
enum: {
color: color.enum,
},
operator: {
color: color.operator,
},
number: {
color: color.number,
},
boolean: {
color: color.boolean,
},
function: {
color: color.function,
},
preproc: {
color: color.primary,
},
embedded: {
color: color.primary,
},
}
return default_syntax
} }
// Merge the base syntax with the theme syntax overrides export function build_syntax(): Syntax {
// This is a deep merge, so any nested properties will be merged as well const theme = useTheme()
// This allows for a theme to only override a single property of a syntax highlight style
const merge_syntax = ( const default_syntax: Syntax = build_default_syntax()
baseSyntax: Syntax,
theme_syntax_overrides: ThemeConfigInputSyntax if (!theme.syntax) {
): Syntax => { return default_syntax
return deepmerge<Syntax, ThemeConfigInputSyntax>( }
baseSyntax,
theme_syntax_overrides, const syntax = deepmerge<Syntax, Partial<ThemeSyntax>>(
default_syntax,
theme.syntax,
{ {
arrayMerge: (destinationArray, sourceArray) => [ arrayMerge: (destinationArray, sourceArray) => [
...destinationArray, ...destinationArray,
@ -47,49 +327,6 @@ const merge_syntax = (
], ],
} }
) )
}
/** Returns a complete Syntax object of the combined styles of a theme's syntax overrides and the default syntax styles */ return syntax
export const syntaxStyle = (
ramps: RampSet,
theme_syntax_overrides: ThemeConfigInputSyntax
): Syntax => {
const syntax_highlights: Partial<Syntax> = {
comment: { color: ramps.neutral(0.71).hex() },
"comment.doc": { color: ramps.neutral(0.71).hex() },
primary: { color: ramps.neutral(1).hex() },
emphasis: { color: ramps.blue(0.5).hex() },
"emphasis.strong": {
color: ramps.blue(0.5).hex(),
weight: font_weights.bold,
},
link_uri: { color: ramps.green(0.5).hex(), underline: true },
link_text: { color: ramps.orange(0.5).hex(), italic: true },
"text.literal": { color: ramps.orange(0.5).hex() },
punctuation: { color: ramps.neutral(0.86).hex() },
"punctuation.bracket": { color: ramps.neutral(0.86).hex() },
"punctuation.special": { color: ramps.neutral(0.86).hex() },
"punctuation.delimiter": { color: ramps.neutral(0.86).hex() },
"punctuation.list_marker": { color: ramps.neutral(0.86).hex() },
string: { color: ramps.orange(0.5).hex() },
"string.special": { color: ramps.orange(0.5).hex() },
"string.special.symbol": { color: ramps.orange(0.5).hex() },
"string.escape": { color: ramps.neutral(0.71).hex() },
"string.regex": { color: ramps.orange(0.5).hex() },
"method.constructor": { color: ramps.blue(0.5).hex() },
type: { color: ramps.cyan(0.5).hex() },
label: { color: ramps.blue(0.5).hex() },
attribute: { color: ramps.blue(0.5).hex() },
property: { color: ramps.blue(0.5).hex() },
constant: { color: ramps.green(0.5).hex() },
keyword: { color: ramps.blue(0.5).hex() },
operator: { color: ramps.orange(0.5).hex() },
number: { color: ramps.green(0.5).hex() },
boolean: { color: ramps.green(0.5).hex() },
function: { color: ramps.yellow(0.5).hex() },
}
const baseSyntax = apply_defaults(ramps, syntax_highlights)
const mergedSyntax = merge_syntax(baseSyntax, theme_syntax_overrides)
return mergedSyntax
} }

View file

@ -1,5 +1,5 @@
import { Scale, Color } from "chroma-js" import { Scale, Color } from "chroma-js"
import { SyntaxHighlightStyle, SyntaxProperty } from "../types/syntax" import { Syntax } from "./syntax"
interface ThemeMeta { interface ThemeMeta {
/** The name of the theme */ /** The name of the theme */
@ -55,9 +55,7 @@ export type ThemeConfigInputColorsKeys = keyof ThemeConfigInputColors
* } * }
* ``` * ```
*/ */
export type ThemeConfigInputSyntax = Partial< export type ThemeConfigInputSyntax = Partial<Syntax>
Record<SyntaxProperty, Partial<SyntaxHighlightStyle>>
>
interface ThemeConfigOverrides { interface ThemeConfigOverrides {
syntax: ThemeConfigInputSyntax syntax: ThemeConfigInputSyntax

View file

@ -4,13 +4,17 @@ import {
SingleOtherToken, SingleOtherToken,
TokenTypes, TokenTypes,
} from "@tokens-studio/types" } from "@tokens-studio/types"
import { Shadow } from "../create_theme" import {
Shadow,
SyntaxHighlightStyle,
ThemeSyntax,
} from "../create_theme"
import { LayerToken, layer_token } from "./layer" import { LayerToken, layer_token } from "./layer"
import { PlayersToken, players_token } from "./players" import { PlayersToken, players_token } from "./players"
import { color_token } from "./token" import { color_token } from "./token"
import { Syntax } from "../syntax"
import editor from "../../style_tree/editor" import editor from "../../style_tree/editor"
import { useTheme } from "../../../src/common" import { useTheme } from "../../../src/common"
import { Syntax, SyntaxHighlightStyle } from "../../types/syntax"
interface ThemeTokens { interface ThemeTokens {
name: SingleOtherToken name: SingleOtherToken
@ -47,7 +51,7 @@ const modal_shadow_token = (): SingleBoxShadowToken => {
return create_shadow_token(shadow, "modal_shadow") return create_shadow_token(shadow, "modal_shadow")
} }
type ThemeSyntaxColorTokens = Record<keyof Syntax, SingleColorToken> type ThemeSyntaxColorTokens = Record<keyof ThemeSyntax, SingleColorToken>
function syntax_highlight_style_color_tokens( function syntax_highlight_style_color_tokens(
syntax: Syntax syntax: Syntax

View file

@ -1,8 +1,4 @@
import { import { ThemeLicenseType, ThemeSyntax, ThemeFamilyMeta } from "../../common"
ThemeLicenseType,
ThemeFamilyMeta,
ThemeConfigInputSyntax,
} from "../../common"
export interface Variant { export interface Variant {
colors: { colors: {
@ -33,7 +29,7 @@ export const meta: ThemeFamilyMeta = {
"https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/", "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/",
} }
export const build_syntax = (variant: Variant): ThemeConfigInputSyntax => { export const build_syntax = (variant: Variant): ThemeSyntax => {
const { colors } = variant const { colors } = variant
return { return {
primary: { color: colors.base06 }, primary: { color: colors.base06 },
@ -54,6 +50,7 @@ export const build_syntax = (variant: Variant): ThemeConfigInputSyntax => {
property: { color: colors.base08 }, property: { color: colors.base08 },
variable: { color: colors.base06 }, variable: { color: colors.base06 },
"variable.special": { color: colors.base0E }, "variable.special": { color: colors.base0E },
variant: { color: colors.base0A },
keyword: { color: colors.base0E }, keyword: { color: colors.base0E },
} }
} }

View file

@ -3,8 +3,8 @@ import {
chroma, chroma,
color_ramp, color_ramp,
ThemeLicenseType, ThemeLicenseType,
ThemeSyntax,
ThemeFamilyMeta, ThemeFamilyMeta,
ThemeConfigInputSyntax,
} from "../../common" } from "../../common"
export const ayu = { export const ayu = {
@ -27,7 +27,7 @@ export const build_theme = (t: typeof dark, light: boolean) => {
purple: t.syntax.constant.hex(), purple: t.syntax.constant.hex(),
} }
const syntax: ThemeConfigInputSyntax = { const syntax: ThemeSyntax = {
constant: { color: t.syntax.constant.hex() }, constant: { color: t.syntax.constant.hex() },
"string.regex": { color: t.syntax.regexp.hex() }, "string.regex": { color: t.syntax.regexp.hex() },
string: { color: t.syntax.string.hex() }, string: { color: t.syntax.string.hex() },
@ -61,7 +61,7 @@ export const build_theme = (t: typeof dark, light: boolean) => {
} }
} }
export const build_syntax = (t: typeof dark): ThemeConfigInputSyntax => { export const build_syntax = (t: typeof dark): ThemeSyntax => {
return { return {
constant: { color: t.syntax.constant.hex() }, constant: { color: t.syntax.constant.hex() },
"string.regex": { color: t.syntax.regexp.hex() }, "string.regex": { color: t.syntax.regexp.hex() },

View file

@ -4,8 +4,8 @@ import {
ThemeAppearance, ThemeAppearance,
ThemeLicenseType, ThemeLicenseType,
ThemeConfig, ThemeConfig,
ThemeSyntax,
ThemeFamilyMeta, ThemeFamilyMeta,
ThemeConfigInputSyntax,
} from "../../common" } from "../../common"
const meta: ThemeFamilyMeta = { const meta: ThemeFamilyMeta = {
@ -214,7 +214,7 @@ const build_variant = (variant: Variant): ThemeConfig => {
magenta: color_ramp(chroma(variant.colors.gray)), magenta: color_ramp(chroma(variant.colors.gray)),
} }
const syntax: ThemeConfigInputSyntax = { const syntax: ThemeSyntax = {
primary: { color: neutral[is_light ? 0 : 8] }, primary: { color: neutral[is_light ? 0 : 8] },
"text.literal": { color: colors.blue }, "text.literal": { color: colors.blue },
comment: { color: colors.gray }, comment: { color: colors.gray },
@ -229,7 +229,7 @@ const build_variant = (variant: Variant): ThemeConfig => {
"string.special.symbol": { color: colors.aqua }, "string.special.symbol": { color: colors.aqua },
"string.regex": { color: colors.orange }, "string.regex": { color: colors.orange },
type: { color: colors.yellow }, type: { color: colors.yellow },
// enum: { color: colors.orange }, enum: { color: colors.orange },
tag: { color: colors.aqua }, tag: { color: colors.aqua },
constant: { color: colors.yellow }, constant: { color: colors.yellow },
keyword: { color: colors.red }, keyword: { color: colors.red },

View file

@ -54,6 +54,7 @@ export const theme: ThemeConfig = {
syntax: { syntax: {
boolean: { color: color.orange }, boolean: { color: color.orange },
comment: { color: color.grey }, comment: { color: color.grey },
enum: { color: color.red },
"emphasis.strong": { color: color.orange }, "emphasis.strong": { color: color.orange },
function: { color: color.blue }, function: { color: color.blue },
keyword: { color: color.purple }, keyword: { color: color.purple },
@ -72,7 +73,8 @@ export const theme: ThemeConfig = {
"text.literal": { color: color.green }, "text.literal": { color: color.green },
type: { color: color.teal }, type: { color: color.teal },
"variable.special": { color: color.orange }, "variable.special": { color: color.orange },
"method.constructor": { color: color.blue }, variant: { color: color.blue },
constructor: { color: color.blue },
}, },
}, },
} }

View file

@ -55,6 +55,7 @@ export const theme: ThemeConfig = {
syntax: { syntax: {
boolean: { color: color.orange }, boolean: { color: color.orange },
comment: { color: color.grey }, comment: { color: color.grey },
enum: { color: color.red },
"emphasis.strong": { color: color.orange }, "emphasis.strong": { color: color.orange },
function: { color: color.blue }, function: { color: color.blue },
keyword: { color: color.purple }, keyword: { color: color.purple },
@ -72,6 +73,7 @@ export const theme: ThemeConfig = {
"text.literal": { color: color.green }, "text.literal": { color: color.green },
type: { color: color.teal }, type: { color: color.teal },
"variable.special": { color: color.orange }, "variable.special": { color: color.orange },
variant: { color: color.blue },
}, },
}, },
} }

View file

@ -1,4 +1,4 @@
import { ThemeConfigInputSyntax } from "../../common" import { ThemeSyntax } from "../../common"
export const color = { export const color = {
default: { default: {
@ -54,7 +54,7 @@ export const color = {
}, },
} }
export const syntax = (c: typeof color.default): ThemeConfigInputSyntax => { export const syntax = (c: typeof color.default): Partial<ThemeSyntax> => {
return { return {
comment: { color: c.muted }, comment: { color: c.muted },
operator: { color: c.pine }, operator: { color: c.pine },

View file

@ -1,111 +0,0 @@
import fs from "fs"
import path from "path"
import readline from "readline"
function escapeTypeName(name: string): string {
return `'${name.replace("@", "").toLowerCase()}'`
}
const generatedNote = `// This file is generated by extract_syntax_types.ts
// Do not edit this file directly
// It is generated from the highlight.scm files in the zed crate
// To regenerate this file manually:
// 'npm run extract-syntax-types' from ./styles`
const defaultTextProperty = ` /** Default text color */
| 'primary'`
const main = async () => {
const pathFromRoot = "crates/zed/src/languages"
const directoryPath = path.join(__dirname, "../../../", pathFromRoot)
const stylesMap: Record<string, Set<string>> = {}
const propertyLanguageMap: Record<string, Set<string>> = {}
const processFile = async (filePath: string, language: string) => {
const fileStream = fs.createReadStream(filePath)
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
})
for await (const line of rl) {
const cleanedLine = line.replace(/"@[a-zA-Z0-9_.]*"/g, "")
const match = cleanedLine.match(/@(\w+\.*)*/g)
if (match) {
match.forEach((property) => {
const formattedProperty = escapeTypeName(property)
// Only add non-empty properties
if (formattedProperty !== "''") {
if (!propertyLanguageMap[formattedProperty]) {
propertyLanguageMap[formattedProperty] = new Set()
}
propertyLanguageMap[formattedProperty].add(language)
}
})
}
}
}
const directories = fs
.readdirSync(directoryPath, { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name)
for (const dir of directories) {
const highlightsFilePath = path.join(
directoryPath,
dir,
"highlights.scm"
)
if (fs.existsSync(highlightsFilePath)) {
await processFile(highlightsFilePath, dir)
}
}
for (const [language, properties] of Object.entries(stylesMap)) {
console.log(`${language}: ${Array.from(properties).join(", ")}`)
}
const sortedProperties = Object.entries(propertyLanguageMap).sort(
([propA], [propB]) => propA.localeCompare(propB)
)
const outStream = fs.createWriteStream(path.join(__dirname, "syntax.ts"))
let allProperties = ""
const syntaxKeys = []
for (const [property, languages] of sortedProperties) {
let languagesArray = Array.from(languages)
const moreThanSeven = languagesArray.length > 7
// Limit to the first 7 languages, append "..." if more than 7
languagesArray = languagesArray.slice(0, 7)
if (moreThanSeven) {
languagesArray.push("...")
}
const languagesString = languagesArray.join(", ")
const comment = `/** ${languagesString} */`
allProperties += ` ${comment}\n | ${property} \n`
syntaxKeys.push(property)
}
outStream.write(`${generatedNote}
export type SyntaxHighlightStyle = {
color: string,
fade_out?: number,
italic?: boolean,
underline?: boolean,
weight?: string,
}
export type Syntax = Record<SyntaxProperty, SyntaxHighlightStyle>
export type SyntaxOverride = Partial<Syntax>
export type SyntaxProperty = \n${defaultTextProperty}\n\n${allProperties}
export const allSyntaxKeys: SyntaxProperty[] = [\n ${syntaxKeys.join(
",\n "
)}\n]`)
outStream.end()
}
main().catch(console.error)

View file

@ -1,202 +0,0 @@
// This file is generated by extract_syntax_types.ts
// Do not edit this file directly
// It is generated from the highlight.scm files in the zed crate
// To regenerate this file manually:
// 'npm run extract-syntax-types' from ./styles
export type SyntaxHighlightStyle = {
color: string
fade_out?: number
italic?: boolean
underline?: boolean
weight?: string
}
export type Syntax = Record<SyntaxProperty, SyntaxHighlightStyle>
export type SyntaxOverride = Partial<Syntax>
export type SyntaxProperty =
/** Default text color */
| "primary"
/** elixir */
| "__attribute__"
/** elixir */
| "__name__"
/** elixir */
| "_sigil_name"
/** css, heex, lua */
| "attribute"
/** javascript, lua, tsx, typescript, yaml */
| "boolean"
/** elixir */
| "comment.doc"
/** elixir */
| "comment.unused"
/** bash, c, cpp, css, elixir, elm, erb, ... */
| "comment"
/** elixir, go, javascript, lua, php, python, racket, ... */
| "constant.builtin"
/** bash, c, cpp, elixir, elm, glsl, heex, ... */
| "constant"
/** glsl */
| "delimiter"
/** bash, elixir, javascript, python, ruby, tsx, typescript */
| "embedded"
/** markdown */
| "emphasis.strong"
/** markdown */
| "emphasis"
/** go, python, racket, ruby, scheme */
| "escape"
/** lua */
| "field"
/** lua, php, python */
| "function.builtin"
/** elm, lua, rust */
| "function.definition"
/** ruby */
| "function.method.builtin"
/** go, javascript, php, python, ruby, rust, tsx, ... */
| "function.method"
/** rust */
| "function.special.definition"
/** c, cpp, glsl, rust */
| "function.special"
/** bash, c, cpp, css, elixir, elm, glsl, ... */
| "function"
/** elm */
| "identifier"
/** glsl */
| "keyword.function"
/** bash, c, cpp, css, elixir, elm, erb, ... */
| "keyword"
/** c, cpp, glsl */
| "label"
/** markdown */
| "link_text"
/** markdown */
| "link_uri"
/** lua, php, tsx, typescript */
| "method.constructor"
/** lua */
| "method"
/** heex */
| "module"
/** svelte */
| "none"
/** bash, c, cpp, css, elixir, glsl, go, ... */
| "number"
/** bash, c, cpp, css, elixir, elm, glsl, ... */
| "operator"
/** lua */
| "parameter"
/** lua */
| "preproc"
/** bash, c, cpp, css, glsl, go, html, ... */
| "property"
/** c, cpp, elixir, elm, heex, html, javascript, ... */
| "punctuation.bracket"
/** c, cpp, css, elixir, elm, heex, javascript, ... */
| "punctuation.delimiter"
/** markdown */
| "punctuation.list_marker"
/** elixir, javascript, python, ruby, tsx, typescript, yaml */
| "punctuation.special"
/** elixir */
| "punctuation"
/** glsl */
| "storageclass"
/** elixir, elm, yaml */
| "string.escape"
/** elixir, javascript, racket, ruby, tsx, typescript */
| "string.regex"
/** elixir, ruby */
| "string.special.symbol"
/** css, elixir, toml */
| "string.special"
/** bash, c, cpp, css, elixir, elm, glsl, ... */
| "string"
/** svelte */
| "tag.delimiter"
/** css, heex, php, svelte */
| "tag"
/** markdown */
| "text.literal"
/** markdown */
| "title"
/** javascript, php, rust, tsx, typescript */
| "type.builtin"
/** glsl */
| "type.qualifier"
/** c, cpp, css, elixir, elm, glsl, go, ... */
| "type"
/** glsl, php */
| "variable.builtin"
/** cpp, css, javascript, lua, racket, ruby, rust, ... */
| "variable.special"
/** c, cpp, elm, glsl, go, javascript, lua, ... */
| "variable"
export const allSyntaxKeys: SyntaxProperty[] = [
"__attribute__",
"__name__",
"_sigil_name",
"attribute",
"boolean",
"comment.doc",
"comment.unused",
"comment",
"constant.builtin",
"constant",
"delimiter",
"embedded",
"emphasis.strong",
"emphasis",
"escape",
"field",
"function.builtin",
"function.definition",
"function.method.builtin",
"function.method",
"function.special.definition",
"function.special",
"function",
"identifier",
"keyword.function",
"keyword",
"label",
"link_text",
"link_uri",
"method.constructor",
"method",
"module",
"none",
"number",
"operator",
"parameter",
"preproc",
"property",
"punctuation.bracket",
"punctuation.delimiter",
"punctuation.list_marker",
"punctuation.special",
"punctuation",
"storageclass",
"string.escape",
"string.regex",
"string.special.symbol",
"string.special",
"string",
"tag.delimiter",
"tag",
"text.literal",
"title",
"type.builtin",
"type.qualifier",
"type",
"variable.builtin",
"variable.special",
"variable",
]

View file

@ -24,5 +24,7 @@
"useUnknownInCatchVariables": false, "useUnknownInCatchVariables": false,
"baseUrl": "." "baseUrl": "."
}, },
"exclude": ["node_modules"] "exclude": [
"node_modules"
]
} }