fix(helix-term): Defer mutation of editor config to the application #14629
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
This is a proposed fix for #13187.
Commits
There are 2 commits in this PR.
997da16: Add integration tests to reproduce multi-command key binding bugThis commit adds 4 integration tests, one for each of the following scenarios:
:setcommand.:setcommands.:togglecommand.:togglecommands.a4eefb1: Defer mutation of editor config to the applicationThis commit reworks how the
:setand:togglecommands communicate config changes to the application. In the existing design, these commands do the following:keyargument.valueargument.The bug arises when multiple commands are mapped to a single key. In this case, the commands are executed serially. When each command is executed it loads the config, mutates it, and passes the result to the application. Because all of the bound commands execute before the results from any of them are applied, they all load the same config rather than each command loading the result from the previous command. This means the result of each command gets clobbered by the command following it and only the final command result actually gets applied.
In the new design, the commands do the following:
keyargument.The key difference is that the command is only passing a path and value to the application, not an entire config. This avoids the command capturing stale values for fields that it's not actually operating on.
This does result in some duplicated work since both the command and application need to load the config, convert it to a
serde_json::Value, etc. I think this is desirable because it keeps the behavior for each command in it's command handler. To deduplicate this work, we'd have to pass the raw arguments to the application, and then the command logic would need to move to the application as well. This logic is pretty trivial for:setbut it's somewhat complex for:toggle. Moving that logic to the application seems like it would be confusing and generally less than ideal.Testing
Integration Tests
I tested this by first adding a set of integration tests to reproduce the issue. Running these tests at
997da16(prior to the fix) I get the following result:Running these tests again at
a4eefb1(with the fix) I get:Manual Testing
I also verified the behavior is as expected when running the new build interactively.
I have the following snippet in my config:
Prior to this fix (and the reason I found the original bug report) these two bindings would only change the
inline-diagnostics.cursor-linesetting. With the fix, all three settings are adjusted as expected in both cases.