From 4b733f6b9c7bf1c245e103ad15aeef0d277990b4 Mon Sep 17 00:00:00 2001 From: Klesti Selimaj Date: Sun, 21 Jun 2026 15:05:58 +0200 Subject: [PATCH] Cleaned up lsp --- crates/analyzer/src/builder.rs | 139 ----------- crates/analyzer/src/lib.rs | 373 +----------------------------- crates/analyzer/src/transpiler.rs | 163 ------------- 3 files changed, 1 insertion(+), 674 deletions(-) delete mode 100644 crates/analyzer/src/builder.rs delete mode 100644 crates/analyzer/src/transpiler.rs diff --git a/crates/analyzer/src/builder.rs b/crates/analyzer/src/builder.rs deleted file mode 100644 index 7f8ecfc..0000000 --- a/crates/analyzer/src/builder.rs +++ /dev/null @@ -1,139 +0,0 @@ -use std::{ - collections::HashMap, - env, fs, - path::{MAIN_SEPARATOR, PathBuf}, - process::{Command, Stdio}, -}; - -use cargo_metadata::{CompilerMessage, Message}; -use mist_parser::rev_mapper; - -#[derive(Debug, Clone)] -pub struct MistDiagnosticMessage { - pub message: String, - pub file_path: PathBuf, - pub file_name: String, - pub line: usize, - pub column: usize, -} - -#[derive(Debug, Clone)] -pub enum MistDiagnostic { - Error(MistDiagnosticMessage), - Warning(MistDiagnosticMessage), - Rust(CompilerMessage), -} - -pub fn build(mut args: Vec, root: PathBuf) -> Vec { - args.insert(1, "--message-format=json".to_string()); - - let is_root = root == env::current_dir().expect("Failed getting env"); - - let mut command = Command::new("cargo") - .args(args) - .stdout(Stdio::piped()) - .spawn() - .expect("Failed to run cargo"); - - let mut reader = std::io::BufReader::new(command.stdout.take().expect("Failed to get reader")); - - let mut diagnostics = Vec::new(); - - let mut mapping: HashMap = HashMap::new(); - - let mist_src = format!(".mist{MAIN_SEPARATOR}lsp"); - - for message in cargo_metadata::Message::parse_stream(&mut reader) { - match message { - Ok(Message::CompilerMessage(msg)) => { - for span in &msg.message.spans { - if span.is_primary { - let rust_path = root.join(&span.file_name); - - let mist_file = span - .file_name - .replacen(&mist_src, "src", 1) - .trim_end_matches(".rs") - .to_string() - + ".mist"; - - let mist_path = root.join(&mist_file); - - if !fs::exists(&mist_path).expect("Unable to check if mist file exists") { - diagnostics.push(MistDiagnostic::Rust(msg)); - break; - } - - // let map = mapping.entry(rust_path.clone()).or_insert_with(|| { - // get_mapping( - // &fs::read_to_string(rust_path) - // .expect("Failed to read file for mapping"), - // ) - // }); - - // let mist_span = - // find_mapping(&map, &RustMap(span.line_end, span.column_start)) - // .expect("Unable to find mapping"); - - // let mist_msg = MistDiagnosticMessage { - // message: format!( - // "{}: {}", - // msg.message.message, - // span.label.clone().unwrap_or_default() - // ), - // file_name: if is_root { - // mist_file - // } else { - // mist_path.to_string_lossy().to_string() - // }, - // file_path: mist_path, - // line: mist_span.1.0, - // column: mist_span.1.1, - // }; - - // match msg.message.level { - // cargo_metadata::diagnostic::DiagnosticLevel::Error => { - // diagnostics.push(MistDiagnostic::Error(mist_msg)) - // } - - // cargo_metadata::diagnostic::DiagnosticLevel::Warning => { - // diagnostics.push(MistDiagnostic::Warning(mist_msg)) - // } - - // _ => {} - // } - } - } - } - - Ok(Message::BuildFinished(_)) => { - command.wait().unwrap(); - - return diagnostics; - } - - Ok(Message::TextLine(text)) => println!("{text}"), - _ => {} - } - } - - diagnostics -} - -pub fn get_line( - files: &mut HashMap>, - msg: &MistDiagnosticMessage, -) -> Option { - let src_path = msg.file_path.clone(); - - 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 - 1).map(|v| v.trim().to_string()) -} diff --git a/crates/analyzer/src/lib.rs b/crates/analyzer/src/lib.rs index 5569ad2..14473d2 100644 --- a/crates/analyzer/src/lib.rs +++ b/crates/analyzer/src/lib.rs @@ -1,6 +1,4 @@ -pub mod builder; pub mod rust_analyzer; -pub mod transpiler; use std::collections::{HashMap, HashSet}; use std::path::{Component, PathBuf}; @@ -10,11 +8,9 @@ use mist_parser::rev_mapper; use ropey::Rope; use tokio::sync::Mutex; use tower_lsp::jsonrpc::Result; -use tower_lsp::lsp_types::notification::Notification; use tower_lsp::lsp_types::{self, *}; use tower_lsp::{Client, LanguageServer, LspService, Server}; -use crate::builder::MistDiagnostic; use crate::rust_analyzer::RustAnalyzer; #[derive(Debug)] @@ -143,8 +139,6 @@ impl LanguageServer for Backend { if let Some(root) = &*workspace_folder.lock().await { let src_root = root.join("src"); - transpiler::build(root); - analyzer .lock() .await @@ -157,23 +151,7 @@ impl LanguageServer for Backend { collect_mist_files(&src_root, &mut files); for file in files { - if let Ok(text) = std::fs::read_to_string(&file) { - if let Ok(transpiled) = transpiler::transpile_text(&text) { - let rust_path = from_mist_to_rust(file.clone()); - - // store document - documents - .lock() - .await - .insert(file.clone(), Rope::from_str(&text)); - - // store mapping - // mapping - // .lock() - // .await - // .insert(rust_path, rev_mapper::get_mapping(&transpiled)); - } - } + if let Ok(text) = std::fs::read_to_string(&file) {} } eprintln!("Ready to use"); @@ -199,355 +177,6 @@ impl LanguageServer for Backend { async fn shutdown(&self) -> Result<()> { Ok(()) } - - async fn did_save(&self, _: DidSaveTextDocumentParams) { - self.client - .log_message(MessageType::INFO, "Processing did_save event") - .await; - - if let Some(root) = &*self.workspace_folder.lock().await { - transpiler::build(root); - } - - let workspace_root = match self.workspace_folder.lock().await.clone() { - Some(root) => root, - None => { - self.client - .log_message( - MessageType::WARNING, - "Skipping diagnostics: No active workspace folder found", - ) - .await; - return; - } - }; - - let diagnostics_raw = builder::build( - vec![ - "check".to_string(), - "--workspace".to_string(), - "--all-targets".to_string(), - ], - workspace_root, - ); - - let mut diagnostics = HashMap::new(); - - for diag in diagnostics_raw.iter() { - let (msg, severity) = match diag { - MistDiagnostic::Error(msg) => (msg, DiagnosticSeverity::ERROR), - MistDiagnostic::Warning(msg) => (msg, DiagnosticSeverity::WARNING), - MistDiagnostic::Rust(_) => { - continue; - } - }; - - let line = (msg.line as u32).saturating_sub(1); - let column = (msg.column as u32).saturating_sub(1); - - let url = match clean_lsp_url(&msg.file_path) { - Some(u) => u, - None => continue, - }; - - let diagnostic_item = Diagnostic { - range: Range { - start: Position { - line, - character: column, - }, - end: Position { - line, - character: u32::MAX, - }, - }, - severity: Some(severity), - code: None, - source: Some("mist-analyzer".to_string()), - message: msg.message.clone(), - related_information: None, - tags: None, - data: None, - code_description: None, - }; - - diagnostics - .entry(url) - .or_insert_with(Vec::new) - .push(diagnostic_item); - } - - for (file, _) in self.previous_diagnostics.lock().await.iter() { - self.client - .publish_diagnostics(file.clone(), Vec::new(), None) - .await; - } - - for (file, diag) in &diagnostics { - self.client - .publish_diagnostics(file.clone(), diag.clone(), None) - .await; - } - - *self.previous_diagnostics.lock().await = diagnostics; - } - - async fn did_open(&self, mut params: DidOpenTextDocumentParams) { - if params.text_document.language_id == "mist" { - let original_text = params.text_document.text.clone(); - - self.documents.lock().await.insert( - params.text_document.uri.to_file_path().unwrap(), - Rope::from_str(&original_text), - ); - - params.text_document.language_id = "rust".to_string(); - - match transpiler::transpile_text(&original_text) { - Ok(transpiled_text) => { - params.text_document.text = transpiled_text; - - let rust_path = - from_mist_to_rust(params.text_document.uri.to_file_path().unwrap()); - - params.text_document.uri = Url::from_file_path(&rust_path).unwrap(); - - // self.mapping.lock().await.insert( - // rust_path, - // rev_mapper::get_mapping(¶ms.text_document.text), - // ); - } - Err(e) => { - self.client - .log_message( - MessageType::WARNING, - format!("MIST-LSP: Syntax invalid during open/change: {:?}", e), - ) - .await; - - return; - } - } - } - - if let Ok(mut ra) = self.rust_analyzer.try_lock() { - let _ = ra - .notify(notification::DidOpenTextDocument::METHOD, params) - .await; - } - } - - async fn did_change(&self, mut params: DidChangeTextDocumentParams) { - let mist_path = params.text_document.uri.to_file_path().unwrap(); - - let rust_path = from_mist_to_rust(mist_path.clone()); - - let rust_uri = Url::from_file_path(&rust_path).unwrap(); - - if let Some(change) = params.content_changes.first_mut() { - self.documents - .lock() - .await - .insert(mist_path, Rope::from_str(&change.text)); - - match transpiler::transpile_text(&change.text) { - Ok(transpiled_text) => { - change.text = transpiled_text; - - // self.mapping - // .lock() - // .await - // .insert(rust_path, rev_mapper::get_mapping(&change.text)); - } - Err(e) => { - self.client - .log_message( - MessageType::WARNING, - format!("MIST-LSP: Syntax invalid during change: {:?}", e), - ) - .await; - - return; - } - } - } - - params.text_document.uri = rust_uri; - - if let Ok(mut ra) = self.rust_analyzer.try_lock() { - let _ = ra - .notify(notification::DidChangeTextDocument::METHOD, params) - .await; - } - } - - async fn did_close(&self, mut params: DidCloseTextDocumentParams) { - self.client - .log_message(MessageType::INFO, "MIST-LSP: Processing did_close event") - .await; - - let rust_path = from_mist_to_rust(params.text_document.uri.to_file_path().unwrap()); - - let mist_path = params.text_document.uri.to_file_path().unwrap(); - - self.documents.lock().await.remove(&mist_path); - - self.mapping.lock().await.remove(&rust_path); - - params.text_document.uri = Url::from_file_path(&rust_path).unwrap(); - - if let Ok(mut ra) = self.rust_analyzer.try_lock() { - let _ = ra - .notify(notification::DidCloseTextDocument::METHOD, params) - .await; - } - } - - async fn goto_definition( - &self, - params: GotoDefinitionParams, - ) -> Result> { - let file_path = params - .text_document_position_params - .text_document - .uri - .to_file_path() - .unwrap(); - - let source = match self.documents.lock().await.get(&file_path) { - Some(doc) => doc.clone(), - None => return Ok(None), - }; - - let inject = "__mist_23"; - let injected_source = insert_at_position( - &source, - params.text_document_position_params.position.line as usize + 1, - params.text_document_position_params.position.character as usize, - &inject, - ); - - let output = Rope::from_str( - &match transpiler::transpile_text(&injected_source.to_string()) { - Ok(out) => out, - Err(_) => return Ok(None), - }, - ); - - let (line, character) = match find_row_col(&output, inject) { - Some(coords) => coords, - None => return Ok(None), - }; - - let uri = - Url::from_file_path(from_mist_to_rust(file_path)).expect("failed to generate rs url"); - - let rs_res = self - .rust_analyzer - .lock() - .await - .request::(lsp_types::GotoDefinitionParams { - text_document_position_params: lsp_types::TextDocumentPositionParams { - position: lsp_types::Position { - line: line as u32, - character: character as u32, - }, - text_document: lsp_types::TextDocumentIdentifier { uri }, - }, - partial_result_params: lsp_types::PartialResultParams::default(), - work_done_progress_params: lsp_types::WorkDoneProgressParams::default(), - }) - .await - .expect("Failed to send to rust"); - - Ok(match rs_res { - Some(GotoDefinitionResponse::Array(arr)) => { - let mut mapped_arr = Vec::new(); - for rs_loc in arr { - let mapped_loc = self.get_mist_location(rs_loc).await; - mapped_arr.push(mapped_loc); - } - Some(GotoDefinitionResponse::Array(mapped_arr)) - } - _ => rs_res, - }) - } - - async fn completion(&self, mut params: CompletionParams) -> Result> { - self.client - .log_message(MessageType::INFO, "COMPLETEING!") - .await; - - let file_path = params - .text_document_position - .text_document - .uri - .to_file_path() - .unwrap(); - - let source = match self.documents.lock().await.get(&file_path) { - Some(doc) => doc.clone(), - None => return Ok(None), - }; - - let inject = "__mist_23"; - let injected_source = insert_at_position( - &source, - params.text_document_position.position.line as usize + 1, - params.text_document_position.position.character as usize, - &inject, - ); - - let output = Rope::from_str( - &match transpiler::transpile_text(&injected_source.to_string()) { - Ok(out) => out, - Err(_) => return Ok(None), - }, - ); - - let (line, character) = match find_row_col(&output, inject) { - Some(coords) => coords, - None => return Ok(None), - }; - - let uri = - Url::from_file_path(from_mist_to_rust(file_path)).expect("failed to generate rs url"); - - params.text_document_position.text_document.uri = uri; - params.text_document_position.position.line = line as u32; - params.text_document_position.position.character = character as u32; - - let rs_res = self - .rust_analyzer - .lock() - .await - .request::(params) - .await - .expect("Failed to send to rust"); - - Ok(rs_res.map(|rs_res| match rs_res { - CompletionResponse::Array(items) => { - CompletionResponse::Array(items.into_iter().map(simplify_item).collect()) - } - - CompletionResponse::List(list) => { - CompletionResponse::Array(list.items.into_iter().map(simplify_item).collect()) - } - })) - } - - async fn completion_resolve(&self, params: CompletionItem) -> Result { - match self - .rust_analyzer - .lock() - .await - .request::(params.clone()) - .await - { - Ok(o) => Ok(o), - _ => Ok(params), - } - } } #[tokio::main] diff --git a/crates/analyzer/src/transpiler.rs b/crates/analyzer/src/transpiler.rs deleted file mode 100644 index e3baed3..0000000 --- a/crates/analyzer/src/transpiler.rs +++ /dev/null @@ -1,163 +0,0 @@ -use std::{ - fs, - path::{Path, PathBuf}, -}; - -use mist_parser::{ast::TopLevel, error::ParseError}; - -pub fn build(root: &PathBuf) { - let src_dir = root.join("src"); - let out_dir = root.join(".mist/src"); - - if let Err(e) = build_dir(root, &src_dir, &src_dir, &out_dir) { - eprintln!("Warning: Build directory run aborted safely: {e}"); - } -} - -fn build_dir( - root: &Path, - base_src: &Path, - current_dir: &Path, - out_dir: &Path, -) -> Result<(), String> { - let entries = fs::read_dir(current_dir) - .map_err(|e| format!("failed to read directory {}: {}", current_dir.display(), e))?; - - for entry in entries { - let entry = match entry { - Ok(entry) => entry, - Err(e) => { - eprintln!("Warning: Skipping invalid directory entry: {e}"); - continue; // Skip corrupted entry instead of crashing - } - }; - - let path = entry.path(); - - // Recurse into nested directories - if path.is_dir() { - if let Err(e) = build_dir(root, base_src, &path, out_dir) { - eprintln!("Warning: Nested build directory failed: {e}"); - } - continue; - } - - // Safe prefix stripping fallback - let relative = match path.strip_prefix(base_src) { - Ok(p) => p, - Err(_) => { - eprintln!( - "Warning: Path {} is outside base source directory", - path.display() - ); - continue; - } - }; - - // Handle non-mist files with a cache check - if path.extension().and_then(|e| e.to_str()) != Some("mist") { - let dest_path = out_dir.join(relative); - - // Create parent directories for static assets if needed - if let Some(parent) = dest_path.parent() { - let _ = fs::create_dir_all(parent); - } - - if should_skip(&path, &dest_path) { - continue; - } - - if let Err(e) = fs::copy(&path, &dest_path) { - eprintln!( - "Warning: Failed to copy non-mist file {}: {}", - path.display(), - e - ); - } - continue; - } - - let output_path = out_dir.join(relative).with_extension("rs"); - - // Cache layer: Skip if the generated .rs file is newer than the .mist source - if should_skip(&path, &output_path) { - continue; - } - - if let Err(e) = transpile_file(&path, &output_path) { - eprintln!( - "Warning: Transpilation failed for {}: {}", - path.display(), - e - ); - } - } - - Ok(()) -} - -pub fn transpile_file(path: &Path, output_path: &Path) -> Result<(), String> { - // Create parent directories - if let Some(parent) = output_path.parent() { - fs::create_dir_all(parent).map_err(|e| { - format!( - "failed to create output directory {}: {}", - parent.display(), - e - ) - })?; - } - - // Read source - let source = fs::read_to_string(path) - .map_err(|e| format!("failed to read file {}: {}", path.display(), e))?; - - let parser_result = mist_parser::parse(&source).map_err(|e| match e { - ParseError::Ast(e) => { - // Using components carefully to prevent out-of-bounds or zero layout crashes - let start_pos = e.span.start_pos().line_col(); - let span = e.span.as_str(); - - format!( - "\n{}:{}:{}\n Error: {}\n\t{}{}\t{}", - path.display(), - start_pos.0, - start_pos.1, - e.error_message, - span, - if span.ends_with('\n') { "" } else { "\n" }, - "^".repeat(span.trim().len()), - ) - } - ParseError::PreAst(e) => format!("{e}"), - }); - - // If parsing fails, return the error string back gracefully so the LSP can show it - let ast = parser_result.map_err(|e| format!("parse failed in {}:\n{}", path.display(), e))?; - - panic!(); - - // let mut gc = mist_codegen::RustCodegen::new(); - // let output = gc.generate(ast); - - // fs::write(output_path, output) - // .map_err(|e| format!("failed to write output {}: {}", output_path.display(), e))?; - - // Ok(()) -} - -pub fn transpile_text<'a>(source: &'a str) -> Result>> { - panic!(); - // let mut gc = mist_codegen::RustCodegen::new(); - - // Ok(gc.generate(mist_parser::parse(&source)?)) -} - -fn should_skip(source: &Path, output: &Path) -> bool { - if let (Ok(src_meta), Ok(out_meta)) = (fs::metadata(source), fs::metadata(output)) { - if let (Ok(src_time), Ok(out_time)) = (src_meta.modified(), out_meta.modified()) { - return out_time >= src_time; - } - } - false -}