Add completions.lsp_insert_mode setting to control what ranges are replaced when a completion is inserted (#27453)

This PR adds `completions.lsp_insert_mode` and effectively changes the
default from `"replace"` to `"replace_suffix"`, which automatically
detects whether to use the LSP `replace` range instead of `insert`
range.

`"replace_suffix"` was chosen as a default because it's more
conservative than `"replace_subsequence"`, considering that deleting
text is usually faster and less disruptive than having to rewrite a long
replaced word.

Fixes #27197
Fixes #23395 (again)
Fixes #4816 (again)

Release Notes:

- Added new setting `completions.lsp_insert_mode` that changes what will
be replaced when an LSP completion is accepted. The default is
`"replace_suffix"`, but it accepts 4 values: `"insert"` for replacing
only the text before the cursor, `"replace"` for replacing the whole
text, `"replace_suffix"` that acts like `"replace"` when the text after
the cursor is a suffix of the completion, and `"replace_subsequence"`
that acts like `"replace"` when the text around your cursor is a
subsequence of the completion (similiar to a fuzzy match). Check [the
documentation](https://zed.dev/docs/configuring-zed#LSP-Insert-Mode) for
more information.

---------

Co-authored-by: João Marcos <marcospb19@hotmail.com>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
frederik-uni 2025-04-02 21:55:03 +02:00 committed by GitHub
parent 108ae0b5b0
commit 07a77792c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 467 additions and 13 deletions

View file

@ -61,7 +61,7 @@ pub fn all_language_settings<'a>(
pub struct AllLanguageSettings {
/// The edit prediction settings.
pub edit_predictions: EditPredictionSettings,
defaults: LanguageSettings,
pub defaults: LanguageSettings,
languages: HashMap<LanguageName, LanguageSettings>,
pub(crate) file_types: HashMap<Arc<str>, GlobSet>,
}
@ -329,6 +329,11 @@ pub struct CompletionSettings {
/// Default: 0
#[serde(default = "default_lsp_fetch_timeout_ms")]
pub lsp_fetch_timeout_ms: u64,
/// Controls how LSP completions are inserted.
///
/// Default: "replace_suffix"
#[serde(default = "default_lsp_insert_mode")]
pub lsp_insert_mode: LspInsertMode,
}
/// Controls how document's words are completed.
@ -345,10 +350,29 @@ pub enum WordsCompletionMode {
Disabled,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum LspInsertMode {
/// Replaces text before the cursor, using the `insert` range described in the LSP specification.
Insert,
/// Replaces text before and after the cursor, using the `replace` range described in the LSP specification.
Replace,
/// Behaves like `"replace"` if the text that would be replaced is a subsequence of the completion text,
/// and like `"insert"` otherwise.
ReplaceSubsequence,
/// Behaves like `"replace"` if the text after the cursor is a suffix of the completion, and like
/// `"insert"` otherwise.
ReplaceSuffix,
}
fn default_words_completion_mode() -> WordsCompletionMode {
WordsCompletionMode::Fallback
}
fn default_lsp_insert_mode() -> LspInsertMode {
LspInsertMode::Insert
}
fn default_lsp_fetch_timeout_ms() -> u64 {
0
}