Skip to content

Commit 4ff0ef4

Browse files
committed
Support funcref in LanguageClient_diagnosticsList
1 parent 2dd003d commit 4ff0ef4

File tree

5 files changed

+181
-92
lines changed

5 files changed

+181
-92
lines changed

Diff for: autoload/LanguageClient.vim

+10-2
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,14 @@ function! s:hasSnippetSupport() abort
117117
return 0
118118
endfunction
119119

120+
function! s:getStringOrFuncref(name, default) abort
121+
if type(get(g:, a:name, a:default)) is s:TYPE.funcref
122+
return string(get(g:, a:name, a:default))
123+
else
124+
return get(g:, a:name, a:default)
125+
endif
126+
endfunction
127+
120128
function! s:getSelectionUI() abort
121129
if type(get(g:, 'LanguageClient_selectionUI', v:null)) is s:TYPE.funcref
122130
return 'funcref'
@@ -1227,11 +1235,11 @@ function! LanguageClient#handleVimLeavePre() abort
12271235
endtry
12281236
endfunction
12291237

1230-
function! s:LanguageClient_FZFSinkLocation(line) abort
1238+
function! g:LanguageClient_FZFSinkLocation(line) abort
12311239
return LanguageClient#Notify('LanguageClient_FZFSinkLocation', [a:line])
12321240
endfunction
12331241

1234-
function! LanguageClient_FZFSinkCommand(selection) abort
1242+
function! g:LanguageClient_FZFSinkCommand(selection) abort
12351243
return LanguageClient#Notify('LanguageClient_FZFSinkCommand', {
12361244
\ 'selection': a:selection,
12371245
\ })

Diff for: doc/LanguageClient.txt

+43-46
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,49 @@ Valid options: "off" | "messages" | "verbose"
207207
List used to fill diagnostic messages.
208208

209209
Default: "Quickfix"
210-
Valid options: "Quickfix" | "Location" | "Disabled"
210+
Valid options: "Quickfix" | "Location" | "Disabled" | |Funcref|
211+
212+
If you use a |Funcref|, the referenced function should have two arguments
213+
(filename, diagnostics). filename is the name of the file of which the
214+
diagnostics correspond to, and diagnostics is the list of diagnostics for said
215+
file. Those diagnostics are as specified in the LSP specification.
216+
217+
For example, if you wanted to use `dense-analysis/ale` to display diagnostics
218+
instead of this plugin you could use something like this:
219+
220+
```
221+
function! DisplayDiagnostics(filename, diagnostics) abort
222+
let s:diagnostics = []
223+
224+
for d in a:diagnostics
225+
let s:severity = 'I'
226+
if d.severity == 1
227+
let s:severity = 'E'
228+
elseif d.severity == 2
229+
let s:severity = 'W'
230+
endif
231+
232+
call add(s:diagnostics, {
233+
\ "filename": a:filename,
234+
\ "text": d.message,
235+
\ "lnum": d.range.start.line + 1,
236+
\ "end_lnum": d.range.end.line + 1,
237+
\ "col": d.range.end.character,
238+
\ "end_col": d.range.end.character,
239+
\ "type": s:severity,
240+
\ })
241+
endfor
242+
243+
call ale#other_source#ShowResults(bufnr('%'), 'LanguageClientNeovim', s:diagnostics)
244+
endfunction
245+
246+
let g:LanguageClient_diagnosticsDisplayFuncref = function('DisplayDiagnostics')
247+
```
248+
249+
Keep in mind that to complete the integration between `ale` and
250+
`LanguageClient-neovim` you need to add `LanguageClientNeovim` (or the name of
251+
the linter you used in the call to ShowResults) to the list of linters to be
252+
used in `ale`.
211253

212254
2.10 g:LanguageClient_diagnosticsEnable *g:LanguageClient_diagnosticsEnable*
213255

@@ -635,51 +677,6 @@ Highlight group to be used for code lens.
635677

636678
Default: 'Comment'
637679

