From 70ec348f4d92849e0853df4d562bf6d4ffda771c Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 14 Jul 2026 07:15:17 +0200 Subject: [PATCH 1/8] Fix mutability #119 --- crates/codegen/src/class_decl.rs | 2 +- mist-test/src/items/class_test.mist | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/codegen/src/class_decl.rs b/crates/codegen/src/class_decl.rs index e7bd747..902fbe2 100644 --- a/crates/codegen/src/class_decl.rs +++ b/crates/codegen/src/class_decl.rs @@ -593,7 +593,7 @@ pub fn gen_method_point(method: &FunctionDecl, ctx: &mut Context, cg: &mut RustC cg.addln(" = core::mem::transmute(func_ptr);"); if mutable_self { - cg.add_indented("func(self as *mut Self as *const core::ffi::c_void"); + cg.add_indented("func(self as *mut Self as *mut core::ffi::c_void"); } else { cg.add_indented("func(self as *const Self as *const core::ffi::c_void"); } diff --git a/mist-test/src/items/class_test.mist b/mist-test/src/items/class_test.mist index e6153cf..7562983 100644 --- a/mist-test/src/items/class_test.mist +++ b/mist-test/src/items/class_test.mist @@ -22,6 +22,8 @@ pub class Animal "Unknown".to_string() } + pub virtual void speak_mut(&mut self){} + pub void test_speak<'a>(&'a self) { assert_eq!(self.speak(), "Woof!"); From d834ff595d39920cb7ab0f6afe268fc340993b69 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 14 Jul 2026 07:19:43 +0200 Subject: [PATCH 2/8] Added more struct rules #117 --- crates/parser/src/grammar.pest | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/parser/src/grammar.pest b/crates/parser/src/grammar.pest index 391ef69..f6aa8c1 100644 --- a/crates/parser/src/grammar.pest +++ b/crates/parser/src/grammar.pest @@ -287,6 +287,14 @@ struct_decl = { visibility? ~ "struct" ~ identifier ~ generics_decl? ~ "{" ~ field_list ~ "}" } +tuple_struct_decl = { + visibility? ~ "struct" ~ identifier ~ generics_decl? ~ tuple_type ~ ";" +} + +empty_struct_decl = { + visibility? ~ "struct" ~ identifier ~ generics_decl? ~ ";" +} + // ====================================================== // ENUMS // ====================================================== @@ -399,7 +407,7 @@ type_alias = { "type" ~ identifier ~ generics_decl? ~ "=" ~ type_expr ~ ";" } top_level = { mod_attribute - | (attributes ~ (include_global | include_local | include_use_global | import | impl_for_decl | impl_decl | trait_decl | struct_decl | enum_decl | class_decl | declare_module | function_decl | const_decl | static_decl | type_alias)) + | (attributes ~ (include_global | include_local | include_use_global | import | impl_for_decl | impl_decl | trait_decl | struct_decl | tuple_struct_decl | empty_struct_decl | enum_decl | class_decl | declare_module | function_decl | const_decl | static_decl | type_alias)) } // ====================================================== From 5079b108197f0b5b70fb1ed4078e015e9ea2ba21 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 14 Jul 2026 07:32:42 +0200 Subject: [PATCH 3/8] Added other struct types #117 --- crates/codegen/src/top_level.rs | 27 +++++++++++++++++++++++++++ crates/parser/src/ast/top_level.rs | 6 ++++++ crates/parser/src/grammar.pest | 8 ++------ crates/parser/src/parser/items/mod.rs | 16 +++++++++++++++- mist-test/src/items/struct_test.mist | 3 +++ 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/crates/codegen/src/top_level.rs b/crates/codegen/src/top_level.rs index e4ed540..069d683 100644 --- a/crates/codegen/src/top_level.rs +++ b/crates/codegen/src/top_level.rs @@ -266,6 +266,33 @@ impl GenRust for TopLevelKind { cg.indent -= 1; cg.addln("}\n"); } + Self::StructDeclTupleUnit { + visibility, + name, + generics, + unit, + } => { + cg.addln(&format!( + "{}struct {}{}", + visibility.get_rust(), + name.get_rust(), + generics.get_rust() + )); + cg.indent += 1; + + if let Some(unit) = unit { + cg.add(" ("); + for unit in unit { + cg.add_indented(""); + unit.gen_rust(ctx, cg); + cg.add(", "); + } + cg.add(")"); + } + + cg.indent -= 1; + cg.addln(";\n"); + } Self::EnumDecl { visibility, name, diff --git a/crates/parser/src/ast/top_level.rs b/crates/parser/src/ast/top_level.rs index 20ceba9..741edbe 100644 --- a/crates/parser/src/ast/top_level.rs +++ b/crates/parser/src/ast/top_level.rs @@ -59,6 +59,12 @@ pub enum TopLevelKind { generics: GenericsDecl, fields: Vec>, }, + StructDeclTupleUnit { + visibility: Visibility, + name: Identifier, + generics: GenericsDecl, + unit: Option>>, + }, FunctionDecl(FunctionDecl), ClassDecl { visibility: Visibility, diff --git a/crates/parser/src/grammar.pest b/crates/parser/src/grammar.pest index f6aa8c1..483b0fa 100644 --- a/crates/parser/src/grammar.pest +++ b/crates/parser/src/grammar.pest @@ -288,11 +288,7 @@ struct_decl = { } tuple_struct_decl = { - visibility? ~ "struct" ~ identifier ~ generics_decl? ~ tuple_type ~ ";" -} - -empty_struct_decl = { - visibility? ~ "struct" ~ identifier ~ generics_decl? ~ ";" + visibility? ~ "struct" ~ identifier ~ generics_decl? ~ tuple_type? ~ ";" } // ====================================================== @@ -407,7 +403,7 @@ type_alias = { "type" ~ identifier ~ generics_decl? ~ "=" ~ type_expr ~ ";" } top_level = { mod_attribute - | (attributes ~ (include_global | include_local | include_use_global | import | impl_for_decl | impl_decl | trait_decl | struct_decl | tuple_struct_decl | empty_struct_decl | enum_decl | class_decl | declare_module | function_decl | const_decl | static_decl | type_alias)) + | (attributes ~ (include_global | include_local | include_use_global | import | impl_for_decl | impl_decl | trait_decl | struct_decl | tuple_struct_decl | enum_decl | class_decl | declare_module | function_decl | const_decl | static_decl | type_alias)) } // ====================================================== diff --git a/crates/parser/src/parser/items/mod.rs b/crates/parser/src/parser/items/mod.rs index 4022024..6b7e30d 100644 --- a/crates/parser/src/parser/items/mod.rs +++ b/crates/parser/src/parser/items/mod.rs @@ -57,6 +57,21 @@ impl<'a> TryFrom> for TopLevelKind { fields: collect_recovered(inner.next().unwrap().into_inner())?, }), + Rule::tuple_struct_decl => Ok(TopLevelKind::StructDeclTupleUnit { + visibility: Visibility::try_from(&mut inner)?, + + name: inner.next().unwrap().try_into()?, + + generics: consume_rule(&mut inner, Rule::generics_decl) + .map(GenericsDecl::try_from) + .transpose() + .map(|v| v.unwrap_or_default())?, + + unit: consume_rule(&mut inner, Rule::tuple_type) + .map(|v| collect_recovered(v.into_inner())) + .transpose()?, + }), + Rule::class_decl => Ok(TopLevelKind::ClassDecl { visibility: Visibility::try_from(&mut inner)?, @@ -147,7 +162,6 @@ impl<'a> TryFrom> for TopLevelKind { .unwrap() .to_string(), )), - _ => AstError::bug_unimplemented(pair), } } diff --git a/mist-test/src/items/struct_test.mist b/mist-test/src/items/struct_test.mist index 93a8379..a8aaa3b 100644 --- a/mist-test/src/items/struct_test.mist +++ b/mist-test/src/items/struct_test.mist @@ -100,6 +100,9 @@ pub void test_struct_destructure_rename() assert_eq!(b, 15); } +struct TuplePoint(i32, i32); +struct Unit; + pub void run_tests() { test_struct_create_access(); From 6f675b425337399a43137eb231b73b155b3961b1 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 14 Jul 2026 07:37:16 +0200 Subject: [PATCH 4/8] Fix mapping for compiler --- crates/mist-api/src/builder.mist | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/mist-api/src/builder.mist b/crates/mist-api/src/builder.mist index dae8dab..7e37efc 100644 --- a/crates/mist-api/src/builder.mist +++ b/crates/mist-api/src/builder.mist @@ -118,8 +118,8 @@ pub void print_diagnostics(Vec& diagnostics) let line = get_line(&mut files, &msg); println!("\n{}:{}:{}\n \x1b[31mError\x1b[0m: {}\n\t{}", msg.file_name, - msg.line + 1, - msg.column + 1, + msg.line, + msg.column, msg.message, line.unwrap_or_default(),) } @@ -127,8 +127,8 @@ pub void print_diagnostics(Vec& diagnostics) let line = get_line(&mut files, &msg); println!("\n{}:{}:{}\n \x1b[33mWarning\x1b[0m: {}\n\t{}", msg.file_name, - msg.line + 1, - msg.column + 1, + msg.line, + msg.column, msg.message, line.unwrap_or_default(),) } @@ -143,5 +143,5 @@ pub Option get_line(HashMap> mut& files, MistDiagno let lines = files.entry(src_path.clone()).or_insert_with(() => { fs::read_to_string(src_path).expect("Unable to read mist file").lines().into_iter().map(String::from).collect() }); - lines.get(msg.line).map((v) => v.trim().to_string()) + lines.get(msg.line.saturating_sub(1)).map((v) => v.trim().to_string()) } From c716b6352c9486d2db7a4641c2ea00443a5f51f6 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 14 Jul 2026 07:47:25 +0200 Subject: [PATCH 5/8] Fix mapping for analyzer --- crates/analyzer/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/analyzer/src/lib.rs b/crates/analyzer/src/lib.rs index 74f90fb..df5aba9 100644 --- a/crates/analyzer/src/lib.rs +++ b/crates/analyzer/src/lib.rs @@ -98,7 +98,7 @@ fn lsp_pos_to_rust_map(pos: &Position) -> RustMap { fn mist_map_to_lsp_pos(map: &MistMap) -> Position { Position { - line: map.0 as u32, + line: map.0.saturating_sub(1) as u32, character: map.1 as u32, } } From df9e31e26d0f170910cafa17e9fb7ae3e219317a Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 14 Jul 2026 07:59:36 +0200 Subject: [PATCH 6/8] fix Analyzer file path #118 --- crates/analyzer/src/transpiler.rs | 32 ++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/crates/analyzer/src/transpiler.rs b/crates/analyzer/src/transpiler.rs index 1f43af0..d771ccc 100644 --- a/crates/analyzer/src/transpiler.rs +++ b/crates/analyzer/src/transpiler.rs @@ -2,7 +2,7 @@ use std::path::{Path, PathBuf}; use mist_codegen::RustCodegen; use mist_parser::rev_mapper::Mapping; -use mist_parser::{MistFmtConfig, parse}; +use mist_parser::{MistFmtConfig, parse, parse_module}; pub struct TranspiledFile { pub mist_path: PathBuf, @@ -30,6 +30,21 @@ pub fn transpile_mist<'a>( rust_path.set_file_name("mod.rs"); } + // Prioritize the module declaration from the source over the file stem. + // Every transpile re-parses so we always pick up the current declaration. + if let Ok(Some((_, ref name))) = parse_module(source) { + if rust_path.file_name().map(|v| v.to_str()).unwrap_or_default() != Some("mod.rs") { + if let Some(ext) = rust_path.extension().map(|e| e.to_owned()) { + let mut new_name = std::ffi::OsString::from(&name.0); + new_name.push("."); + new_name.push(ext); + rust_path.set_file_name(new_name); + } else { + rust_path.set_file_name(&name.0); + } + } + } + let parsed = parse(source).map_err(TranspileError::Parse)?; for item in &parsed.items { @@ -66,6 +81,21 @@ pub fn transpile_mist_no_sem( rust_path.set_file_name("mod.rs"); } + // Prioritize the module declaration from the source over the file stem. + // Every transpile re-parses so we always pick up the current declaration. + if let Ok(Some((_, ref name))) = parse_module(source) { + if rust_path.file_name().map(|v| v.to_str()).unwrap_or_default() != Some("mod.rs") { + if let Some(ext) = rust_path.extension().map(|e| e.to_owned()) { + let mut new_name = std::ffi::OsString::from(&name.0); + new_name.push("."); + new_name.push(ext); + rust_path.set_file_name(new_name); + } else { + rust_path.set_file_name(&name.0); + } + } + } + let parsed = parse(source).map_err(|e| format!("parse error: {e:?}"))?; let mut codegen = RustCodegen::new(mist_path.to_path_buf()); From 708b956750a149d6b179f3bab8683d8563bb3277 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 14 Jul 2026 08:46:33 +0200 Subject: [PATCH 7/8] fix Analyzer file path #118 --- crates/analyzer/src/lib.rs | 23 ++++++--- crates/analyzer/src/transpiler.rs | 77 +++++++++++++------------------ 2 files changed, 49 insertions(+), 51 deletions(-) diff --git a/crates/analyzer/src/lib.rs b/crates/analyzer/src/lib.rs index df5aba9..d37e889 100644 --- a/crates/analyzer/src/lib.rs +++ b/crates/analyzer/src/lib.rs @@ -21,7 +21,8 @@ use tower_lsp::{Client, LanguageServer, LspService, Server}; use crate::rust_analyzer::RustAnalyzer; use crate::transpiler::{ - TranspileError, TranspiledFile, format_mist, transpile_mist, transpile_mist_no_sem, + TranspileError, TranspiledFile, format_mist, resolve_rust_path, transpile_mist, + transpile_mist_no_sem, }; static MARKER_COUNTER: AtomicU64 = AtomicU64::new(0); @@ -392,10 +393,13 @@ impl Backend { // Use the last known working Rust content + mapping to inject the // marker at the nearest valid Rust position. let mist_target = MistMap(line as usize, character as usize); - let mut rust_path = crate::from_mist_to_rust(mist_path.to_path_buf()); - if mist_path.file_name().and_then(|n| n.to_str()) == Some("package.mist") { - rust_path.set_file_name("mod.rs"); - } + let source_for_path = self + .documents + .lock() + .await + .get(mist_path) + .map(|r| r.to_string()); + let rust_path = resolve_rust_path(mist_path, source_for_path.as_deref()); let (last_mapping, last_content, original_version) = { let map_guard = self.mapping.lock().await; @@ -617,9 +621,10 @@ impl Backend { .cloned() .collect(); for path in &stale { + let source_for_path = docs.get(path).map(|r| r.to_string()); docs.remove(path); if path.extension().and_then(|e| e.to_str()) == Some("mist") { - let rust_path = mist_to_rust_path(path); + let rust_path = resolve_rust_path(path, source_for_path.as_deref()); let _ = std::fs::remove_file(&rust_path); let map_path = rust_path.with_extension("map.json"); let _ = std::fs::remove_file(&map_path); @@ -1175,9 +1180,13 @@ impl LanguageServer for Backend { } }; + let source_for_path = { + let docs = self.documents.lock().await; + docs.get(&mist_path).map(|r| r.to_string()) + }; self.documents.lock().await.remove(&mist_path); - let rust_path = mist_to_rust_path(&mist_path); + let rust_path = resolve_rust_path(&mist_path, source_for_path.as_deref()); if let Some(rust_uri) = clean_lsp_url(&rust_path) { let _ = self.rust_analyzer.lock().await.did_close(rust_uri).await; diff --git a/crates/analyzer/src/transpiler.rs b/crates/analyzer/src/transpiler.rs index d771ccc..8b455c8 100644 --- a/crates/analyzer/src/transpiler.rs +++ b/crates/analyzer/src/transpiler.rs @@ -17,33 +17,43 @@ pub enum TranspileError<'a> { Semantic(Vec), } +/// Resolve the output `.rs` path for a `.mist` source file. +/// +/// Always checks for a `pub module x;` declaration via `parse_module` and +/// uses the declared module name as the filename when present. Falls back +/// to the literal file stem when parsing fails or the file has no module +/// declaration. +pub fn resolve_rust_path(mist_path: &Path, source: Option<&str>) -> PathBuf { + let mut rust_path = crate::from_mist_to_rust(mist_path.to_path_buf()); + // Package files (package.mist) must output as /mod.rs so the Rust + // module hierarchy resolves correctly. + if mist_path.file_name().and_then(|n| n.to_str()) == Some("package.mist") { + rust_path.set_file_name("mod.rs"); + } else if let Some(src) = source { + // Prioritize the module declaration from the source over the file stem. + // Every caller re-parses so we always pick up the current declaration. + if let Ok(Some((_, ref name))) = parse_module(src) { + if rust_path.file_name().map(|v| v.to_str()).unwrap_or_default() != Some("mod.rs") { + if let Some(ext) = rust_path.extension().map(|e| e.to_owned()) { + let mut new_name = std::ffi::OsString::from(&name.0); + new_name.push("."); + new_name.push(ext); + rust_path.set_file_name(new_name); + } else { + rust_path.set_file_name(&name.0); + } + } + } + } + rust_path +} + pub fn transpile_mist<'a>( mist_path: &Path, source: &'a str, extra_mod_decl: &str, ) -> Result> { - let mut rust_path = crate::from_mist_to_rust(mist_path.to_path_buf()); - // Package files (package.mist) must output as /mod.rs so the Rust module - // hierarchy resolves correctly (pub mod ; declarations look for sibling - // .rs files, and the parent module declaration looks for /mod.rs). - if mist_path.file_name().and_then(|n| n.to_str()) == Some("package.mist") { - rust_path.set_file_name("mod.rs"); - } - - // Prioritize the module declaration from the source over the file stem. - // Every transpile re-parses so we always pick up the current declaration. - if let Ok(Some((_, ref name))) = parse_module(source) { - if rust_path.file_name().map(|v| v.to_str()).unwrap_or_default() != Some("mod.rs") { - if let Some(ext) = rust_path.extension().map(|e| e.to_owned()) { - let mut new_name = std::ffi::OsString::from(&name.0); - new_name.push("."); - new_name.push(ext); - rust_path.set_file_name(new_name); - } else { - rust_path.set_file_name(&name.0); - } - } - } + let rust_path = resolve_rust_path(mist_path, Some(source)); let parsed = parse(source).map_err(TranspileError::Parse)?; @@ -73,28 +83,7 @@ pub fn transpile_mist_no_sem( source: &str, extra_mod_decl: &str, ) -> Result { - let mut rust_path = crate::from_mist_to_rust(mist_path.to_path_buf()); - // Package files (package.mist) must output as /mod.rs so the Rust module - // hierarchy resolves correctly (pub mod ; declarations look for sibling - // .rs files, and the parent module declaration looks for /mod.rs). - if mist_path.file_name().and_then(|n| n.to_str()) == Some("package.mist") { - rust_path.set_file_name("mod.rs"); - } - - // Prioritize the module declaration from the source over the file stem. - // Every transpile re-parses so we always pick up the current declaration. - if let Ok(Some((_, ref name))) = parse_module(source) { - if rust_path.file_name().map(|v| v.to_str()).unwrap_or_default() != Some("mod.rs") { - if let Some(ext) = rust_path.extension().map(|e| e.to_owned()) { - let mut new_name = std::ffi::OsString::from(&name.0); - new_name.push("."); - new_name.push(ext); - rust_path.set_file_name(new_name); - } else { - rust_path.set_file_name(&name.0); - } - } - } + let rust_path = resolve_rust_path(mist_path, Some(source)); let parsed = parse(source).map_err(|e| format!("parse error: {e:?}"))?; From 48ca58725aec66fe0ff65d5bab17eaa7d513cade Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Tue, 14 Jul 2026 09:13:22 +0200 Subject: [PATCH 8/8] RA passthrough --- crates/analyzer/src/lib.rs | 134 ++++++++++++++++++++++++++++++++++--- 1 file changed, 123 insertions(+), 11 deletions(-) diff --git a/crates/analyzer/src/lib.rs b/crates/analyzer/src/lib.rs index d37e889..32ab6c2 100644 --- a/crates/analyzer/src/lib.rs +++ b/crates/analyzer/src/lib.rs @@ -189,6 +189,10 @@ fn find_marker_position(content: &str, marker: &str) -> Option { Some(Position { line, character }) } +fn is_mist_file(path: &Path) -> bool { + path.extension().and_then(|e| e.to_str()) == Some("mist") +} + fn mist_to_rust_path(mist_path: &Path) -> PathBuf { let mut path = mist_path.to_path_buf(); path.set_extension("rs"); @@ -615,11 +619,7 @@ impl Backend { // mod.rs output files for directories with no remaining source children. { let mut docs = self.documents.lock().await; - let stale: Vec = docs - .keys() - .filter(|p| !p.exists()) - .cloned() - .collect(); + let stale: Vec = docs.keys().filter(|p| !p.exists()).cloned().collect(); for path in &stale { let source_for_path = docs.get(path).map(|r| r.to_string()); docs.remove(path); @@ -636,8 +636,7 @@ impl Backend { let synthetic: Vec = docs .keys() .filter(|p| { - p.file_name().and_then(|n| n.to_str()) == Some("package.mist") - && !p.exists() + p.file_name().and_then(|n| n.to_str()) == Some("package.mist") && !p.exists() }) .cloned() .collect(); @@ -1094,6 +1093,18 @@ impl LanguageServer for Backend { return; } }; + + // Non-.mist files pass through directly to rust-analyzer. + if !is_mist_file(&mist_path) { + let _ = self + .rust_analyzer + .lock() + .await + .did_open(uri, ¶ms.text_document.text) + .await; + return; + } + let source = params.text_document.text; self.documents @@ -1116,6 +1127,18 @@ impl LanguageServer for Backend { } }; + if !is_mist_file(&mist_path) { + if let Some(change) = params.content_changes.into_iter().last() { + let _ = self + .rust_analyzer + .lock() + .await + .did_change(uri, &change.text, params.text_document.version) + .await; + } + return; + } + if let Some(change) = params.content_changes.into_iter().last() { let source = change.text; @@ -1148,6 +1171,11 @@ impl LanguageServer for Backend { .expect("Failed to read file") }; + if !is_mist_file(&mist_path) { + let _ = self.rust_analyzer.lock().await.did_save(uri, &text).await; + return; + } + self.documents .lock() .await @@ -1180,6 +1208,11 @@ impl LanguageServer for Backend { } }; + if !is_mist_file(&mist_path) { + let _ = self.rust_analyzer.lock().await.did_close(uri).await; + return; + } + let source_for_path = { let docs = self.documents.lock().await; docs.get(&mist_path).map(|r| r.to_string()) @@ -1204,6 +1237,25 @@ impl LanguageServer for Backend { Ok(p) => p, Err(_) => return Ok(None), }; + + // Non-.mist files pass through directly to rust-analyzer. + if !is_mist_file(&mist_path) { + let result = self + .rust_analyzer + .lock() + .await + .request::(params) + .await; + + return match result { + Ok(r) => Ok(r), + Err(e) => { + eprintln!("completion error (passthrough): {e}"); + Ok(None) + } + }; + } + let source = match self.documents.lock().await.get(&mist_path) { Some(r) => r.to_string(), None => return Ok(None), @@ -1281,7 +1333,7 @@ impl LanguageServer for Backend { &self, params: GotoDefinitionParams, ) -> tower_lsp::jsonrpc::Result> { - let mist_uri = params.text_document_position_params.text_document.uri; + let mist_uri = ¶ms.text_document_position_params.text_document.uri; let mist_pos = params.text_document_position_params.position; eprintln!( "[goto_definition] entered at mist ({}, {})", @@ -1292,6 +1344,25 @@ impl LanguageServer for Backend { Ok(p) => p, Err(_) => return Ok(None), }; + + // Non-.mist files pass through directly to rust-analyzer. + if !is_mist_file(&mist_path) { + let result = self + .rust_analyzer + .lock() + .await + .request::(params) + .await; + + return match result { + Ok(r) => Ok(r), + Err(e) => { + eprintln!("goto_definition error (passthrough): {e}"); + Ok(None) + } + }; + } + let source = match self.documents.lock().await.get(&mist_path) { Some(r) => r.to_string(), None => return Ok(None), @@ -1461,13 +1532,32 @@ impl LanguageServer for Backend { } async fn hover(&self, params: HoverParams) -> tower_lsp::jsonrpc::Result> { - let mist_uri = params.text_document_position_params.text_document.uri; + let mist_uri = ¶ms.text_document_position_params.text_document.uri; let mist_pos = params.text_document_position_params.position; let mist_path = match mist_uri.to_file_path() { Ok(p) => p, Err(_) => return Ok(None), }; + + // Non-.mist files pass through directly to rust-analyzer. + if !is_mist_file(&mist_path) { + let result = self + .rust_analyzer + .lock() + .await + .request::(params) + .await; + + return match result { + Ok(r) => Ok(r), + Err(e) => { + eprintln!("hover error (passthrough): {e}"); + Ok(None) + } + }; + } + let source = match self.documents.lock().await.get(&mist_path) { Some(r) => r.to_string(), None => return Ok(None), @@ -1531,6 +1621,24 @@ impl LanguageServer for Backend { .to_file_path() .map_err(|_| tower_lsp::jsonrpc::Error::internal_error())?; + // Non-.mist files pass through directly to rust-analyzer. + if !is_mist_file(&mist_path) { + let result = self + .rust_analyzer + .lock() + .await + .request::(params) + .await; + + return match result { + Ok(r) => Ok(r), + Err(e) => { + eprintln!("formatting error (passthrough): {e}"); + Ok(None) + } + }; + } + let docs = self.documents.lock().await; let old_text = docs @@ -1560,7 +1668,12 @@ impl LanguageServer for Backend { } } -fn mist_ify_completions(source: &str, pos: &Position, items: &mut Vec, trigger_char: Option<&str>) { +fn mist_ify_completions( + source: &str, + pos: &Position, + items: &mut Vec, + trigger_char: Option<&str>, +) { let is_scoping_trigger = matches!(trigger_char, Some("." | ":")); for item in items.iter_mut() { @@ -1740,7 +1853,6 @@ fn mist_ify_completions(source: &str, pos: &Position, items: &mut Vec