Skip to content

Commit a94e9f5

Browse files
committed
Add support to specifiy server name to send the correct initializationOptions
1 parent d6d6d08 commit a94e9f5

File tree

3 files changed

+103
-29
lines changed

3 files changed

+103
-29
lines changed

Diff for: autoload/LanguageClient.vim

+14
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,20 @@ function! s:Echowarn(message) abort
8181
echohl WarningMsg | echomsg s:AddPrefix(a:message) | echohl None
8282
endfunction
8383

84+
function! s:ShowAlert(name, lines) abort
85+
execute 'silent! pedit! +setlocal\\ ' .
86+
\ 'buftype=nofile\\ nobuflisted\\ ' .
87+
\ 'noswapfile\\ nonumber\\ ' .
88+
\ 'filetype=help' . ' ' . a:name
89+
90+
if has('nvim')
91+
let l:bufid = bufnr(a:name)
92+
call nvim_buf_set_lines(l:bufid, 0, -1, 0, a:lines)
93+
else
94+
" call setbufline(a:name, 1, a:lines)
95+
endif
96+
endfunction
97+
8498
" timeout: skip function call f until this timeout, in seconds.
8599
function! s:Debounce(timeout, f) abort
86100
" Map function to its last execute time.

Diff for: src/language_server_protocol.rs

