diff --git a/src/bin/main.rs b/src/bin/main.rs index fdf22424..02f18409 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,6 +1,8 @@ use std::collections::HashMap; use std::path::PathBuf; +use asm_lsp::types::LspClient; + use asm_lsp::handle::{ handle_completion_request, handle_diagnostics, handle_did_change_text_document_notification, handle_did_close_text_document_notification, handle_did_open_text_document_notification, @@ -100,12 +102,18 @@ pub fn main() -> Result<()> { let server_capabilities = serde_json::to_value(capabilities).unwrap(); let initialization_params = connection.initialize(server_capabilities)?; - let mut names_to_info = NameToInfoMaps::default(); let params: InitializeParams = serde_json::from_value(initialization_params.clone()).unwrap(); info!("Client initialization params: {:?}", params); - let config = get_config(¶ms); + let mut config = get_config(¶ms); info!("Server Configuration: {:?}", config); + if let Some(ref client_info) = params.client_info { + if client_info.name.eq("helix") { + info!("Helix LSP client detected"); + config.client = Some(LspClient::Helix); + } + } + let mut names_to_info = NameToInfoMaps::default(); // create a map of &Instruction_name -> &Instruction - Use that in user queries // The Instruction(s) themselves are stored in a vector and we only keep references to the // former map @@ -447,7 +455,14 @@ fn main_loop( start.elapsed().as_millis() ); } else if let Ok((id, params)) = cast_req::(req.clone()) { - handle_goto_def_request(connection, id, ¶ms, &text_store, &mut tree_store)?; + handle_goto_def_request( + connection, + id, + ¶ms, + config, + &text_store, + &mut tree_store, + )?; info!( "Goto definition request serviced in {}ms", start.elapsed().as_millis() @@ -457,6 +472,7 @@ fn main_loop( connection, id, ¶ms, + config, &text_store, &mut tree_store, )?; @@ -469,6 +485,7 @@ fn main_loop( connection, id, ¶ms, + config, &text_store, &mut tree_store, &names_to_info.instructions, @@ -482,6 +499,7 @@ fn main_loop( connection, id, ¶ms, + config, &text_store, &mut tree_store, )?; diff --git a/src/handle.rs b/src/handle.rs index 0597ba36..6d02c907 100644 --- a/src/handle.rs +++ b/src/handle.rs @@ -20,7 +20,8 @@ use tree_sitter::Parser; use crate::{ apply_compile_cmd, get_comp_resp, get_default_compile_cmd, get_document_symbols, get_goto_def_resp, get_hover_resp, get_ref_resp, get_sig_help_resp, get_word_from_pos_params, - text_doc_change_to_ts_edit, Config, NameToInfoMaps, NameToInstructionMap, TreeEntry, TreeStore, + send_empty_resp, text_doc_change_to_ts_edit, Config, NameToInfoMaps, NameToInstructionMap, + TreeEntry, TreeStore, }; /// Handles hover requests @@ -43,20 +44,12 @@ pub fn handle_hover_request( names_to_info: &NameToInfoMaps, include_dirs: &HashMap>, ) -> Result<()> { - let empty_resp = Response { - id: id.clone(), - result: None, - error: None, - }; - let word = if let Some(doc) = text_store.get_document(¶ms.text_document_position_params.text_document.uri) { get_word_from_pos_params(doc, ¶ms.text_document_position_params) } else { - return Ok(connection - .sender - .send(Message::Response(empty_resp.clone()))?); + return send_empty_resp(connection, id, config); }; if let Some(hover_resp) = get_hover_resp( @@ -79,7 +72,7 @@ pub fn handle_hover_request( return Ok(connection.sender.send(Message::Response(result))?); } - Ok(connection.sender.send(Message::Response(empty_resp))?) + send_empty_resp(connection, id, config) } /// Handles completion requests @@ -126,13 +119,7 @@ pub fn handle_completion_request( } } - let empty_resp = Response { - id, - result: None, - error: None, - }; - - Ok(connection.sender.send(Message::Response(empty_resp))?) + send_empty_resp(connection, id, config) } /// Handles go to definition requests @@ -148,6 +135,7 @@ pub fn handle_goto_def_request( connection: &Connection, id: RequestId, params: &GotoDefinitionParams, + config: &Config, text_store: &TextDocuments, tree_store: &mut TreeStore, ) -> Result<()> { @@ -167,13 +155,7 @@ pub fn handle_goto_def_request( } } - let empty_resp = Response { - id, - result: None, - error: None, - }; - - Ok(connection.sender.send(Message::Response(empty_resp))?) + send_empty_resp(connection, id, config) } /// Handles document symbols requests @@ -189,6 +171,7 @@ pub fn handle_document_symbols_request( connection: &Connection, id: RequestId, params: &DocumentSymbolParams, + config: &Config, text_store: &TextDocuments, tree_store: &mut TreeStore, ) -> Result<()> { @@ -208,13 +191,7 @@ pub fn handle_document_symbols_request( } } - let empty_resp = Response { - id, - result: None, - error: None, - }; - - Ok(connection.sender.send(Message::Response(empty_resp))?) + send_empty_resp(connection, id, config) } /// Handles signature help requests @@ -230,6 +207,7 @@ pub fn handle_signature_help_request( connection: &Connection, id: RequestId, params: &SignatureHelpParams, + config: &Config, text_store: &TextDocuments, tree_store: &mut TreeStore, names_to_instructions: &NameToInstructionMap, @@ -257,13 +235,7 @@ pub fn handle_signature_help_request( } } - let empty_resp = Response { - id, - result: None, - error: None, - }; - - Ok(connection.sender.send(Message::Response(empty_resp))?) + send_empty_resp(connection, id, config) } /// Handles reference requests @@ -279,6 +251,7 @@ pub fn handle_references_request( connection: &Connection, id: RequestId, params: &ReferenceParams, + config: &Config, text_store: &TextDocuments, tree_store: &mut TreeStore, ) -> Result<()> { @@ -299,13 +272,7 @@ pub fn handle_references_request( } } - let empty_resp = Response { - id, - result: None, - error: None, - }; - - Ok(connection.sender.send(Message::Response(empty_resp))?) + send_empty_resp(connection, id, config) } /// Produces diagnostics and sends a `PublishDiagnostics` notification to the client diff --git a/src/lsp.rs b/src/lsp.rs index 49a9fc06..9fe67b69 100644 --- a/src/lsp.rs +++ b/src/lsp.rs @@ -10,6 +10,7 @@ use anyhow::{anyhow, Result}; use compile_commands::{CompilationDatabase, CompileArgs, CompileCommand, SourceFile}; use dirs::config_dir; use log::{error, info, log, log_enabled, warn}; +use lsp_server::{Connection, Message, RequestId, Response}; use lsp_textdocument::{FullTextDocument, TextDocuments}; use lsp_types::{ CompletionItem, CompletionItemKind, CompletionList, CompletionParams, CompletionTriggerKind, @@ -27,10 +28,31 @@ use tree_sitter::InputEdit; use crate::types::Column; use crate::{ - Arch, ArchOrAssembler, Assembler, Completable, Config, Hoverable, Instruction, + Arch, ArchOrAssembler, Assembler, Completable, Config, Hoverable, Instruction, LspClient, NameToInstructionMap, TreeEntry, TreeStore, }; +/// Sends an empty, non-error response to the lsp client via `connection` +/// +/// # Errors +/// +/// Returns `Err` if the response fails to send via `connection` +pub fn send_empty_resp(connection: &Connection, id: RequestId, config: &Config) -> Result<()> { + let empty_resp = Response { + id, + result: None, + error: None, + }; + + // Helix shuts the server down when the above empty response is sent, + // so send nothing in its case + if config.client == Some(LspClient::Helix) { + Ok(()) + } else { + Ok(connection.sender.send(Message::Response(empty_resp))?) + } +} + /// Find the start and end indices of a word inside the given line /// Borrowed from RLS /// characters besides the default alphanumeric and '_' @@ -91,9 +113,6 @@ pub fn get_word_from_file_params(pos_params: &TextDocumentPositionParams) -> Res } /// Returns a string slice to the word in doc specified by the position params -/// -/// The `extra_chars` param allows specifying extra chars to be considered as -/// valid word chars, in addition to the default alphanumeric, '_', and '.' chars #[must_use] pub fn get_word_from_pos_params<'a>( doc: &'a FullTextDocument, diff --git a/src/test.rs b/src/test.rs index d1f2a7b8..a5a7e63b 100644 --- a/src/test.rs +++ b/src/test.rs @@ -46,6 +46,7 @@ mod tests { diagnostics: None, default_diagnostics: None, }, + client: None, } } @@ -71,6 +72,7 @@ mod tests { diagnostics: None, default_diagnostics: None, }, + client: None, } } @@ -96,6 +98,7 @@ mod tests { diagnostics: None, default_diagnostics: None, }, + client: None, } } @@ -121,6 +124,7 @@ mod tests { diagnostics: None, default_diagnostics: None, }, + client: None, } } @@ -146,6 +150,7 @@ mod tests { diagnostics: None, default_diagnostics: None, }, + client: None, } } @@ -171,6 +176,7 @@ mod tests { diagnostics: None, default_diagnostics: None, }, + client: None, } } @@ -196,6 +202,7 @@ mod tests { diagnostics: None, default_diagnostics: None, }, + client: None, } } @@ -221,6 +228,7 @@ mod tests { diagnostics: None, default_diagnostics: None, }, + client: None, } } diff --git a/src/types.rs b/src/types.rs index e6f59fc5..fd0c4973 100644 --- a/src/types.rs +++ b/src/types.rs @@ -874,6 +874,7 @@ pub struct Config { pub assemblers: Assemblers, pub instruction_sets: InstructionSets, pub opts: ConfigOptions, + pub client: Option, } impl Default for Config { @@ -883,10 +884,16 @@ impl Default for Config { assemblers: Assemblers::default(), instruction_sets: InstructionSets::default(), opts: ConfigOptions::default(), + client: None, } } } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum LspClient { + Helix, +} + // Instruction Set Architecture ------------------------------------------------------------------- #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, EnumString, AsRefStr, Serialize, Deserialize)] pub enum ISA {