diff --git a/Cargo.lock b/Cargo.lock index e89696adf..c9e421a28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,24 +2,18 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b476ce7103678b0c6d3d395dbbae31d48ff910bd28be979ba5d48c6351131d0d" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c" - -[[package]] -name = "arc-swap" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" +checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" [[package]] name = "arrayref" @@ -158,9 +152,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "blake2b_simd" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" dependencies = [ "arrayref", "arrayvec", @@ -279,9 +273,9 @@ dependencies = [ [[package]] name = "crossterm" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef9149b29071d44c9fb98fd9c27fcf74405bbdb761889ad6a03f36be93b0b15" +checksum = "4e86d73f2a0b407b5768d10a8c720cf5d2df49a9efc10ca09176d201ead4b7fb" dependencies = [ "bitflags", "crossterm_winapi", @@ -479,6 +473,7 @@ dependencies = [ "jsonrpc-core", "log", "lsp-types", + "once_cell", "pathdiff", "serde", "serde_json", @@ -653,15 +648,15 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "memchr" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "mio" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f1c83949125de4a582aa2da15ae6324d91cf6a58a70ea407643941ff98f558" +checksum = "8962c171f57fcfffa53f4df1bb15ec4c8cf26a7569459c9ceb62d94aab0d9584" dependencies = [ "libc", "log", @@ -707,9 +702,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg", "num-traits", @@ -717,9 +712,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg", ] @@ -837,9 +832,9 @@ dependencies = [ [[package]] name = "proc-macro-hack" -version = "0.5.18" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro-nested" @@ -884,9 +879,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8963b85b8ce3074fecffde43b4b0dded83ce2f367dc8d363afc56679f3ee820b" +checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" dependencies = [ "aho-corasick", "memchr", @@ -896,9 +891,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cab7a364d15cde1e505267766a2d3c4e22a843e1a601f0fa7564c0f82ced11c" +checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" [[package]] name = "ropey" @@ -997,11 +992,10 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035" +checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab" dependencies = [ - "arc-swap", "libc", ] @@ -1079,18 +1073,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" +checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" +checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56" dependencies = [ "proc-macro2", "quote", @@ -1125,9 +1119,9 @@ checksum = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117" [[package]] name = "tree-sitter" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ee7370fec3aecde3862a7d64c571048f70a7298daef1815e8fc68b9de54b5c" +checksum = "d18dcb776d3affaba6db04d11d645946d34a69b3172e588af96ce9fecd20faac" dependencies = [ "cc", "regex", diff --git a/helix-core/src/syntax.rs b/helix-core/src/syntax.rs index f4826fb45..70d42c475 100644 --- a/helix-core/src/syntax.rs +++ b/helix-core/src/syntax.rs @@ -62,6 +62,10 @@ impl LanguageConfiguration { }) .map(Option::as_ref) } + + pub fn scope(&self) -> &str { + &self.scope + } } use once_cell::sync::Lazy; diff --git a/helix-lsp/Cargo.toml b/helix-lsp/Cargo.toml index 0c5d8b918..08216f59c 100644 --- a/helix-lsp/Cargo.toml +++ b/helix-lsp/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] helix-core = { path = "../helix-core" } helix-view = { path = "../helix-view" } +once_cell = "1.4" lsp-types = { version = "0.83", features = ["proposed"] } smol = "1.2" diff --git a/helix-lsp/src/lib.rs b/helix-lsp/src/lib.rs index 1ee8199f4..8353ef7d7 100644 --- a/helix-lsp/src/lib.rs +++ b/helix-lsp/src/lib.rs @@ -4,11 +4,15 @@ mod transport; pub use jsonrpc_core as jsonrpc; pub use lsp_types as lsp; +pub use once_cell::sync::{Lazy, OnceCell}; + pub use client::Client; pub use lsp::{Position, Url}; use thiserror::Error; +use std::{collections::HashMap, sync::Arc}; + #[derive(Error, Debug)] pub enum Error { #[error("protocol error: {0}")] @@ -62,3 +66,52 @@ impl Notification { } pub use jsonrpc::Call; + +type LanguageId = String; + +pub static REGISTRY: Lazy = Lazy::new(Registry::init); + +pub struct Registry { + inner: HashMap>>, +} + +impl Registry { + pub fn init() -> Self { + Self { + inner: HashMap::new(), + } + } + + pub fn get(&self, id: &str, ex: &smol::Executor) -> Option> { + // TODO: use get_or_try_init and propagate the error + self.inner + .get(id) + .map(|cell| { + cell.get_or_init(|| { + // TODO: lookup defaults for id (name, args) + + // initialize a new client + let client = Client::start(&ex, "rust-analyzer", &[]); + // TODO: also call initialize().await() + Arc::new(client) + }) + }) + .cloned() + } +} + +// REGISTRY = HashMap>> +// spawn one server per language type, need to spawn one per workspace if server doesn't support +// workspaces +// +// could also be a client per root dir +// +// storing a copy of Option>> on Document would make the LSP client easily +// accessible during edit/save callbacks +// +// the event loop needs to process all incoming streams, maybe we can just have that be a separate +// task that's continually running and store the state on the client, then use read lock to +// retrieve data during render +// -> PROBLEM: how do you trigger an update on the editor side when data updates? +// +// -> The data updates should pull all events until we run out so we don't frequently re-render diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index cacfde56a..141779ecc 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -636,9 +636,17 @@ impl<'a> Application<'a> { } } Some(Call::MethodCall(call)) => { - // TODO: need to make Result - - unimplemented!("{:?}", call) + debug!("Method not found {}", call.method); + + self.language_server.reply( + call.id, + // TODO: make a Into trait that can cast to Err(jsonrpc::Error) + Err(helix_lsp::jsonrpc::Error { + code: helix_lsp::jsonrpc::ErrorCode::MethodNotFound, + message: "Method not found".to_string(), + data: None, + }), + ); } _ => unreachable!(), } diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 1587de8b5..e8f311c51 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -25,6 +25,8 @@ pub struct Document { /// Tree-sitter AST tree pub syntax: Option, + /// Corresponding language scope name. Usually `source.`. + pub language: Option, /// Pending changes since last history commit. pub changes: ChangeSet, @@ -64,6 +66,7 @@ impl Document { mode: Mode::Normal, restore_cursor: false, syntax: None, + language: None, changes, old_state, diagnostics: Vec::new(), @@ -73,6 +76,7 @@ impl Document { } // TODO: passing scopes here is awkward + // TODO: async fn? pub fn load(path: PathBuf, scopes: &[String]) -> Result { use std::{env, fs::File, io::BufReader}; let _current_dir = env::current_dir()?; @@ -90,6 +94,15 @@ impl Document { let syntax = Syntax::new(&doc.state.doc, highlight_config.clone()); doc.syntax = Some(syntax); + // TODO: maybe just keep an Arc<> pointer to the language_config? + doc.language = Some(language_config.scope().to_string()); + + // TODO: this ties lsp support to tree-sitter enabled languages for now. Language + // config should use Option to let us have non-tree-sitter configs. + + // TODO: circular dep: view <-> lsp + // helix_lsp::REGISTRY; + // view should probably depend on lsp }; // canonicalize path to absolute value @@ -98,6 +111,8 @@ impl Document { Ok(doc) } + // TODO: do we need some way of ensuring two save operations on the same doc can't run at once? + // or is that handled by the OS/async layer pub fn save(&self) -> impl Future> { // we clone and move text + path into the future so that we asynchronously save the current // state without blocking any further edits.