diff --git a/Cargo.toml b/Cargo.toml index 810f9664..6c8bf18c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] -members = ["parser", "cli", "typechecker", "ruff_python_import_resolver"] - +members = ["parser", "cli", "typechecker", "ruff_python_import_resolver", "lsp"] +resolver = "2" [workspace.dependencies] log = { version = "0.4.17" } diff --git a/lsp/Cargo.toml b/lsp/Cargo.toml new file mode 100644 index 00000000..6a834396 --- /dev/null +++ b/lsp/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "lsp" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +typechecker = { path = "../typechecker" } +parser = { path = "../parser" } +env_logger = "0.9.0" +serde_json = "1.0.78" +tokio = { version = "1.17.0", features = ["full"] } +tower-lsp = { version = "0.19.0", features = ["proposed"]} +serde = { version = "1.0", features = ["derive"] } +dashmap = "5.1.0" +log = "0.4.14" +im-rc = "15.0.0" diff --git a/lsp/src/main.rs b/lsp/src/main.rs new file mode 100644 index 00000000..b6b811de --- /dev/null +++ b/lsp/src/main.rs @@ -0,0 +1,99 @@ +use std::path::PathBuf; + +use tower_lsp::jsonrpc::Result; +use tower_lsp::lsp_types::*; +use tower_lsp::{Client, LanguageServer, LspService, Server}; + +use typechecker::build::BuildManager; +use typechecker::settings::{ImportDiscovery, Settings}; + +#[derive(Debug)] +struct Backend { + client: Client, +} + +#[tower_lsp::async_trait] +impl LanguageServer for Backend { + async fn initialize(&self, params: InitializeParams) -> Result { + Ok(InitializeResult::default()) + } + + async fn initialized(&self, _: InitializedParams) { + self.client + .log_message(MessageType::INFO, "server initialized!") + .await; + } + + #[allow(unused_variables)] + async fn did_open(&self, params: DidOpenTextDocumentParams) { + self.client + .log_message(MessageType::INFO, "file opened!") + .await; + let uri = params.text_document.uri; + // check if the uri is path buf or just return + let path = uri.to_file_path().unwrap_or_default(); + let file_name = path + .file_name() + .unwrap_or_default() + .to_str() + .unwrap_or_default(); + let file_name = file_name.to_string(); + let file_content = params.text_document.text; + let settings = Settings { + debug: true, + root: path.clone(), + import_discovery: ImportDiscovery { + python_executable: None, + }, + }; + let mut build_manager = BuildManager::new(vec![], settings); + build_manager.add_source(&path); + build_manager.build(); + let errs = build_manager.get_errors(); + for err in errs { + self.client + .publish_diagnostics( + uri.clone(), + vec![Diagnostic { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + severity: Some(DiagnosticSeverity::ERROR), + code: None, + code_description: None, + source: Some("typechecker".to_string()), + message: err, + related_information: None, + tags: None, + data: None, + }], + None, + ) + .await; + } + } + + async fn shutdown(&self) -> Result<()> { + Ok(()) + } +} + +#[tokio::main] +async fn main() { + let stdin = tokio::io::stdin(); + let stdout = tokio::io::stdout(); + + let build_manager = Box::new(BuildManager::new(vec![], Settings::test_settings())); + let (service, socket) = LspService::new(|client| Backend { + client, + build_manager, + }); + Server::new(stdin, stdout, socket).serve(service).await; +}