on master help sign in
migrate helix-syntax crate into helix-core and helix-term
eeb3f8eMichael Davis
Cargo.lock+4−12
@@ -358,11 +358,12 @@ dependencies = [
358name = "helix-core"
358name = "helix-core"
359version = "0.6.0"
359version = "0.6.0"
360dependencies = [
360dependencies = [
361+ "anyhow",
361 "arc-swap",
362 "arc-swap",
362 "chrono",
363 "chrono",
363 "encoding_rs",
364 "encoding_rs",
364 "etcetera",
365 "etcetera",
365− "helix-syntax",
366+ "libloading",
366 "log",
367 "log",
367 "once_cell",
368 "once_cell",
368 "quickcheck",
369 "quickcheck",
@@ -415,22 +416,12 @@ dependencies = [
415 "which",
416 "which",
416]
417]
417
418
418−[[package]]
419−name = "helix-syntax"
420−version = "0.6.0"
421−dependencies = [
422− "anyhow",
423− "cc",
424− "libloading",
425− "threadpool",
426− "tree-sitter",
427−]
428−
429[[package]]
419[[package]]
430name = "helix-term"
420name = "helix-term"
431version = "0.6.0"
421version = "0.6.0"
432dependencies = [
422dependencies = [
433 "anyhow",
423 "anyhow",
424+ "cc",
434 "chrono",
425 "chrono",
435 "content_inspector",
426 "content_inspector",
436 "crossterm",
427 "crossterm",
@@ -454,6 +445,7 @@ dependencies = [
454 "serde_json",
445 "serde_json",
455 "signal-hook",
446 "signal-hook",
456 "signal-hook-tokio",
447 "signal-hook-tokio",
448+ "threadpool",
457 "tokio",
449 "tokio",
458 "tokio-stream",
450 "tokio-stream",
459 "toml",
451 "toml",
Cargo.toml−5
@@ -4,7 +4,6 @@ members = [
4 "helix-view",
4 "helix-view",
5 "helix-term",
5 "helix-term",
6 "helix-tui",
6 "helix-tui",
7− "helix-syntax",
8 "helix-lsp",
7 "helix-lsp",
9 "helix-dap",
8 "helix-dap",
10 "xtask",
9 "xtask",
@@ -14,10 +13,6 @@ default-members = [
14 "helix-term"
13 "helix-term"
15]
14]
16
15
17−# Build helix-syntax in release mode to make the code path faster in development.
18−# [profile.dev.package."helix-syntax"]
19−# opt-level = 3
20−
21[profile.dev]
16[profile.dev]
22split-debuginfo = "unpacked"
17split-debuginfo = "unpacked"
23
18
docs/architecture.md+6−7
@@ -1,11 +1,10 @@
1
1
2−| Crate | Description |
2+| Crate | Description |
3−| ----------- | ----------- |
3+| ----------- | ----------- |
4−| helix-core | Core editing primitives, functional. |
4+| helix-core | Core editing primitives, functional. |
5−| helix-syntax | Tree-sitter grammars |
6−| helix-lsp | Language server client |
5+| helix-lsp | Language server client |
7−| helix-view | UI abstractions for use in backends, imperative shell. |
6+| helix-view | UI abstractions for use in backends, imperative shell. |
8−| helix-term | Terminal UI |
7+| helix-term | Terminal UI |
9| helix-tui | TUI primitives, forked from tui-rs, inspired by Cursive |
8| helix-tui | TUI primitives, forked from tui-rs, inspired by Cursive |
10
9
11
10
helix-core/Cargo.toml+3−2
@@ -13,8 +13,6 @@ include = ["src/**/*", "README.md"]
13[features]
13[features]
14
14
15[dependencies]
15[dependencies]
16−helix-syntax = { version = "0.6", path = "../helix-syntax" }
17−
18ropey = "1.3"
16ropey = "1.3"
19smallvec = "1.8"
17smallvec = "1.8"
20smartstring = "1.0.0"
18smartstring = "1.0.0"
@@ -40,5 +38,8 @@ encoding_rs = "0.8"
40
38
41chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
39chrono = { version = "0.4", default-features = false, features = ["alloc", "std"] }
42
40
41+libloading = "0.7"
42+anyhow = "1"
43+
43[dev-dependencies]
44[dev-dependencies]
44quickcheck = { version = "1", default-features = false }
45quickcheck = { version = "1", default-features = false }
helix-core/src/syntax.rs+33−3
@@ -7,7 +7,9 @@ use crate::{
7 Rope, RopeSlice, Tendril,
7 Rope, RopeSlice, Tendril,
8};
8};
9
9
10−pub use helix_syntax::get_language;
10+use anyhow::{Context, Result};
11+use libloading::{Library, Symbol};
12+use tree_sitter::Language;
11
13
12use arc_swap::{ArcSwap, Guard};
14use arc_swap::{ArcSwap, Guard};
13use slotmap::{DefaultKey as LayerId, HopSlotMap};
15use slotmap::{DefaultKey as LayerId, HopSlotMap};
@@ -25,6 +27,34 @@ use std::{
25use once_cell::sync::{Lazy, OnceCell};
27use once_cell::sync::{Lazy, OnceCell};
26use serde::{Deserialize, Serialize};
28use serde::{Deserialize, Serialize};
27
29
30+#[cfg(unix)]
31+pub const DYLIB_EXTENSION: &str = "so";
32+
33+#[cfg(windows)]
34+pub const DYLIB_EXTENSION: &str = "dll";
35+
36+fn replace_dashes_with_underscores(name: &str) -> String {
37+ name.replace('-', "_")
38+}
39+
40+pub fn get_language(runtime_path: &std::path::Path, name: &str) -> Result<Language> {
41+ let name = name.to_ascii_lowercase();
42+ let mut library_path = runtime_path.join("grammars").join(&name);
43+ library_path.set_extension(DYLIB_EXTENSION);
44+
45+ let library = unsafe { Library::new(&library_path) }
46+ .with_context(|| format!("Error opening dynamic library {:?}", &library_path))?;
47+ let language_fn_name = format!("tree_sitter_{}", replace_dashes_with_underscores(&name));
48+ let language = unsafe {
49+ let language_fn: Symbol<unsafe extern "C" fn() -> Language> = library
50+ .get(language_fn_name.as_bytes())
51+ .with_context(|| format!("Failed to load symbol {}", language_fn_name))?;
52+ language_fn()
53+ };
54+ std::mem::forget(library);
55+ Ok(language)
56+}
57+
28fn deserialize_regex<'de, D>(deserializer: D) -> Result<Option<Regex>, D::Error>
58fn deserialize_regex<'de, D>(deserializer: D) -> Result<Option<Regex>, D::Error>
29where
59where
30 D: serde::Deserializer<'de>,
60 D: serde::Deserializer<'de>,
@@ -426,7 +456,7 @@ impl LanguageConfiguration {
426 &injections_query,
456 &injections_query,
427 &locals_query,
457 &locals_query,
428 )
458 )
429− .unwrap(); // TODO: avoid panic
459+ .unwrap_or_else(|query_error| panic!("Could not parse queries for language {:?}. Are your grammars out of sync? Try running 'hx --fetch-grammars' and 'hx --build-grammars'. This query could not be parsed: {:?}", self.language_id, query_error));
430
460
431 config.configure(scopes);
461 config.configure(scopes);
432 Some(Arc::new(config))
462 Some(Arc::new(config))
@@ -2023,7 +2053,7 @@ mod test {
2023 );
2053 );
2024
2054
2025 let loader = Loader::new(Configuration { language: vec![] });
2055 let loader = Loader::new(Configuration { language: vec![] });
2026− let language = get_language(&crate::RUNTIME_DIR, "Rust").unwrap();
2056+ let language = get_language("Rust").unwrap();
2027
2057
2028 let query = Query::new(language, query_str).unwrap();
2058 let query = Query::new(language, query_str).unwrap();
2029 let textobject = TextObjectQuery { query };
2059 let textobject = TextObjectQuery { query };
helix-syntax/Cargo.tomldeleted−21
@@ -1,21 +0,0 @@
1−[package]
2−name = "helix-syntax"
3−version = "0.6.0"
4−authors = ["Blaž Hrastnik <blaz@mxxn.io>"]
5−edition = "2021"
6−license = "MPL-2.0"
7−description = "Tree-sitter grammars support"
8−categories = ["editor"]
9−repository = "https://github.com/helix-editor/helix"
10−homepage = "https://helix-editor.com"
11−include = ["src/**/*", "languages/**/*", "build.rs", "!**/docs/**/*", "!**/test/**/*", "!**/examples/**/*", "!**/build/**/*"]
12−
13−[dependencies]
14−tree-sitter = "0.20"
15−libloading = "0.7"
16−anyhow = "1"
17−
18−[build-dependencies]
19−cc = { version = "1" }
20−threadpool = { version = "1.0" }
21−anyhow = "1"
helix-syntax/README.mddeleted−13
@@ -1,13 +0,0 @@
1−helix-syntax
2−============
3−
4−Syntax highlighting for helix, (shallow) submodules resides here.
5−
6−Differences from nvim-treesitter
7−--------------------------------
8−
9−As the syntax are commonly ported from
10−<https://github.com/nvim-treesitter/nvim-treesitter>.
11−
12−Note that we do not support the custom `#any-of` predicate which is
13−supported by neovim so one needs to change it to `#match` with regex.
helix-syntax/src/lib.rsdeleted−31
@@ -1,31 +0,0 @@
1−use anyhow::{Context, Result};
2−use libloading::{Library, Symbol};
3−use tree_sitter::Language;
4−
5−fn replace_dashes_with_underscores(name: &str) -> String {
6− name.replace('-', "_")
7−}
8−#[cfg(unix)]
9−const DYLIB_EXTENSION: &str = "so";
10−
11−#[cfg(windows)]
12−const DYLIB_EXTENSION: &str = "dll";
13−
14−pub fn get_language(runtime_path: &std::path::Path, name: &str) -> Result<Language> {
15− let name = name.to_ascii_lowercase();
16− let mut library_path = runtime_path.join("grammars").join(&name);
17− // TODO: duplicated under build
18− library_path.set_extension(DYLIB_EXTENSION);
19−
20− let library = unsafe { Library::new(&library_path) }
21− .with_context(|| format!("Error opening dynamic library {:?}", &library_path))?;
22− let language_fn_name = format!("tree_sitter_{}", replace_dashes_with_underscores(&name));
23− let language = unsafe {
24− let language_fn: Symbol<unsafe extern "C" fn() -> Language> = library
25− .get(language_fn_name.as_bytes())
26− .with_context(|| format!("Failed to load symbol {}", language_fn_name))?;
27− language_fn()
28− };
29− std::mem::forget(library);
30− Ok(language)
31−}
helix-term/Cargo.toml+4
@@ -66,5 +66,9 @@ grep-searcher = "0.1.8"
66# Remove once retain_mut lands in stable rust
66# Remove once retain_mut lands in stable rust
67retain_mut = "0.1.7"
67retain_mut = "0.1.7"
68
68
69+# compiling grammars
70+cc = { version = "1" }
71+threadpool = { version = "1.0" }
72+
69[target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100
73[target.'cfg(not(windows))'.dependencies] # https://github.com/vorner/signal-hook/issues/100
70signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
74signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
helix-term/build.rs+5
@@ -14,5 +14,10 @@ fn main() {
14 None => env!("CARGO_PKG_VERSION").into(),
14 None => env!("CARGO_PKG_VERSION").into(),
15 };
15 };
16
16
17+ println!(
18+ "cargo:rustc-env=BUILD_TARGET={}",
19+ std::env::var("TARGET").unwrap()
20+ );
21+
17 println!("cargo:rustc-env=VERSION_AND_GIT_HASH={}", version);
22 println!("cargo:rustc-env=VERSION_AND_GIT_HASH={}", version);
18}
23}
helix-syntax/build.rs → helix-term/src/grammars.rsrenamed+16−47
@@ -6,11 +6,13 @@ use std::{
6 process::Command,
6 process::Command,
7};
7};
8
8
9−use std::sync::mpsc::channel;
9+use helix_core::syntax::DYLIB_EXTENSION;
10
10
11+const BUILD_TARGET: &str = env!("BUILD_TARGET");
12+
11−fn collect_tree_sitter_dirs(ignore: &[String]) -> Result<Vec<String>> {
13+pub fn collect_tree_sitter_dirs(ignore: &[String]) -> Result<Vec<String>> {
12 let mut dirs = Vec::new();
14 let mut dirs = Vec::new();
13− let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("languages");
15+ let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../helix-syntax/languages");
14
16
15 for entry in fs::read_dir(path)? {
17 for entry in fs::read_dir(path)? {
16 let entry = entry?;
18 let entry = entry?;
@@ -32,12 +34,6 @@ fn collect_tree_sitter_dirs(ignore: &[String]) -> Result<Vec<String>> {
32 Ok(dirs)
34 Ok(dirs)
33}
35}
34
36
35−#[cfg(unix)]
36−const DYLIB_EXTENSION: &str = "so";
37−
38−#[cfg(windows)]
39−const DYLIB_EXTENSION: &str = "dll";
40−
41fn build_library(src_path: &Path, language: &str) -> Result<()> {
37fn build_library(src_path: &Path, language: &str) -> Result<()> {
42 let header_path = src_path;
38 let header_path = src_path;
43 // let grammar_path = src_path.join("grammar.json");
39 // let grammar_path = src_path.join("grammar.json");
@@ -65,7 +61,12 @@ fn build_library(src_path: &Path, language: &str) -> Result<()> {
65 return Ok(());
61 return Ok(());
66 }
62 }
67 let mut config = cc::Build::new();
63 let mut config = cc::Build::new();
64+ config
65+ .cpp(true)
66+ .opt_level(2)
68− config.cpp(true).opt_level(2).cargo_metadata(false);
67+ .cargo_metadata(false)
68+ .host(BUILD_TARGET)
69+ .target(BUILD_TARGET);
69 let compiler = config.get_compiler();
70 let compiler = config.get_compiler();
70 let mut command = Command::new(compiler.path());
71 let mut command = Command::new(compiler.path());
71 command.current_dir(src_path);
72 command.current_dir(src_path);
@@ -148,9 +149,10 @@ fn mtime(path: &Path) -> Result<SystemTime> {
148 Ok(fs::metadata(path)?.modified()?)
149 Ok(fs::metadata(path)?.modified()?)
149}
150}
150
151
151−fn build_dir(dir: &str, language: &str) {
152+pub fn build_dir(dir: &str, language: &str) {
152 println!("Build language {}", language);
153 println!("Build language {}", language);
153− if PathBuf::from("languages")
154+ if PathBuf::from(env!("CARGO_MANIFEST_DIR"))
155+ .join("../helix-syntax/languages")
154 .join(dir)
156 .join(dir)
155 .read_dir()
157 .read_dir()
156 .unwrap()
158 .unwrap()
@@ -158,49 +160,16 @@ fn build_dir(dir: &str, language: &str) {
158 .is_none()
160 .is_none()
159 {
161 {
160 eprintln!(
162 eprintln!(
161− "The directory {} is empty, you probably need to use 'git submodule update --init --recursive'?",
163+ "The directory {} is empty, you probably need to use './scripts/grammars sync'?",
162 dir
164 dir
163 );
165 );
164 std::process::exit(1);
166 std::process::exit(1);
165 }
167 }
166
168
167 let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
169 let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
168− .join("languages")
170+ .join("../helix-syntax/languages")
169 .join(dir)
171 .join(dir)
170 .join("src");
172 .join("src");
171
173
172 build_library(&path, language).unwrap();
174 build_library(&path, language).unwrap();
173}
175}
174−
175−fn main() {
176− let ignore = vec![
177− "tree-sitter-typescript".to_string(),
178− "tree-sitter-ocaml".to_string(),
179− ];
180− let dirs = collect_tree_sitter_dirs(&ignore).unwrap();
181−
182− let mut n_jobs = 0;
183− let pool = threadpool::Builder::new().build(); // by going through the builder, it'll use num_cpus
184− let (tx, rx) = channel();
185−
186− for dir in dirs {
187− let tx = tx.clone();
188− n_jobs += 1;
189−
190− pool.execute(move || {
191− let language = &dir.strip_prefix("tree-sitter-").unwrap();
192− build_dir(&dir, language);
193−
194− // report progress
195− tx.send(1).unwrap();
196− });
197− }
198− pool.join();
199− // drop(tx);
200− assert_eq!(rx.try_iter().sum::<usize>(), n_jobs);
201−
202− build_dir("tree-sitter-typescript/tsx", "tsx");
203− build_dir("tree-sitter-typescript/typescript", "typescript");
204− build_dir("tree-sitter-ocaml/ocaml", "ocaml");
205− build_dir("tree-sitter-ocaml/interface", "ocaml-interface")
206−}
helix-term/src/lib.rs+1
@@ -7,6 +7,7 @@ pub mod commands;
7pub mod compositor;
7pub mod compositor;
8pub mod config;
8pub mod config;
9pub mod health;
9pub mod health;
10+pub mod grammars;
10pub mod job;
11pub mod job;
11pub mod keymap;
12pub mod keymap;
12pub mod ui;
13pub mod ui;