Skip to content

Commit a4eefb1

Browse files
committed
Defer mutation of editor config to the application
1 parent 997da16 commit a4eefb1

File tree

3 files changed

+37
-20
lines changed

3 files changed

+37
-20
lines changed

helix-term/src/application.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -376,22 +376,41 @@ impl Application {
376376
}
377377
}
378378

379+
fn update_config(
380+
&mut self,
381+
pointer: String,
382+
new_value: serde_json::Value,
383+
) -> anyhow::Result<()> {
384+
let mut app_config = (*self.config.load().clone()).clone();
385+
let mut editor_config = serde_json::json!(app_config.editor);
386+
387+
let old_value = editor_config
388+
.pointer_mut(&pointer)
389+
.ok_or_else(|| anyhow::anyhow!("Unknown key `{}`", pointer))?;
390+
*old_value = new_value;
391+
392+
app_config.editor = serde_json::from_value(editor_config)
393+
.map_err(|_| anyhow::anyhow!("Could not parse field"))?;
394+
395+
self.terminal.reconfigure((&app_config.editor).into())?;
396+
self.config.store(Arc::new(app_config));
397+
Ok(())
398+
}
399+
379400
pub fn handle_config_events(&mut self, config_event: ConfigEvent) {
380401
let old_editor_config = self.editor.config();
381402

382403
match config_event {
383404
ConfigEvent::Refresh => self.refresh_config(),
384405

385406
// Since only the Application can make changes to Editor's config,
386-
// the Editor must send up a new copy of a modified config so that
387-
// the Application can apply it.
388-
ConfigEvent::Update(editor_config) => {
389-
let mut app_config = (*self.config.load().clone()).clone();
390-
app_config.editor = *editor_config;
391-
if let Err(err) = self.terminal.reconfigure((&app_config.editor).into()) {
407+
// the Editor must send an update request so that the Application
408+
// can apply it. Each update request includes a path to the field
409+
// that should be updated and the new value for that field.
410+
ConfigEvent::Update(pointer, new_value) => {
411+
if let Err(err) = self.update_config(pointer, new_value) {
392412
self.editor.set_error(err.to_string());
393413
};
394-
self.config.store(Arc::new(app_config));
395414
}
396415
}
397416

helix-term/src/commands/typed.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,22 +2060,21 @@ fn set_option(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> a
20602060
let key_error = || anyhow::anyhow!("Unknown key `{}`", key);
20612061
let field_error = |_| anyhow::anyhow!("Could not parse field `{}`", arg);
20622062

2063-
let mut config = serde_json::json!(&cx.editor.config().deref());
2063+
let config = serde_json::json!(&cx.editor.config().deref());
20642064
let pointer = format!("/{}", key.replace('.', "/"));
2065-
let value = config.pointer_mut(&pointer).ok_or_else(key_error)?;
2065+
let value = config.pointer(&pointer).ok_or_else(key_error)?;
20662066

2067-
*value = if value.is_string() {
2067+
let value = if value.is_string() {
20682068
// JSON strings require quotes, so we can't .parse() directly
20692069
Value::String(arg.to_string())
20702070
} else {
20712071
arg.parse().map_err(field_error)?
20722072
};
2073-
let config = serde_json::from_value(config).map_err(field_error)?;
20742073

20752074
cx.editor
20762075
.config_events
20772076
.0
2078-
.send(ConfigEvent::Update(config))?;
2077+
.send(ConfigEvent::Update(pointer, value))?;
20792078
Ok(())
20802079
}
20812080

@@ -2095,11 +2094,11 @@ fn toggle_option(
20952094

20962095
let key_error = || anyhow::anyhow!("Unknown key `{}`", key);
20972096

2098-
let mut config = serde_json::json!(&cx.editor.config().deref());
2097+
let config = serde_json::json!(&cx.editor.config().deref());
20992098
let pointer = format!("/{}", key.replace('.', "/"));
2100-
let value = config.pointer_mut(&pointer).ok_or_else(key_error)?;
2099+
let value = config.pointer(&pointer).ok_or_else(key_error)?;
21012100

2102-
*value = match value {
2101+
let value = match value {
21032102
Value::Bool(ref value) => {
21042103
ensure!(
21052104
args.len() == 1,
@@ -2149,7 +2148,7 @@ fn toggle_option(
21492148

21502149
if let Some(wrongly_typed_value) = values
21512150
.iter()
2152-
.find(|v| std::mem::discriminant(*v) != std::mem::discriminant(&*value))
2151+
.find(|v| std::mem::discriminant(*v) != std::mem::discriminant(value))
21532152
{
21542153
bail!("value '{wrongly_typed_value}' has a different type than '{value}'");
21552154
}
@@ -2164,13 +2163,11 @@ fn toggle_option(
21642163
};
21652164

21662165
let status = format!("'{key}' is now set to {value}");
2167-
let config = serde_json::from_value(config)
2168-
.map_err(|err| anyhow::anyhow!("Failed to parse config: {err}"))?;
21692166

21702167
cx.editor
21712168
.config_events
21722169
.0
2173-
.send(ConfigEvent::Update(config))?;
2170+
.send(ConfigEvent::Update(pointer, value))?;
21742171
cx.editor.set_status(status);
21752172
Ok(())
21762173
}

helix-view/src/editor.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ use helix_lsp::lsp;
5656
use helix_stdx::path::canonicalize;
5757

5858
use serde::{ser::SerializeMap, Deserialize, Deserializer, Serialize, Serializer};
59+
use serde_json::Value;
5960

6061
use arc_swap::{
6162
access::{DynAccess, DynGuard},
@@ -1236,7 +1237,7 @@ pub enum EditorEvent {
12361237
#[derive(Debug, Clone)]
12371238
pub enum ConfigEvent {
12381239
Refresh,
1239-
Update(Box<Config>),
1240+
Update(String, Value),
12401241
}
12411242

12421243
enum ThemeAction {

0 commit comments

Comments
 (0)