diff --git a/Cargo.lock b/Cargo.lock index 6c6140f..d4bded0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,6 +292,12 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "httparse" version = "1.10.1" @@ -474,6 +480,7 @@ version = "0.3.6-alpha.1" dependencies = [ "cargo_metadata", "dashmap 6.1.0", + "heck", "mist-codegen", "mist-parser", "pest", diff --git a/crates/analyzer/Cargo.toml b/crates/analyzer/Cargo.toml index 17e742a..0b830f2 100644 --- a/crates/analyzer/Cargo.toml +++ b/crates/analyzer/Cargo.toml @@ -21,3 +21,4 @@ cargo_metadata = "0.23.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" ropey = "1" +heck = "0.5.0" diff --git a/crates/analyzer/src/lib.rs b/crates/analyzer/src/lib.rs index 7a7b835..c7d2d53 100644 --- a/crates/analyzer/src/lib.rs +++ b/crates/analyzer/src/lib.rs @@ -6,6 +6,7 @@ use std::path::{Component, Path, PathBuf}; use std::sync::Arc; use std::sync::atomic::{AtomicU64, Ordering}; +use heck::ToSnakeCase; use mist_parser::error::ParseError; use mist_parser::rev_mapper::{Mapping, MistMap, RustMap}; use ropey::Rope; @@ -864,12 +865,74 @@ impl LanguageServer for Backend { self.client .log_message(MessageType::INFO, "server initialized!") .await; + + let registration = Registration { + id: "watch-mist-files".to_string(), + method: "workspace/didChangeWatchedFiles".to_string(), + register_options: Some( + serde_json::to_value(DidChangeWatchedFilesRegistrationOptions { + watchers: vec![FileSystemWatcher { + glob_pattern: GlobPattern::String("**/*.mist".to_string()), + kind: Some(WatchKind::Create), + }], + }) + .unwrap(), + ), + }; + + let _ = self.client.register_capability(vec![registration]).await; } async fn shutdown(&self) -> tower_lsp::jsonrpc::Result<()> { Ok(()) } + async fn did_change_watched_files(&self, params: DidChangeWatchedFilesParams) { + for change in params.changes { + if change.typ == FileChangeType::CREATED { + if let Ok(path) = change.uri.to_file_path() { + if let Some(file_stem) = + path.file_stem().map(|v| v.to_string_lossy().to_string()) + { + let snake_module_name = file_stem.to_snake_case(); + let insert_text = format!("pub module {};\n", snake_module_name); + + let text_edit = TextEdit { + range: Range { + start: Position { + line: 0, + character: 0, + }, + end: Position { + line: 0, + character: 0, + }, + }, + new_text: insert_text, + }; + + let mut changes = std::collections::HashMap::new(); + changes.insert(change.uri.clone(), vec![text_edit]); + + let workspace_edit = WorkspaceEdit { + changes: Some(changes), + ..Default::default() + }; + + if let Err(e) = self.client.apply_edit(workspace_edit).await { + self.client + .log_message( + MessageType::ERROR, + format!("Failed to auto-insert module: {}", e), + ) + .await; + } + } + } + } + } + } + async fn did_open(&self, params: DidOpenTextDocumentParams) { let uri = params.text_document.uri; let mist_path = match uri.to_file_path() {