Skip to content

Commit 38347bb

Browse files
committed
Add function to execute code action by name (#1160)
1 parent 9c3f6d6 commit 38347bb

File tree

5 files changed

+66
-2
lines changed

5 files changed

+66
-2
lines changed

autoload/LanguageClient.vim

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,20 @@ function! LanguageClient#textDocument_codeAction(...) abort
10491049
call s:do_codeAction('n', a:000)
10501050
endfunction
10511051

1052+
function! LanguageClient#executeCodeAction(kind, ...) abort
1053+
let l:Callback = get(a:000, 1, v:null)
1054+
let l:params = {
1055+
\ 'filename': LSP#filename(),
1056+
\ 'line': LSP#line(),
1057+
\ 'character': LSP#character(),
1058+
\ 'handle': s:IsFalse(l:Callback),
1059+
\ 'range': LSP#range('n'),
1060+
\ 'kind': a:kind,
1061+
\ }
1062+
call extend(l:params, get(a:000, 0, {}))
1063+
return LanguageClient#Call('languageClient/executeCodeAction', l:params, l:Callback)
1064+
endfunction
1065+
10521066
function! LanguageClient#textDocument_completion(...) abort
10531067
" Note: do not add 'text' as it might be huge.
10541068
let l:params = {

doc/LanguageClient.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,21 @@ Signature: LanguageClient#textDocument_switchSourceHeader(...)
10251025

10261026
Calls clangd's `textDocument/switchSourceHeader` extension request.
10271027

1028+
*LanguageClient#executeCodeAction*
1029+
Signature: LanguageClient#executeCodeAction(kind, ...)
1030+
1031+
Tries to execute the code action with the give kind under the cursor position.
1032+
The action will only be executed if there is exactly one code action with that
1033+
kind under the cursor.
1034+
1035+
This function can be used to create commands for common LSP actions, such as
1036+
`source.organizeImports`. To do so you can create a command like this:
1037+
1038+
command! OrganizeImports call LanguageClient#executeCodeAction('source.organizeImports')
1039+
1040+
Note that this only works for code actions, not commands, and only in normal
1041+
mode.
1042+
10281043
==============================================================================
10291044
5. Mappings *LanguageClientMappings*
10301045

src/language_server_protocol.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,8 +1244,7 @@ impl LanguageClient {
12441244
Ok(result)
12451245
}
12461246

1247-
#[tracing::instrument(level = "info", skip(self))]
1248-
pub fn text_document_code_action(&self, params: &Value) -> Result<Value> {
1247+
pub fn get_code_actions(&self, params: &Value) -> Result<Value> {
12491248
self.text_document_did_change(params)?;
12501249
let filename = self.vim()?.get_filename(params)?;
12511250
let language_id = self.vim()?.get_language_id(&filename, params)?;
@@ -1281,6 +1280,40 @@ impl LanguageClient {
12811280
},
12821281
)?;
12831282

1283+
Ok(result)
1284+
}
1285+
1286+
#[tracing::instrument(level = "info", skip(self))]
1287+
pub fn execute_code_action(&self, params: &Value) -> Result<Value> {
1288+
let result = self.get_code_actions(params)?;
1289+
let response = <Option<CodeActionResponse>>::deserialize(&result)?;
1290+
let response: CodeActionResponse = response.unwrap_or_default();
1291+
let kind: String =
1292+
try_get("kind", params)?.ok_or_else(|| anyhow!("Missing kind parameter"))?;
1293+
let action_kind = CodeActionKind::from(kind.clone());
1294+
let actions: Vec<CodeActionOrCommand> = response.into_iter().filter(|a| matches!(a,
1295+
CodeActionOrCommand::CodeAction(action) if action.kind.is_some() && action.kind.as_ref().unwrap() == &action_kind)
1296+
).collect();
1297+
if actions.len() > 1 {
1298+
return Err(anyhow!("Too many code actions found with kind {}", kind));
1299+
}
1300+
if actions.len() == 0 {
1301+
return Err(anyhow!("No code actions found with kind {}", kind));
1302+
}
1303+
1304+
match actions.first().cloned() {
1305+
Some(CodeActionOrCommand::CodeAction(action)) => {
1306+
self.handle_code_action_selection(&[action], 0)?
1307+
}
1308+
_ => return Err(anyhow!("No code actions found with kind {}", kind)),
1309+
}
1310+
1311+
Ok(result)
1312+
}
1313+
1314+
#[tracing::instrument(level = "info", skip(self))]
1315+
pub fn text_document_code_action(&self, params: &Value) -> Result<Value> {
1316+
let result = self.get_code_actions(params)?;
12841317
let response = <Option<CodeActionResponse>>::deserialize(&result)?;
12851318
let response = response.unwrap_or_default();
12861319

src/rpchandler.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ impl LanguageClient {
120120
REQUEST_CODE_LENS_ACTION => self.handle_code_lens_action(&params),
121121
REQUEST_SEMANTIC_SCOPES => self.semantic_scopes(&params),
122122
REQUEST_SHOW_SEMANTIC_HL_SYMBOLS => self.semantic_highlight_symbols(&params),
123+
REQUEST_EXECUTE_CODE_ACTION => self.execute_code_action(&params),
123124

124125
clangd::request::SwitchSourceHeader::METHOD => {
125126
self.text_document_switch_source_header(&params)

src/types.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ pub const REQUEST_CODE_LENS_ACTION: &str = "LanguageClient/handleCodeLensAction"
6565
pub const REQUEST_SEMANTIC_SCOPES: &str = "languageClient/semanticScopes";
6666
pub const REQUEST_SHOW_SEMANTIC_HL_SYMBOLS: &str = "languageClient/showSemanticHighlightSymbols";
6767
pub const REQUEST_CLASS_FILE_CONTENTS: &str = "java/classFileContents";
68+
pub const REQUEST_EXECUTE_CODE_ACTION: &str = "languageClient/executeCodeAction";
6869

6970
pub const NOTIFICATION_HANDLE_BUF_NEW_FILE: &str = "languageClient/handleBufNewFile";
7071
pub const NOTIFICATION_HANDLE_BUF_ENTER: &str = "languageClient/handleBufEnter";

0 commit comments

Comments
 (0)