638-
2.42 g:LanguageClient_diagnosticsDisplayFuncref *g:LanguageClient_diagnosticsDisplayFuncref*
639-
640-
If set, LanguageClient-neovim will call this function instead of setting the diagnostics signs. This
641-
is useful to delegate the display of diagnostics to other engines. The function is called with two
642-
arguments, the first one is the file name of which the diagnostics correspond to, and the seconds one
643-
is the list of diagnostics for said file. Those diagnostics are as specified in the LSP specification.
644-
645-
For example, if you wanted to use `dense-analysis/ale` to display diagnostics instead of this plugin
646-
you could use something like this:
647-
648-
```
649-
function! g:DisplayDiagnostics(filename, diagnostics) abort
650-
let s:diagnostics = []
651-
652-
for d in a:diagnostics
653-
let s:severity = 'I'
654-
if d.severity == 1
655-
let s:severity = 'E'
656-
elseif d.severity == 2
657-
let s:severity = 'W'
658-
endif
659-
660-
call add(s:diagnostics, {
661-
\ "filename": a:filename,
662-
\ "text": d.message,
663-
\ "lnum": d.range.start.line + 1,
664-
\ "end_lnum": d.range.end.line + 1,
665-
\ "col": d.range.end.character,
666-
\ "end_col": d.range.end.character,
667-
\ "type": s:severity,
668-
\ })
669-
endfor
670-
671-
call ale#other_source#ShowResults(bufnr('%'), 'LanguageClientNeovim', s:diagnostics)
672-
endfunction
673-
674-
let g:LanguageClient_diagnosticsDisplayFuncref = 'g:DisplayDiagnostics'
675-
```
676-
677-
Keep in mind that to complete the integration between `ale` and `LanguageClient-neovim` you need to
678-
add `LanguageClientNeovim` (or the name of the linter you used in the call to ShowResults) to the list
679-
of linters to be used in `ale`.
680-
681-
Default: v:null
682-
683680
==============================================================================
684681
3. Commands *LanguageClientCommands*
685682

Diff for: src/language_server_protocol.rs

