diff --git a/crates/codebook-lsp/src/lsp.rs b/crates/codebook-lsp/src/lsp.rs index 13c2ebe..14881f7 100644 --- a/crates/codebook-lsp/src/lsp.rs +++ b/crates/codebook-lsp/src/lsp.rs @@ -38,6 +38,7 @@ pub struct Backend { enum CodebookCommand { AddWord, AddWordGlobal, + IgnoreFile, Unknown, } @@ -46,6 +47,7 @@ impl From<&str> for CodebookCommand { match command { "codebook.addWord" => CodebookCommand::AddWord, "codebook.addWordGlobal" => CodebookCommand::AddWordGlobal, + "codebook.ignoreFile" => CodebookCommand::IgnoreFile, _ => CodebookCommand::Unknown, } } @@ -56,6 +58,7 @@ impl From for String { match command { CodebookCommand::AddWord => "codebook.addWord".to_string(), CodebookCommand::AddWordGlobal => "codebook.addWordGlobal".to_string(), + CodebookCommand::IgnoreFile => "codebook.ignoreFile".to_string(), CodebookCommand::Unknown => "codebook.unknown".to_string(), } } @@ -93,6 +96,7 @@ impl LanguageServer for Backend { commands: vec![ CodebookCommand::AddWord.into(), CodebookCommand::AddWordGlobal.into(), + CodebookCommand::IgnoreFile.into(), ], work_done_progress_options: Default::default(), }), @@ -256,6 +260,20 @@ impl LanguageServer for Backend { data: None, })); } + actions.push(CodeActionOrCommand::CodeAction(CodeAction { + title: "Add current file to ignore list".to_string(), + kind: Some(CodeActionKind::QUICKFIX), + diagnostics: None, + edit: None, + command: Some(Command { + title: "Add current file to ignore list".to_string(), + command: CodebookCommand::IgnoreFile.into(), + arguments: Some(vec![params.text_document.uri.to_string().into()]), + }), + is_preferred: None, + disabled: None, + data: None, + })); match actions.is_empty() { true => Ok(None), false => Ok(Some(actions)), @@ -294,6 +312,23 @@ impl LanguageServer for Backend { } Ok(None) } + CodebookCommand::IgnoreFile => { + let config = self.config_handle(); + let file_uri = params + .arguments + .first() + .expect("CodebookCommand::IgnoreFile: There has to be a file URI here!") + .as_str() + .expect( + "CodebookCommand::IgnoreFile: Argument should be convertible to a String.", + ); + let updated = self.add_ignore_file(config.as_ref(), file_uri); + if updated { + let _ = config.save(); + self.recheck_all().await; + } + Ok(None) + } CodebookCommand::Unknown => Ok(None), } } @@ -382,6 +417,7 @@ impl Backend { } should_save } + fn add_words_global( &self, config: &CodebookConfigFile, @@ -404,6 +440,42 @@ impl Backend { should_save } + fn get_relative_path(&self, uri: &str) -> String { + let uri = Url::parse(uri) + .expect("This is a correctly formatted URL because it comes from the LSP protocol."); + let file_path = uri.to_file_path().unwrap_or_default(); + let absolute_workspace_dir = &self.workspace_dir.canonicalize(); + + match absolute_workspace_dir { + Ok(dir) => match file_path.canonicalize() { + Ok(canon_file_path) => match canon_file_path.strip_prefix(dir) { + Ok(relative) => relative.to_string_lossy().to_string(), + Err(_) => file_path.to_string_lossy().to_string(), + }, + Err(_) => file_path.to_string_lossy().to_string(), + }, + Err(err) => { + info!("Could not get absolute path from workspace directory. Error: {err}."); + file_path.to_string_lossy().to_string() + } + } + } + + fn add_ignore_file(&self, config: &CodebookConfigFile, file_uri: &str) -> bool { + let relative_path = &self.get_relative_path(file_uri); + match config.add_ignore(relative_path) { + Ok(true) => true, + Ok(false) => { + info!("File {file_uri} already exists in the ignored files."); + false + } + Err(e) => { + error!("Failed to add ignore file: {e}"); + false + } + } + } + fn make_suggestion(&self, suggestion: &str, range: &Range, uri: &Url) -> CodeAction { let title = format!("Replace with '{suggestion}'"); let mut map = HashMap::new();