aboutsummaryrefslogtreecommitdiff
path: root/helix-syntax/src/lib.rs
diff options
context:
space:
mode:
authorBlaž Hrastnik2021-07-11 10:36:45 +0000
committerBlaž Hrastnik2021-07-14 01:00:05 +0000
commitdd2903ff10387c04e933aa37846663131297b8b3 (patch)
tree97a6d2d98e8cf350e1e32cad28c7a83483649be9 /helix-syntax/src/lib.rs
parentdd5e8082e410032c9782835cf0fc52a469d050b1 (diff)
Dynamically load grammar libraries at runtime
Diffstat (limited to 'helix-syntax/src/lib.rs')
-rw-r--r--helix-syntax/src/lib.rs115
1 files changed, 30 insertions, 85 deletions
diff --git a/helix-syntax/src/lib.rs b/helix-syntax/src/lib.rs
index 5e3bb3ea..b6c0ecf3 100644
--- a/helix-syntax/src/lib.rs
+++ b/helix-syntax/src/lib.rs
@@ -1,94 +1,39 @@
-use serde::{Deserialize, Serialize};
+use anyhow::{Context, Result};
+use libloading::{Library, Symbol};
use tree_sitter::Language;
-#[macro_export]
-macro_rules! mk_extern {
- ( $( $name:ident ),* ) => {
- $(
- extern "C" { pub fn $name() -> Language; }
- )*
- };
-}
-
-#[macro_export]
-macro_rules! mk_enum {
- ( $( $camel:ident ),* ) => {
- #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
- #[serde(rename_all = "lowercase")]
- pub enum Lang {
- $(
- $camel,
- )*
+fn replace_dashes_with_underscores(name: &str) -> String {
+ let mut result = String::with_capacity(name.len());
+ for c in name.chars() {
+ if c == '-' {
+ result.push('_');
+ } else {
+ result.push(c);
}
- };
+ }
+ result
}
+#[cfg(unix)]
+const DYLIB_EXTENSION: &str = "so";
-#[macro_export]
-macro_rules! mk_get_language {
- ( $( ($camel:ident, $name:ident) ),* ) => {
- #[must_use]
- pub fn get_language(lang: Lang) -> Language {
- unsafe {
- match lang {
- $(
- Lang::$camel => $name(),
- )*
- }
- }
- }
- };
-}
+#[cfg(windows)]
+const DYLIB_EXTENSION: &str = "dll";
-#[macro_export]
-macro_rules! mk_get_language_name {
- ( $( $camel:ident ),* ) => {
- #[must_use]
- pub const fn get_language_name(lang: Lang) -> &'static str {
- match lang {
- $(
- Lang::$camel => stringify!($camel),
- )*
- }
- }
- };
-}
+pub fn get_language(runtime_path: &std::path::Path, name: &str) -> Result<Language> {
+ let name = name.to_ascii_lowercase();
+ let mut library_path = runtime_path.join("grammars").join(&name);
+ // TODO: duplicated under build
+ library_path.set_extension(DYLIB_EXTENSION);
-#[macro_export]
-macro_rules! mk_langs {
- ( $( ($camel:ident, $name:ident) ),* ) => {
- mk_extern!($( $name ),*);
- mk_enum!($( $camel ),*);
- mk_get_language!($( ($camel, $name) ),*);
- mk_get_language_name!($( $camel ),*);
+ let library = unsafe { Library::new(&library_path) }
+ .with_context(|| format!("Error opening dynamic library {:?}", &library_path))?;
+ let language_fn_name = format!("tree_sitter_{}", replace_dashes_with_underscores(&name));
+ let language = unsafe {
+ let language_fn: Symbol<unsafe extern "C" fn() -> Language> = library
+ .get(language_fn_name.as_bytes())
+ .with_context(|| format!("Failed to load symbol {}", language_fn_name))?;
+ language_fn()
};
+ std::mem::forget(library);
+ Ok(language)
}
-
-mk_langs!(
- // 1) Name for enum
- // 2) tree-sitter function to call to get a Language
- (Agda, tree_sitter_agda),
- (Bash, tree_sitter_bash),
- (Cpp, tree_sitter_cpp),
- (CSharp, tree_sitter_c_sharp),
- (Css, tree_sitter_css),
- (C, tree_sitter_c),
- (Elixir, tree_sitter_elixir),
- (Go, tree_sitter_go),
- // (Haskell, tree_sitter_haskell),
- (Html, tree_sitter_html),
- (Javascript, tree_sitter_javascript),
- (Java, tree_sitter_java),
- (Json, tree_sitter_json),
- (Julia, tree_sitter_julia),
- (Latex, tree_sitter_latex),
- (Nix, tree_sitter_nix),
- (Php, tree_sitter_php),
- (Python, tree_sitter_python),
- (Ruby, tree_sitter_ruby),
- (Rust, tree_sitter_rust),
- (Scala, tree_sitter_scala),
- (Swift, tree_sitter_swift),
- (Toml, tree_sitter_toml),
- (Tsx, tree_sitter_tsx),
- (Typescript, tree_sitter_typescript)
-);