+56-34
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use crate::extensions::java;
21
use crate::language_client::LanguageClient;
32
use crate::vim::{try_get, Mode};
3+
use crate::{extensions::java, vim::Funcref};
44
use crate::{
55
rpcclient::RpcClient,
66
types::*,
@@ -127,15 +127,15 @@ impl LanguageClient {
127127
): (
128128
u64,
129129
HashMap<String, Vec<String>>,
130-
Option<String>,
130+
Option<Either<Funcref, String>>,
131131
Option<String>,
132132
Vec<String>,
133133
u64,
134134
Option<RootMarkers>,
135135
Option<f64>,
136136
Option<f64>,
137137
u64,
138-
Option<String>,
138+
Option<Either<Funcref, String>>,
139139
Value,
140140
String,
141141
Option<String>,
@@ -145,15 +145,15 @@ impl LanguageClient {
145145
[
146146
"!!get(g:, 'LanguageClient_autoStart', 1)",
147147
"s:GetVar('LanguageClient_serverCommands', {})",
148-
"s:getSelectionUI()",
148+
"s:getStringOrFuncref('LanguageClient_selectionUI', v:null)",
149149
"get(g:, 'LanguageClient_trace', v:null)",
150150
"map(s:ToList(get(g:, 'LanguageClient_settingsPath', '.vim/settings.json')), 'expand(v:val)')",
151151
"!!get(g:, 'LanguageClient_loadSettings', 1)",
152152
"get(g:, 'LanguageClient_rootMarkers', v:null)",
153153
"get(g:, 'LanguageClient_changeThrottle', v:null)",
154154
"get(g:, 'LanguageClient_waitOutputTimeout', v:null)",
155155
"!!get(g:, 'LanguageClient_diagnosticsEnable', 1)",
156-
"get(g:, 'LanguageClient_diagnosticsList', 'Quickfix')",
156+
"s:getStringOrFuncref('LanguageClient_diagnosticsList', 'Quickfix')",
157157
"get(g:, 'LanguageClient_diagnosticsDisplay', {})",
158158
"get(g:, 'LanguageClient_windowLogMessageLevel', 'Warning')",
159159
"get(g:, 'LanguageClient_hoverPreview', 'Auto')",
@@ -165,7 +165,6 @@ impl LanguageClient {
165165

166166
#[allow(clippy::type_complexity)]
167167
let (
168-
diagnostics_display_funcref,
169168
diagnostics_signs_max,
170169
diagnostics_max_severity,
171170
diagnostics_ignore_sources,
@@ -181,7 +180,6 @@ impl LanguageClient {
181180
enable_extensions,
182181
code_lens_hl_group,
183182
): (
184-
Option<String>,
185183
Option<usize>,
186184
String,
187185
Vec<String>,
@@ -198,7 +196,6 @@ impl LanguageClient {
198196
String,
199197
) = self.vim()?.eval(
200198
[
201-
"get(g:, 'LanguageClient_diagnosticsDisplayFuncref', v:null)",
202199
"get(g:, 'LanguageClient_diagnosticsSignsMax', v:null)",
203200
"get(g:, 'LanguageClient_diagnosticsMaxSeverity', 'Hint')",
204201
"get(g:, 'LanguageClient_diagnosticsIgnoreSources', [])",
@@ -232,12 +229,12 @@ impl LanguageClient {
232229
None => Some(TraceOption::default()),
233230
};
234231

235-
let selection_ui = if let Some(s) = selection_ui {
236-
SelectionUI::from_str(&s)?
237-
} else if self.vim()?.eval::<_, i64>("get(g:, 'loaded_fzf')")? == 1 {
238-
SelectionUI::Funcref
232+
let selection_ui = if let Some(Either::Right(s)) = selection_ui {
233+
Either::Right(SelectionUI::from_str(&s)?)
234+
} else if let Some(Either::Left(s)) = selection_ui {
235+
Either::Left(s)
239236
} else {
240-
SelectionUI::default()
237+
Either::Right(SelectionUI::default())
241238
};
242239

243240
let change_throttle = change_throttle.map(|t| Duration::from_millis((t * 1000.0) as u64));
@@ -246,10 +243,12 @@ impl LanguageClient {
246243

247244
let diagnostics_enable = diagnostics_enable == 1;
248245

249-
let diagnostics_list = if let Some(s) = diagnostics_list {
250-
DiagnosticsList::from_str(&s)?
246+
let diagnostics_list = if let Some(Either::Right(s)) = diagnostics_list {
247+
Either::Right(DiagnosticsList::from_str(&s)?)
248+
} else if let Some(Either::Left(s)) = diagnostics_list {
249+
Either::Left(s)
251250
} else {
252-
DiagnosticsList::Disabled
251+
Either::Right(DiagnosticsList::Disabled)
253252
};
254253

255254
let window_log_level = match window_log_message_level.to_ascii_uppercase().as_str() {
@@ -331,7 +330,6 @@ impl LanguageClient {
331330
state.preferred_markup_kind = preferred_markup_kind;
332331
state.enable_extensions = enable_extensions;
333332
state.code_lens_hl_group = code_lens_hl_group;
334-
state.diagnostics_display_funcref = diagnostics_display_funcref;
335333

336334
Ok(())
337335
})?;
@@ -686,15 +684,18 @@ impl LanguageClient {
686684
.collect();
687685

688686
let title = "[LC]: diagnostics";
689-
let diagnostics_list = self.get(|state| state.diagnostics_list)?;
687+
let diagnostics_list = self.get(|state| state.diagnostics_list.clone())?;
690688
match diagnostics_list {
691-
DiagnosticsList::Quickfix => {
692-
self.vim()?.setqflist(&qflist, "r", title)?;
693-
}
694-
DiagnosticsList::Location => {
695-
self.vim()?.setloclist(&qflist, "r", title)?;
696-
}
697-
DiagnosticsList::Disabled => {}
689+
Either::Left(_) => {}
690+
Either::Right(dl) => match dl {
691+
DiagnosticsList::Quickfix => {
692+
self.vim()?.setqflist(&qflist, "r", title)?;
693+
}
694+
DiagnosticsList::Location => {
695+
self.vim()?.setloclist(&qflist, "r", title)?;
696+
}
697+
DiagnosticsList::Disabled => {}
698+
},
698699
}
699700

700701
Ok(())
@@ -1890,14 +1891,21 @@ impl LanguageClient {
18901891
.map(|it| ListItem::string_item(it, self, &cwd))
18911892
.collect();
18921893

1893-
match self.get(|state| state.selection_ui)? {
1894-
SelectionUI::Funcref => {
1894+
match self.get(|state| state.selection_ui.clone())? {
1895+
Either::Left(f) => {
1896+
self.vim()?
1897+
.rpcclient
1898+
.notify(f, json!([actions?, NOTIFICATION_FZF_SINK_COMMAND]))?;
1899+
}
1900+
// this exists purely for compatibility purposes, we should consider dropping this at
1901+
// some point and letting the user set up the FZF integration via a funcref
1902+
Either::Right(SelectionUI::FZF) => {
18951903
self.vim()?.rpcclient.notify(
18961904
"s:selectionUI_funcref",
18971905
json!([actions?, NOTIFICATION_FZF_SINK_COMMAND]),
18981906
)?;
18991907
}
1900-
SelectionUI::Quickfix | SelectionUI::LocationList => {
1908+
Either::Right(SelectionUI::Quickfix) | Either::Right(SelectionUI::LocationList) => {
19011909
let mut actions: Vec<String> = actions?
19021910
.iter_mut()
19031911
.enumerate()
@@ -1922,11 +1930,25 @@ impl LanguageClient {
19221930
where
19231931
T: ListItem,
19241932
{
1925-
let selection_ui = self.get(|state| state.selection_ui)?;
1933+
let selection_ui = self.get(|state| state.selection_ui.clone())?;
19261934
let selection_ui_auto_open = self.get(|state| state.selection_ui_auto_open)?;
19271935

19281936
match selection_ui {
1929-
SelectionUI::Funcref => {
1937+
Either::Left(f) => {
1938+
let cwd: String = self.vim()?.eval("getcwd()")?;
1939+
let source: Result<Vec<_>> = items
1940+
.iter()
1941+
.map(|it| ListItem::string_item(it, self, &cwd))
1942+
.collect();
1943+
let source = source?;
1944+
1945+
self.vim()?
1946+
.rpcclient
1947+
.notify(f, json!([source, NOTIFICATION_FZF_SINK_LOCATION]))?;
1948+
}
1949+
// this exists purely for compatibility purposes, we should consider dropping this at
1950+
// some point and letting the user set up the FZF integration via a funcref
1951+
Either::Right(SelectionUI::FZF) => {
19301952
let cwd: String = self.vim()?.eval("getcwd()")?;
19311953
let source: Result<Vec<_>> = items
19321954
.iter()
@@ -1936,10 +1958,10 @@ impl LanguageClient {
19361958

19371959
self.vim()?.rpcclient.notify(
19381960
"s:selectionUI_funcref",
1939-
json!([source, format!("s:{}", NOTIFICATION_FZF_SINK_LOCATION)]),
1961+
json!([source, NOTIFICATION_FZF_SINK_LOCATION]),
19401962
)?;
19411963
}
1942-
SelectionUI::Quickfix => {
1964+
Either::Right(SelectionUI::Quickfix) => {
19431965
let list: Result<Vec<_>> = items
19441966
.iter()
19451967
.map(|it| ListItem::quickfix_item(it, self))
@@ -1951,7 +1973,7 @@ impl LanguageClient {
19511973
}
19521974
self.vim()?.echo("Populated quickfix list.")?;
19531975
}
1954-
SelectionUI::LocationList => {
1976+
Either::Right(SelectionUI::LocationList) => {
19551977
let list: Result<Vec<_>> = items
19561978
.iter()
19571979
.map(|it| ListItem::quickfix_item(it, self))
@@ -2476,7 +2498,7 @@ impl LanguageClient {
24762498
}
24772499

24782500
// if a diagnostics display funcref has been configured then call that function and return
2479-
if let Some(funcref) = self.get(|state| state.diagnostics_display_funcref.clone())? {
2501+
if let Either::Left(funcref) = self.get(|state| state.diagnostics_list.clone())? {
24802502
self.vim()?
24812503
.rpcclient
24822504
.notify(funcref, json!([filename, diagnostics]))?;

0 commit comments

Comments
 (0)