diff --git a/Cargo.lock b/Cargo.lock index 4e0fc699..ec12d0f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + [[package]] name = "async-trait" version = "0.1.77" @@ -281,6 +287,15 @@ dependencies = [ "itertools 0.10.5", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -306,6 +321,16 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "ctrlc" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" +dependencies = [ + "nix", + "windows-sys 0.52.0", +] + [[package]] name = "either" version = "1.9.0" @@ -408,6 +433,20 @@ dependencies = [ "smallvec", ] +[[package]] +name = "harper-ls" +version = "0.1.0" +dependencies = [ + "anyhow", + "ctrlc", + "lsp-server", + "lsp-types", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + [[package]] name = "harper-serve" version = "0.1.0" @@ -498,6 +537,16 @@ dependencies = [ "want", ] +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "is-macro" version = "0.3.5" @@ -588,6 +637,31 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "lsp-server" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248f65b78f6db5d8e1b1604b4098a28b43d21a8eb1deeca22b1c421b276c7095" +dependencies = [ + "crossbeam-channel", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "lsp-types" +version = "0.95.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "158c1911354ef73e8fe42da6b10c0484cb65c7f1007f28022e847706c1ab6984" +dependencies = [ + "bitflags 1.3.2", + "serde", + "serde_json", + "serde_repr", + "url", +] + [[package]] name = "matchit" version = "0.7.3" @@ -626,6 +700,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "libc", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -945,6 +1030,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1028,6 +1124,21 @@ dependencies = [ "serde_json", ] +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.35.1" @@ -1161,12 +1272,39 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + [[package]] name = "valuable" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 32d1c503..148b1be9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = [ "harper-core", "harper-serve", "harper-wasm"] +members = [ "harper-core", "harper-ls", "harper-serve", "harper-wasm"] resolver = "2" diff --git a/harper-ls/Cargo.toml b/harper-ls/Cargo.toml new file mode 100644 index 00000000..feb0824f --- /dev/null +++ b/harper-ls/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "harper-ls" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.79" +ctrlc = "3.4.2" +lsp-server = "0.7.6" +lsp-types = "0.95.0" +serde = "1.0.195" +serde_json = "1.0.111" +tracing = "0.1.40" +tracing-subscriber = "0.3.18" diff --git a/harper-ls/src/main.rs b/harper-ls/src/main.rs new file mode 100644 index 00000000..d7671a9d --- /dev/null +++ b/harper-ls/src/main.rs @@ -0,0 +1,97 @@ +use lsp_types::{ + request::GotoDefinition, GotoDefinitionResponse, InitializeParams, ServerCapabilities, +}; +use lsp_types::{Location, OneOf, Position}; + +use lsp_server::{Connection, ExtractError, Message, Request, RequestId, Response}; +use tracing::{info, Level}; + +fn main() -> anyhow::Result<()> { + let subscriber = tracing_subscriber::FmtSubscriber::builder() + .with_max_level(Level::DEBUG) + .finish(); + + tracing::subscriber::set_global_default(subscriber)?; + + let (connection, io_threads) = Connection::listen("127.0.0.1:4000")?; + + let server_capabilities = serde_json::to_value(ServerCapabilities { + definition_provider: Some(OneOf::Left(true)), + ..Default::default() + }) + .unwrap(); + let initialization_params = match connection.initialize(server_capabilities) { + Ok(it) => it, + Err(e) => { + if e.channel_is_disconnected() { + io_threads.join()?; + } + return Err(e.into()); + } + }; + main_loop(connection, initialization_params)?; + io_threads.join()?; + + info!("Shutting down server.c"); + Ok(()) +} + +fn main_loop(connection: Connection, params: serde_json::Value) -> anyhow::Result<()> { + let _params: InitializeParams = serde_json::from_value(params).unwrap(); + info!("Starting example main loop"); + for msg in &connection.receiver { + info!("Got msg: {msg:?}"); + match msg { + Message::Request(req) => { + if connection.handle_shutdown(&req)? { + return Ok(()); + } + info!("Got request: {req:?}"); + match cast::(req) { + Ok((id, params)) => { + info!("Got gotoDefinition request #{id}: {params:?}"); + let result = Some(GotoDefinitionResponse::Array(vec![Location { + uri: params.text_document_position_params.text_document.uri, + range: lsp_types::Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + }])); + let result = serde_json::to_value(&result).unwrap(); + let resp = Response { + id, + result: Some(result), + error: None, + }; + connection.sender.send(Message::Response(resp))?; + continue; + } + Err(err @ ExtractError::JsonError { .. }) => panic!("{err:?}"), + Err(ExtractError::MethodMismatch(req)) => req, + }; + } + Message::Response(resp) => { + info!("Got response: {resp:?}"); + } + Message::Notification(not) => { + info!("Got notification: {not:?}"); + } + } + } + + Ok(()) +} + +fn cast(req: Request) -> Result<(RequestId, R::Params), ExtractError> +where + R: lsp_types::request::Request, + R::Params: serde::de::DeserializeOwned, +{ + req.extract(R::METHOD) +} diff --git a/nvim.lua b/nvim.lua new file mode 100644 index 00000000..9055ffd4 --- /dev/null +++ b/nvim.lua @@ -0,0 +1,5 @@ +vim.lsp.start({ + name = "example", + cmd = vim.lsp.rpc.connect("127.0.0.1", 4000), + root_dir = "." +})