Skip to content

Commit fe8b0a6

Browse files
committed
Split global and document settings
1 parent 46a60fc commit fe8b0a6

File tree

3 files changed

+96
-38
lines changed

3 files changed

+96
-38
lines changed

crates/ark/src/lsp/config.rs

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,45 @@ use serde_json::Value;
44

55
use crate::lsp::diagnostics::DiagnosticsConfig;
66

7-
pub struct Setting {
7+
pub struct Setting<T> {
88
pub key: &'static str,
9-
pub set: fn(&mut LspConfig, Value),
9+
pub set: fn(&mut T, Value),
1010
}
1111

12-
// List of LSP settings for which clients can send `didChangeConfiguration`
13-
// notifications. We register our interest in watching over these settings in
14-
// our `initialized` handler. The `set` methods convert from a json `Value` to
15-
// the expected type, using a default value if the conversion fails.
16-
pub static SETTINGS: &[Setting] = &[
12+
/// List of LSP settings for which clients can send `didChangeConfiguration`
13+
/// notifications. We register our interest in watching over these settings in
14+
/// our `initialized` handler. The `set` methods convert from a json `Value` to
15+
/// the expected type, using a default value if the conversion fails.
16+
///
17+
/// This array is for global settings. If the setting should only affect a given
18+
/// document URI, add it to `DOCUMENT_SETTINGS` instead.
19+
pub static GLOBAL_SETTINGS: &[Setting<LspConfig>] = &[
20+
Setting {
21+
key: "positron.r.diagnostics.enable",
22+
set: |cfg, v| {
23+
cfg.diagnostics.enable = v
24+
.as_bool()
25+
.unwrap_or_else(|| DiagnosticsConfig::default().enable)
26+
},
27+
},
28+
Setting {
29+
key: "positron.r.symbols.includeAssignmentsInBlocks",
30+
set: |cfg, v| {
31+
cfg.symbols.include_assignments_in_blocks = v
32+
.as_bool()
33+
.unwrap_or_else(|| SymbolsConfig::default().include_assignments_in_blocks)
34+
},
35+
},
36+
];
37+
38+
/// These document settings are updated on a URI basis. Each document has its
39+
/// own value of the setting.
40+
pub static DOCUMENT_SETTINGS: &[Setting<DocumentConfig>] = &[
1741
Setting {
1842
key: "editor.insertSpaces",
1943
set: |cfg, v| {
2044
let default_style = IndentationConfig::default().indent_style;
21-
cfg.document.indent.indent_style = if v
45+
cfg.indent.indent_style = if v
2246
.as_bool()
2347
.unwrap_or_else(|| default_style == IndentStyle::Space)
2448
{
@@ -31,7 +55,7 @@ pub static SETTINGS: &[Setting] = &[
3155
Setting {
3256
key: "editor.indentSize",
3357
set: |cfg, v| {
34-
cfg.document.indent.indent_size = v
58+
cfg.indent.indent_size = v
3559
.as_u64()
3660
.map(|n| n as usize)
3761
.unwrap_or_else(|| IndentationConfig::default().indent_size)
@@ -40,36 +64,19 @@ pub static SETTINGS: &[Setting] = &[
4064
Setting {
4165
key: "editor.tabSize",
4266
set: |cfg, v| {
43-
cfg.document.indent.tab_width = v
67+
cfg.indent.tab_width = v
4468
.as_u64()
4569
.map(|n| n as usize)
4670
.unwrap_or_else(|| IndentationConfig::default().tab_width)
4771
},
4872
},
49-
Setting {
50-
key: "positron.r.diagnostics.enable",
51-
set: |cfg, v| {
52-
cfg.diagnostics.enable = v
53-
.as_bool()
54-
.unwrap_or_else(|| DiagnosticsConfig::default().enable)
55-
},
56-
},
57-
Setting {
58-
key: "positron.r.symbols.includeAssignmentsInBlocks",
59-
set: |cfg, v| {
60-
cfg.symbols.include_assignments_in_blocks = v
61-
.as_bool()
62-
.unwrap_or_else(|| SymbolsConfig::default().include_assignments_in_blocks)
63-
},
64-
},
6573
];
6674

6775
/// Configuration of the LSP
6876
#[derive(Clone, Default, Debug)]
6977
pub(crate) struct LspConfig {
7078
pub(crate) diagnostics: DiagnosticsConfig,
7179
pub(crate) symbols: SymbolsConfig,
72-
pub(crate) document: DocumentConfig,
7380
}
7481

7582
#[derive(Serialize, Deserialize, Clone, Debug)]

crates/ark/src/lsp/handlers.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,14 @@ pub(crate) async fn handle_initialized(
103103
// changed by extensions or by the user without changing the actual
104104
// underlying setting. Unfortunately we don't receive updates in that case.
105105

106-
for setting in crate::lsp::config::SETTINGS {
106+
for setting in crate::lsp::config::GLOBAL_SETTINGS {
107+
regs.push(Registration {
108+
id: uuid::Uuid::new_v4().to_string(),
109+
method: String::from("workspace/didChangeConfiguration"),
110+
register_options: Some(serde_json::json!({ "section": setting.key })),
111+
});
112+
}
113+
for setting in crate::lsp::config::DOCUMENT_SETTINGS {
107114
regs.push(Registration {
108115
id: uuid::Uuid::new_v4().to_string(),
109116
method: String::from("workspace/didChangeConfiguration"),

crates/ark/src/lsp/state_handlers.rs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use std::path::Path;
99

1010
use anyhow::anyhow;
11+
use tower_lsp::lsp_types;
1112
use tower_lsp::lsp_types::CompletionOptions;
1213
use tower_lsp::lsp_types::CompletionOptionsCompletionItem;
1314
use tower_lsp::lsp_types::DidChangeConfigurationParams;
@@ -39,7 +40,8 @@ use url::Url;
3940
use crate::lsp;
4041
use crate::lsp::capabilities::Capabilities;
4142
use crate::lsp::config::indent_style_from_lsp;
42-
use crate::lsp::config::SETTINGS;
43+
use crate::lsp::config::DOCUMENT_SETTINGS;
44+
use crate::lsp::config::GLOBAL_SETTINGS;
4345
use crate::lsp::documents::Document;
4446
use crate::lsp::encoding::get_position_encoding_kind;
4547
use crate::lsp::indexer;
@@ -277,34 +279,76 @@ pub(crate) fn did_change_formatting_options(
277279
}
278280

279281
async fn update_config(
280-
_uris: Vec<Url>,
282+
uris: Vec<Url>,
281283
client: &tower_lsp::Client,
282284
state: &mut WorldState,
283285
) -> anyhow::Result<()> {
284-
// Build the configuration request for global settings
285-
let items: Vec<_> = SETTINGS
286+
// Build the configuration request for global and document settings
287+
let mut items: Vec<_> = vec![];
288+
289+
// This should be first because we first handle the global settings below,
290+
// splitting them off the response array
291+
let mut global_items: Vec<_> = GLOBAL_SETTINGS
286292
.iter()
287-
.map(|mapping| tower_lsp::lsp_types::ConfigurationItem {
293+
.map(|mapping| lsp_types::ConfigurationItem {
288294
scope_uri: None,
289295
section: Some(mapping.key.to_string()),
290296
})
291297
.collect();
292298

293-
let configs = client.configuration(items).await?;
299+
// For document items we create a n_uris * n_document_settings array that we'll
300+
// handle by batch in a double loop over URIs and document settings
301+
let mut document_items: Vec<_> = uris
302+
.iter()
303+
.flat_map(|uri| {
304+
DOCUMENT_SETTINGS
305+
.iter()
306+
.map(|mapping| lsp_types::ConfigurationItem {
307+
scope_uri: Some(uri.clone()),
308+
section: Some(mapping.key.to_string()),
309+
})
310+
})
311+
.collect();
312+
313+
// Concatenate everything into a flat array that we'll send in one request
314+
items.append(&mut global_items);
315+
items.append(&mut document_items);
316+
317+
// The response better match the number of items we send in
318+
let n_items = items.len();
319+
320+
let mut configs = client.configuration(items).await?;
294321

295-
if configs.len() != SETTINGS.len() {
322+
if configs.len() != n_items {
296323
return Err(anyhow!(
297324
"Unexpected number of retrieved configurations: {}/{}",
298325
configs.len(),
299-
SETTINGS.len()
326+
n_items
300327
));
301328
}
302329

303-
// Apply each config value using its update closure
304-
for (mapping, value) in SETTINGS.iter().zip(configs) {
330+
let document_configs = configs.split_off(GLOBAL_SETTINGS.len());
331+
let global_configs = configs;
332+
333+
for (mapping, value) in GLOBAL_SETTINGS.into_iter().zip(global_configs) {
305334
(mapping.set)(&mut state.config, value);
306335
}
307336

337+
let mut remaining = document_configs;
338+
339+
for uri in uris.into_iter() {
340+
// Need to juggle a bit because `split_off()` returns the tail of the
341+
// split and updates the vector with the head
342+
let tail = remaining.split_off(DOCUMENT_SETTINGS.len());
343+
let head = std::mem::replace(&mut remaining, tail);
344+
345+
for (mapping, value) in DOCUMENT_SETTINGS.iter().zip(head) {
346+
if let Ok(doc) = state.get_document_mut(&uri) {
347+
(mapping.set)(&mut doc.config, value);
348+
}
349+
}
350+
}
351+
308352
Ok(())
309353
}
310354

0 commit comments

Comments
 (0)