+44-28
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl LanguageClient {
126126
is_nvim,
127127
): (
128128
u64,
129-
HashMap<String, Vec<String>>,
129+
HashMap<String, ServerCommand>,
130130
Option<String>,
131131
Option<String>,
132132
Vec<String>,
@@ -295,7 +295,7 @@ impl LanguageClient {
295295
state.semantic_highlight_maps = semantic_highlight_maps;
296296
state.semantic_scope_separator = semantic_scope_separator;
297297
state.semantic_scope_to_hl_group_table.clear();
298-
state.server_commands.extend(server_commands);
298+
state.server_commands = server_commands;
299299
state.selection_ui = selection_ui;
300300
state.selection_ui_auto_open = selection_ui_auto_open;
301301
state.trace = trace;
@@ -1136,6 +1136,42 @@ impl LanguageClient {
11361136
}
11371137
}
11381138

1139+
fn get_server_initialization_options_for_language_id(
1140+
&self,
1141+
root: &str,
1142+
language_id: &str,
1143+
) -> Result<Option<Value>> {
1144+
let server_name = self.server_name_for_language_id(&language_id)?;
1145+
let settings = self.get_workspace_settings(&root)?;
1146+
// warn the user that they are using a deprecated workspace settings
1147+
// file format and direct them to the documentation about the new one
1148+
if settings.pointer("/initializationOptions").is_some() {
1149+
let lines = vec![
1150+
"You seem to be using an incorrect workspace settings format for LanguageClient-neovim, to learn more about this error see `:help g:LanguageClient_settingsPath`",
1151+
];
1152+
self.vim()?
1153+
.rpcclient
1154+
.notify("s:ShowAlert", json!(["__LanguageClient__", lines]))?;
1155+
}
1156+
1157+
let section = format!("/{}", server_name);
1158+
let initialization_options = settings.pointer(section.as_str()).unwrap_or(&Value::Null);
1159+
let initialization_options =
1160+
get_default_initialization_options(&language_id).combine(&initialization_options);
1161+
1162+
if initialization_options.is_null() {
1163+
Ok(None)
1164+
} else {
1165+
Ok(Some(initialization_options))
1166+
}
1167+
}
1168+
1169+
pub fn server_name_for_language_id(&self, language_id: &str) -> Result<String> {
1170+
let server_commands = self.get(|state| state.server_commands.clone())?;
1171+
let server_command = server_commands.get(language_id).unwrap();
1172+
Ok(server_command.get_server_name())
1173+
}
1174+
11391175
/////// LSP ///////
11401176

11411177
fn initialize(&self, params: &Value) -> Result<Value> {
@@ -1147,23 +1183,12 @@ impl LanguageClient {
11471183
let has_snippet_support = has_snippet_support > 0;
11481184
let root = self.get(|state| state.roots.get(&language_id).cloned().unwrap_or_default())?;
11491185

1150-
let initialization_options = self
1151-
.get_workspace_settings(&root)
1152-
.map(|s| s["initializationOptions"].clone())
1153-
.unwrap_or_else(|err| {
1154-
warn!("Failed to get initializationOptions: {}", err);
1155-
json!(Value::Null)
1156-
});
1157-
let initialization_options =
1158-
get_default_initialization_options(&language_id).combine(&initialization_options);
1159-
let initialization_options = if initialization_options.is_null() {
1160-
None
1161-
} else {
1162-
Some(initialization_options)
1163-
};
1164-
11651186
let trace = self.get(|state| state.trace)?;
11661187
let preferred_markup_kind = self.get(|state| state.preferred_markup_kind.clone())?;
1188+
let initialization_options = self.get_server_initialization_options_for_language_id(
1189+
root.as_str(),
1190+
language_id.as_str(),
1191+
)?;
11671192

11681193
let result: Value = self.get_client(&Some(language_id.clone()))?.call(
11691194
lsp_types::request::Initialize::METHOD,
@@ -2923,7 +2948,7 @@ impl LanguageClient {
29232948

29242949
pub fn register_server_commands(&self, params: &Value) -> Result<Value> {
29252950
info!("Begin {}", REQUEST_REGISTER_SERVER_COMMANDS);
2926-
let commands = HashMap::<String, Vec<String>>::deserialize(params)?;
2951+
let commands = HashMap::<String, ServerCommand>::deserialize(params)?;
29272952
self.update(|state| {
29282953
state.server_commands.extend(commands);
29292954
Ok(())
@@ -3892,6 +3917,7 @@ impl LanguageClient {
38923917
language_id: language_id.clone(),
38933918
})
38943919
})?;
3920+
let command = command.get_command();
38953921

38963922
let root_path: Option<String> = try_get("rootPath", &params)?;
38973923
let root = if let Some(r) = root_path {
@@ -3995,16 +4021,6 @@ impl LanguageClient {
39954021
self.initialize(&params)?;
39964022
self.initialized(&params)?;
39974023

3998-
let root = self.get(|state| state.roots.get(&language_id).cloned().unwrap_or_default())?;
3999-
match self.get_workspace_settings(&root) {
4000-
Ok(Value::Null) => (),
4001-
Ok(settings) => self.workspace_did_change_configuration(&json!({
4002-
"languageId": language_id,
4003-
"settings": settings,
4004-
}))?,
4005-
Err(err) => warn!("Failed to get workspace settings: {}", err),
4006-
}
4007-
40084024
self.vim()?
40094025
.rpcclient
40104026
.notify("setbufvar", json!([filename, VIM_IS_SERVER_RUNNING, 1]))?;

Diff for: src/types.rs

+45-1
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,50 @@ pub enum UseVirtualText {
134134
No,
135135
}
136136

137+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
138+
pub struct CommandWithMeta {
139+
pub command: Vec<String>,
140+
pub server_name: Option<String>,
141+
}
142+
143+
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
144+
#[serde(untagged)]
145+
pub enum ServerCommand {
146+
Command(Vec<String>),
147+
CommandWithMeta(CommandWithMeta),
148+
}
149+
150+
impl ServerCommand {
151+
pub fn get_command(&self) -> &[String] {
152+
match self {
153+
ServerCommand::Command(cmd) => &cmd,
154+
ServerCommand::CommandWithMeta(cmd) => &cmd.command,
155+
}
156+
}
157+
158+
/// Returns the server name from a ServerCommand. For compatibility purposes, this
159+
/// makes a rather wild assumption when the server name hasn't been explicitly
160+
/// configured, the assumption is that the command for this server is an
161+
/// executable and that the name of the executable is the name of the server.
162+
/// This may not be true for many cases, but it's the best we can do to try and
163+
/// guess the name of the server.
164+
pub fn get_server_name(&self) -> String {
165+
match self {
166+
ServerCommand::Command(cmd) => ServerCommand::name_from_command(&cmd),
167+
ServerCommand::CommandWithMeta(cmd) => {
168+
let server_name = cmd.server_name.clone();
169+
server_name.unwrap_or_else(|| ServerCommand::name_from_command(&cmd.command))
170+
}
171+
}
172+
}
173+
174+
fn name_from_command(cmd: &[String]) -> String {
175+
// it's safe to assume there is at least one item in cmd, otherwise
176+
// this would be an empty server command
177+
cmd.first().cloned().unwrap_or_default()
178+
}
179+
}
180+
137181
#[derive(Serialize)]
138182
pub struct State {
139183
// Program state.
@@ -183,7 +227,7 @@ pub struct State {
183227
pub stashed_code_action_actions: Vec<CodeAction>,
184228

185229
// User settings.
186-
pub server_commands: HashMap<String, Vec<String>>,
230+
pub server_commands: HashMap<String, ServerCommand>,
187231
// languageId => (scope_regex => highlight group)
188232
pub semantic_highlight_maps: HashMap<String, HashMap<String, String>>,
189233
pub semantic_scope_separator: String,

0 commit comments

Comments
 (0)