From 2050e733e11a4027cc041b5ecc383f852d83f29c Mon Sep 17 00:00:00 2001 From: Martin Asquino Date: Mon, 13 Jul 2020 08:26:31 +0100 Subject: [PATCH 1/2] Add function and plug mappings to cycle diagnostics --- autoload/LanguageClient.vim | 16 ++++++++++++ doc/LanguageClient.txt | 17 +++++++++++++ plugin/LanguageClient.vim | 10 ++++++++ src/language_server_protocol.rs | 45 +++++++++++++++++++++++++++++++++ src/rpchandler.rs | 6 ++++- src/types.rs | 2 ++ 6 files changed, 95 insertions(+), 1 deletion(-) diff --git a/autoload/LanguageClient.vim b/autoload/LanguageClient.vim index 7b566e55..58172bd3 100644 --- a/autoload/LanguageClient.vim +++ b/autoload/LanguageClient.vim @@ -1050,6 +1050,22 @@ function! LanguageClient#setLoggingLevel(level) abort return LanguageClient#Call('languageClient/setLoggingLevel', l:params, v:null) endfunction +function! LanguageClient#diagnosticsPrevious() abort + let l:params = { + \ 'filename': LSP#filename(), + \ 'position': LSP#position(), + \ } + return LanguageClient#Notify('languageClient/diagnosticsPrevious', l:params) +endfunction + +function! LanguageClient#diagnosticsNext() abort + let l:params = { + \ 'filename': LSP#filename(), + \ 'position': LSP#position(), + \ } + return LanguageClient#Notify('languageClient/diagnosticsNext', l:params) +endfunction + function! LanguageClient#setDiagnosticsList(diagnosticsList) abort let l:params = { \ 'diagnosticsList': a:diagnosticsList, diff --git a/doc/LanguageClient.txt b/doc/LanguageClient.txt index 91889206..36fb23f4 100644 --- a/doc/LanguageClient.txt +++ b/doc/LanguageClient.txt @@ -905,6 +905,17 @@ Signature: LanguageClient#debugInfo(...) Print out debug info. +*LanguageClient#diagnosticsNext* +Signature: LanguageClient#diagnosticsNext() + +Moves the cursor to the next diagnostic in the buffer, relative to the current cursor position. + +*LanguageClient#diagnosticsPrevious* +Signature: LanguageClient#diagnosticsPrevious() + +Moves the cursor to the previous diagnostic in the buffer, relative to the current cursor position. + + ============================================================================== 5. Mappings *LanguageClientMappings* @@ -959,6 +970,12 @@ Calls LanguageClient_textDocument_formatting. *(lcn-format-sync)* Calls LanguageClient_textDocument_formatting_sync. +*(lcn-diagnostics-next)* +Calls LanguageClient_diagnosticsNext. + +*(lcn-diagnostics-prev)* +Calls LanguageClient_diagnosticsPrevious. + ============================================================================== 6. Events *LanguageClientEvents* diff --git a/plugin/LanguageClient.vim b/plugin/LanguageClient.vim index 61bb9cce..89b0ed0b 100644 --- a/plugin/LanguageClient.vim +++ b/plugin/LanguageClient.vim @@ -110,6 +110,14 @@ function! LanguageClient_statusLine(...) return call('LanguageClient#statusLine', a:000) endfunction +function! LanguageClient_diagnosticsPrevious(...) + return call('LanguageClient#diagnosticsPrevious', a:000) +endfunction + +function! LanguageClient_diagnosticsNext(...) + return call('LanguageClient#diagnosticsNext', a:000) +endfunction + function! LanguageClient_statusLineDiagnosticsCounts(...) return call('LanguageClient#statusLineDiagnosticsCounts', a:000) endfunction @@ -178,4 +186,6 @@ augroup languageClient nnoremap (lcn-explain-error) :call LanguageClient_explainErrorAtPoint() nnoremap (lcn-format) :call LanguageClient_textDocument_formatting() nnoremap (lcn-format-sync) :call LanguageClient_textDocument_formatting_sync() + nnoremap (lcn-diagnostics-next) :call LanguageClient_diagnosticsNext() + nnoremap (lcn-diagnostics-prev) :call LanguageClient_diagnosticsPrevious() augroup END diff --git a/src/language_server_protocol.rs b/src/language_server_protocol.rs index 7a731dd7..29aba5bc 100644 --- a/src/language_server_protocol.rs +++ b/src/language_server_protocol.rs @@ -58,6 +58,12 @@ use std::{ time::{Duration, Instant}, }; +#[derive(PartialEq)] +pub enum Direction { + Next, + Previous, +} + impl LanguageClient { pub fn get_client(&self, language_id: &LanguageId) -> Result> { self.get(|state| state.clients.get(language_id).cloned())? @@ -603,6 +609,45 @@ impl LanguageClient { Ok(position) } + // moves the cursor to the next or previous diagnostic, depending on the value of direction. + pub fn cycle_diagnostics(&self, params: &Value, direction: Direction) -> Result<()> { + let filename = self.vim()?.get_filename(params)?; + let pos = self.vim()?.get_position(params)?; + let mut diagnostics = self.get(|state| state.diagnostics.clone())?; + if let Some(diagnostics) = diagnostics.get_mut(&filename) { + if direction == Direction::Next { + diagnostics.sort_by_key(|edit| (edit.range.start.line, edit.range.start.character)); + } else { + diagnostics.sort_by_key(|edit| { + ( + -(edit.range.start.line as i64), + -(edit.range.start.character as i64), + ) + }); + } + + let (line, col) = (pos.line, pos.character); + if let Some((_, diagnostic)) = diagnostics.iter_mut().find_position(|it| { + let start = it.range.start; + if direction == Direction::Next { + start.line > line || (start.line == line && start.character > col) + } else { + start.line < line || (start.line == line && start.character < col) + } + }) { + let line = diagnostic.range.start.line + 1; + let col = diagnostic.range.start.character + 1; + let _: String = self.vim()?.rpcclient.call("cursor", json!([line, col]))?; + } else { + self.vim()?.echomsg("No diagnostics found")?; + } + } else { + self.vim()?.echomsg("No diagnostics found")?; + } + + Ok(()) + } + fn update_quickfixlist(&self) -> Result<()> { let diagnostics = self.get(|state| state.diagnostics.clone())?; let qflist: Vec<_> = diagnostics diff --git a/src/rpchandler.rs b/src/rpchandler.rs index 91117f1e..f5d58a72 100644 --- a/src/rpchandler.rs +++ b/src/rpchandler.rs @@ -1,4 +1,4 @@ -use crate::{language_client::LanguageClient, types::*}; +use crate::{language_client::LanguageClient, language_server_protocol::Direction, types::*}; use anyhow::{anyhow, Result}; use log::*; use lsp_types::notification::{self, Notification}; @@ -196,6 +196,10 @@ impl LanguageClient { NOTIFICATION_RUST_BEGIN_BUILD => self.rust_handle_begin_build(¶ms)?, NOTIFICATION_RUST_DIAGNOSTICS_BEGIN => self.rust_handle_diagnostics_begin(¶ms)?, NOTIFICATION_RUST_DIAGNOSTICS_END => self.rust_handle_diagnostics_end(¶ms)?, + NOTIFICATION_DIAGNOSTICS_NEXT => self.cycle_diagnostics(¶ms, Direction::Next)?, + NOTIFICATION_DIAGNOSTICS_PREVIOUS => { + self.cycle_diagnostics(¶ms, Direction::Previous)? + } _ => { let language_id_target = if language_id.is_some() { diff --git a/src/types.rs b/src/types.rs index aaa6baa9..80d49255 100644 --- a/src/types.rs +++ b/src/types.rs @@ -81,6 +81,8 @@ pub const NOTIFICATION_RUST_DIAGNOSTICS_BEGIN: &str = "rustDocument/diagnosticsB pub const NOTIFICATION_RUST_DIAGNOSTICS_END: &str = "rustDocument/diagnosticsEnd"; pub const NOTIFICATION_WINDOW_PROGRESS: &str = "window/progress"; pub const NOTIFICATION_LANGUAGE_STATUS: &str = "language/status"; +pub const NOTIFICATION_DIAGNOSTICS_NEXT: &str = "languageClient/diagnosticsNext"; +pub const NOTIFICATION_DIAGNOSTICS_PREVIOUS: &str = "languageClient/diagnosticsPrevious"; pub const VIM_SERVER_STATUS: &str = "g:LanguageClient_serverStatus"; pub const VIM_SERVER_STATUS_MESSAGE: &str = "g:LanguageClient_serverStatusMessage"; From 6d3a69f9d0ba268f357696d05c49d729babfe7f7 Mon Sep 17 00:00:00 2001 From: Martin Asquino Date: Fri, 17 Jul 2020 17:24:47 +0100 Subject: [PATCH 2/2] Fix lint errors --- src/language_client.rs | 6 +++--- src/utils.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/language_client.rs b/src/language_client.rs index 4146ff36..555c7ecb 100644 --- a/src/language_client.rs +++ b/src/language_client.rs @@ -36,12 +36,12 @@ impl LanguageClient { // garbage collected as a result of another modification updating the hash map, while something was holding the lock pub fn get_client_update_mutex(&self, language_id: LanguageId) -> Result>> { let map_guard = self.clients_mutex.lock(); - let mut map = map_guard.or_else(|err| { - Err(anyhow!( + let mut map = map_guard.map_err(|err| { + anyhow!( "Failed to lock client creation for languageId {:?}: {:?}", language_id, err, - )) + ) })?; if !map.contains_key(&language_id) { map.insert(language_id.clone(), Arc::new(Mutex::new(()))); diff --git a/src/utils.rs b/src/utils.rs index 264339c5..45c91994 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -161,7 +161,7 @@ impl + std::fmt::Debug> ToUrl for P { fn to_url(&self) -> Result { Url::from_file_path(self) .or_else(|_| Url::from_str(&self.as_ref().to_string_lossy())) - .or_else(|_| Err(anyhow!("Failed to convert ({:?}) to Url", self))) + .map_err(|_| anyhow!("Failed to convert ({:?}) to Url", self)) } }