From 3d456316ca78a7f6f1d6b8a76ff72c8abdeffcbc Mon Sep 17 00:00:00 2001 From: Shafkath Shuhan Date: Thu, 8 Jul 2021 21:50:01 -0400 Subject: [PATCH 1/8] wip --- Cargo.lock | 31 +++++++++++++++++++++++++++++++ helix-core/src/syntax.rs | 2 +- helix-syntax/Cargo.toml | 1 + helix-syntax/src/lib.rs | 4 +++- helix-term/src/ui/editor.rs | 30 ++++++++++++++++++++++++++---- 5 files changed, 62 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab3cdd1e180c..cee641c3d99a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -309,6 +309,15 @@ dependencies = [ "regex", ] +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "helix-core" version = "0.3.0" @@ -356,6 +365,7 @@ version = "0.3.0" dependencies = [ "cc", "serde", + "strum", "threadpool", "tree-sitter", ] @@ -933,6 +943,27 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" +[[package]] +name = "strum" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syn" version = "1.0.73" diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 5b45a88f9b42..4ba6d1e4b7eb 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -31,7 +31,7 @@ pub struct Configuration { #[serde(rename_all = "kebab-case")] pub struct LanguageConfiguration { #[serde(rename = "name")] - pub(crate) language_id: Lang, + pub language_id: Lang, pub scope: String, // source.rust pub file_types: Vec, // filename ends_with? pub roots: Vec, // these indicate project roots <.git, Cargo.toml> diff --git a/helix-syntax/Cargo.toml b/helix-syntax/Cargo.toml index 140e3d24c4e7..2bb6dbbccdab 100644 --- a/helix-syntax/Cargo.toml +++ b/helix-syntax/Cargo.toml @@ -13,6 +13,7 @@ include = ["src/**/*", "languages/**/*", "build.rs", "!**/docs/**/*", "!**/test/ [dependencies] tree-sitter = "0.19" serde = { version = "1.0", features = ["derive"] } +strum = { version = "0.21", features = ["derive"] } [build-dependencies] cc = { version = "1", features = ["parallel"] } diff --git a/helix-syntax/src/lib.rs b/helix-syntax/src/lib.rs index 5e3bb3ea0a2a..1edc9cb782cf 100644 --- a/helix-syntax/src/lib.rs +++ b/helix-syntax/src/lib.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use strum::EnumString; use tree_sitter::Language; #[macro_export] @@ -13,7 +14,8 @@ macro_rules! mk_extern { #[macro_export] macro_rules! mk_enum { ( $( $camel:ident ),* ) => { - #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] + #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, EnumString)] + #[strum(ascii_case_insensitive)] #[serde(rename_all = "lowercase")] pub enum Lang { $( diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index ef13004c6f7a..4573f233e3f1 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -19,7 +19,7 @@ use helix_view::{ keyboard::{KeyCode, KeyModifiers}, Document, Editor, Theme, View, }; -use std::borrow::Cow; +use std::{borrow::Cow, str::FromStr, sync::Arc}; use crossterm::event::Event; use tui::buffer::Buffer as Surface; @@ -64,6 +64,7 @@ impl EditorView { surface: &mut Surface, theme: &Theme, is_focused: bool, + loader: Arc, ) { let area = Rect::new( view.area.x + OFFSET, @@ -72,7 +73,7 @@ impl EditorView { view.area.height.saturating_sub(1), ); // - 1 for statusline - self.render_buffer(doc, view, area, surface, theme, is_focused); + self.render_buffer(doc, view, area, surface, theme, is_focused, loader); // if we're not at the edge of the screen, draw a right border if viewport.right() != view.area.right() { @@ -106,6 +107,7 @@ impl EditorView { surface: &mut Surface, theme: &Theme, is_focused: bool, + loader: Arc, ) { let text = doc.text().slice(..); @@ -122,8 +124,19 @@ impl EditorView { // TODO: range doesn't actually restrict source, just highlight range let highlights: Vec<_> = match doc.syntax() { Some(syntax) => { + let scopes = theme.scopes(); + let configs: Vec<_> = loader + .language_configs_iter() + .map(|x| (x, x.highlight_config(scopes).unwrap())) + .collect(); syntax - .highlight_iter(text.slice(..), Some(range), None, |_| None) + .highlight_iter(text.slice(..), Some(range), None, |language| { + let language = syntax::Lang::from_str(language).unwrap(); + let (.., highlight_config) = configs + .iter() + .find(|(config, ..)| config.language_id == language)?; + Some(highlight_config) + }) .collect() // TODO: we collect here to avoid holding the lock, fix later } None => vec![Ok(HighlightEvent::Source { @@ -719,7 +732,16 @@ impl Component for EditorView { for (view, is_focused) in cx.editor.tree.views() { let doc = cx.editor.document(view.doc).unwrap(); - self.render_view(doc, view, area, surface, &cx.editor.theme, is_focused); + let loader = cx.editor.syn_loader.clone(); + self.render_view( + doc, + view, + area, + surface, + &cx.editor.theme, + is_focused, + loader, + ); } if let Some(info) = std::mem::take(&mut cx.editor.autoinfo) { From fd71fdd344aa9a5f375f9d20c3d5365fb6ae7f81 Mon Sep 17 00:00:00 2001 From: Shafkath Shuhan Date: Thu, 8 Jul 2021 22:50:50 -0400 Subject: [PATCH 2/8] wip --- Cargo.lock | 31 ------------------------------- helix-syntax/Cargo.toml | 1 - helix-syntax/src/lib.rs | 4 +--- helix-term/src/ui/editor.rs | 18 ++++++++---------- 4 files changed, 9 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cee641c3d99a..ab3cdd1e180c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -309,15 +309,6 @@ dependencies = [ "regex", ] -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "helix-core" version = "0.3.0" @@ -365,7 +356,6 @@ version = "0.3.0" dependencies = [ "cc", "serde", - "strum", "threadpool", "tree-sitter", ] @@ -943,27 +933,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" -[[package]] -name = "strum" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "syn" version = "1.0.73" diff --git a/helix-syntax/Cargo.toml b/helix-syntax/Cargo.toml index 2bb6dbbccdab..140e3d24c4e7 100644 --- a/helix-syntax/Cargo.toml +++ b/helix-syntax/Cargo.toml @@ -13,7 +13,6 @@ include = ["src/**/*", "languages/**/*", "build.rs", "!**/docs/**/*", "!**/test/ [dependencies] tree-sitter = "0.19" serde = { version = "1.0", features = ["derive"] } -strum = { version = "0.21", features = ["derive"] } [build-dependencies] cc = { version = "1", features = ["parallel"] } diff --git a/helix-syntax/src/lib.rs b/helix-syntax/src/lib.rs index 1edc9cb782cf..5e3bb3ea0a2a 100644 --- a/helix-syntax/src/lib.rs +++ b/helix-syntax/src/lib.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use strum::EnumString; use tree_sitter::Language; #[macro_export] @@ -14,8 +13,7 @@ macro_rules! mk_extern { #[macro_export] macro_rules! mk_enum { ( $( $camel:ident ),* ) => { - #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize, EnumString)] - #[strum(ascii_case_insensitive)] + #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum Lang { $( diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 4573f233e3f1..dd46b5dc4e84 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -19,7 +19,7 @@ use helix_view::{ keyboard::{KeyCode, KeyModifiers}, Document, Editor, Theme, View, }; -use std::{borrow::Cow, str::FromStr, sync::Arc}; +use std::{borrow::Cow, sync::Arc}; use crossterm::event::Event; use tui::buffer::Buffer as Surface; @@ -125,17 +125,15 @@ impl EditorView { let highlights: Vec<_> = match doc.syntax() { Some(syntax) => { let scopes = theme.scopes(); - let configs: Vec<_> = loader - .language_configs_iter() - .map(|x| (x, x.highlight_config(scopes).unwrap())) - .collect(); syntax .highlight_iter(text.slice(..), Some(range), None, |language| { - let language = syntax::Lang::from_str(language).unwrap(); - let (.., highlight_config) = configs - .iter() - .find(|(config, ..)| config.language_id == language)?; - Some(highlight_config) + loader.language_config_for_scope(&format!("source.{}", language)).and_then(|language_config| { + let config = language_config.highlight_config(scopes); + let config_ref = unsafe { + std::mem::transmute::<_, &'static syntax::HighlightConfiguration>(config.as_ref()) + }; + Some(config_ref) + }) }) .collect() // TODO: we collect here to avoid holding the lock, fix later } From 4f71202fe110f345fca0c8236fccf05ceed7b726 Mon Sep 17 00:00:00 2001 From: Shafkath Shuhan Date: Thu, 8 Jul 2021 23:07:09 -0400 Subject: [PATCH 3/8] fixed unsafe --- helix-core/src/syntax.rs | 2 +- helix-term/src/ui/editor.rs | 22 +++++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index 4ba6d1e4b7eb..5b45a88f9b42 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -31,7 +31,7 @@ pub struct Configuration { #[serde(rename_all = "kebab-case")] pub struct LanguageConfiguration { #[serde(rename = "name")] - pub language_id: Lang, + pub(crate) language_id: Lang, pub scope: String, // source.rust pub file_types: Vec, // filename ends_with? pub roots: Vec, // these indicate project roots <.git, Cargo.toml> diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index dd46b5dc4e84..40826d421576 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -127,13 +127,21 @@ impl EditorView { let scopes = theme.scopes(); syntax .highlight_iter(text.slice(..), Some(range), None, |language| { - loader.language_config_for_scope(&format!("source.{}", language)).and_then(|language_config| { - let config = language_config.highlight_config(scopes); - let config_ref = unsafe { - std::mem::transmute::<_, &'static syntax::HighlightConfiguration>(config.as_ref()) - }; - Some(config_ref) - }) + loader + .language_config_for_scope(&format!("source.{}", language)) + .and_then(|language_config| { + let config = language_config.highlight_config(scopes)?; + let config_ref = { + let reference = config.as_ref(); + unsafe { + std::mem::transmute::< + _, + &'static syntax::HighlightConfiguration, + >(reference) + } + }; + Some(config_ref) + }) }) .collect() // TODO: we collect here to avoid holding the lock, fix later } From 3aa96aa0e0564615ed50c2c6eac788f53cd06529 Mon Sep 17 00:00:00 2001 From: Shafkath Shuhan Date: Thu, 8 Jul 2021 23:13:31 -0400 Subject: [PATCH 4/8] fix clippy --- helix-term/src/ui/editor.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 40826d421576..0cdbacfaf59e 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -99,6 +99,7 @@ impl EditorView { self.render_statusline(doc, view, area, surface, theme, is_focused); } + #[allow(clippy::too_many_arguments)] pub fn render_buffer( &self, doc: &Document, @@ -133,6 +134,8 @@ impl EditorView { let config = language_config.highlight_config(scopes)?; let config_ref = { let reference = config.as_ref(); + // Safe because the referenced `HighglightConfiguration` is behind + // an `Arc` that will never be dropped in this function. unsafe { std::mem::transmute::< _, From 5704ae0d83f0537f7cb5131b6e55e7f4b1fa0770 Mon Sep 17 00:00:00 2001 From: Shafkath Shuhan Date: Fri, 9 Jul 2021 11:22:22 -0400 Subject: [PATCH 5/8] move out reference variable --- helix-term/src/ui/editor.rs | 49 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 0cdbacfaf59e..51f8c6fb59f3 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -123,36 +123,35 @@ impl EditorView { }; // TODO: range doesn't actually restrict source, just highlight range - let highlights: Vec<_> = match doc.syntax() { - Some(syntax) => { - let scopes = theme.scopes(); - syntax - .highlight_iter(text.slice(..), Some(range), None, |language| { - loader - .language_config_for_scope(&format!("source.{}", language)) - .and_then(|language_config| { - let config = language_config.highlight_config(scopes)?; - let config_ref = { - let reference = config.as_ref(); + let highlights: Vec<_> = + match doc.syntax() { + Some(syntax) => { + let scopes = theme.scopes(); + syntax + .highlight_iter(text.slice(..), Some(range), None, |language| { + loader + .language_config_for_scope(&format!("source.{}", language)) + .and_then(|language_config| { + let config = language_config.highlight_config(scopes)?; + let config_ref = config.as_ref(); // Safe because the referenced `HighglightConfiguration` is behind // an `Arc` that will never be dropped in this function. - unsafe { + let config_ref = unsafe { std::mem::transmute::< _, &'static syntax::HighlightConfiguration, - >(reference) - } - }; - Some(config_ref) - }) - }) - .collect() // TODO: we collect here to avoid holding the lock, fix later - } - None => vec![Ok(HighlightEvent::Source { - start: range.start, - end: range.end, - })], - }; + >(config_ref) + }; + Some(config_ref) + }) + }) + .collect() // TODO: we collect here to avoid holding the lock, fix later + } + None => vec![Ok(HighlightEvent::Source { + start: range.start, + end: range.end, + })], + }; let mut spans = Vec::new(); let mut visual_x = 0u16; let mut line = 0u16; From 36051a12567c95fe395a05b27f7c0805b0f4b06a Mon Sep 17 00:00:00 2001 From: Shafkath Shuhan Date: Fri, 9 Jul 2021 11:30:50 -0400 Subject: [PATCH 6/8] fmt --- helix-term/src/ui/editor.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 51f8c6fb59f3..42a6913fac2a 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -123,18 +123,17 @@ impl EditorView { }; // TODO: range doesn't actually restrict source, just highlight range - let highlights: Vec<_> = - match doc.syntax() { - Some(syntax) => { - let scopes = theme.scopes(); - syntax - .highlight_iter(text.slice(..), Some(range), None, |language| { - loader + let highlights: Vec<_> = match doc.syntax() { + Some(syntax) => { + let scopes = theme.scopes(); + syntax + .highlight_iter(text.slice(..), Some(range), None, |language| { + loader .language_config_for_scope(&format!("source.{}", language)) .and_then(|language_config| { let config = language_config.highlight_config(scopes)?; let config_ref = config.as_ref(); - // Safe because the referenced `HighglightConfiguration` is behind + // Safe because the referenced `HighlightConfiguration` is behind // an `Arc` that will never be dropped in this function. let config_ref = unsafe { std::mem::transmute::< @@ -144,14 +143,14 @@ impl EditorView { }; Some(config_ref) }) - }) - .collect() // TODO: we collect here to avoid holding the lock, fix later - } - None => vec![Ok(HighlightEvent::Source { - start: range.start, - end: range.end, - })], - }; + }) + .collect() // TODO: we collect here to avoid holding the lock, fix later + } + None => vec![Ok(HighlightEvent::Source { + start: range.start, + end: range.end, + })], + }; let mut spans = Vec::new(); let mut visual_x = 0u16; let mut line = 0u16; From 5fb27682c34c827de859cea98aef4fd3b6716730 Mon Sep 17 00:00:00 2001 From: Shafkath Shuhan Date: Fri, 9 Jul 2021 12:11:28 -0400 Subject: [PATCH 7/8] remove arc --- helix-term/src/ui/editor.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 42a6913fac2a..4148a5f7fe98 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -19,7 +19,7 @@ use helix_view::{ keyboard::{KeyCode, KeyModifiers}, Document, Editor, Theme, View, }; -use std::{borrow::Cow, sync::Arc}; +use std::borrow::Cow; use crossterm::event::Event; use tui::buffer::Buffer as Surface; @@ -64,7 +64,7 @@ impl EditorView { surface: &mut Surface, theme: &Theme, is_focused: bool, - loader: Arc, + loader: &syntax::Loader, ) { let area = Rect::new( view.area.x + OFFSET, @@ -108,7 +108,7 @@ impl EditorView { surface: &mut Surface, theme: &Theme, is_focused: bool, - loader: Arc, + loader: &syntax::Loader, ) { let text = doc.text().slice(..); @@ -739,7 +739,7 @@ impl Component for EditorView { for (view, is_focused) in cx.editor.tree.views() { let doc = cx.editor.document(view.doc).unwrap(); - let loader = cx.editor.syn_loader.clone(); + let loader = &cx.editor.syn_loader; self.render_view( doc, view, From 79d73e21c429d5c1d33f3354e69abad96f33b9fc Mon Sep 17 00:00:00 2001 From: Shafkath Shuhan Date: Sat, 10 Jul 2021 18:05:32 -0400 Subject: [PATCH 8/8] change safety comment --- helix-term/src/ui/editor.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 4148a5f7fe98..9a2fbf571d87 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -133,8 +133,9 @@ impl EditorView { .and_then(|language_config| { let config = language_config.highlight_config(scopes)?; let config_ref = config.as_ref(); - // Safe because the referenced `HighlightConfiguration` is behind - // an `Arc` that will never be dropped in this function. + // SAFETY: the referenced `HighlightConfiguration` behind + // the `Arc` is guaranteed to remain valid throughout the + // duration of the highlight. let config_ref = unsafe { std::mem::transmute::< _,