Update default vim substitute command behavior and add support for 'g' flag (#28138)
This Pull Request updates the default behavior of the substitute (`s`) command in vim mode to only replace the next match by default, instead of all, and replace all matches only when the `g` flag is provided, making it more similar to NeoVim's behavior. In order to achieve this, the following changes were introduced: - Update `BufferSearchBar::replace_next` to be a public method, so it can be called from `Vim::replace_command` . - Update the `Replacement::parse` to set the `should_replace_all` field to `false` by default, and only set it to `true` if the `'g'` flag is present in the query. - Add support for when the `Replacement.should_replace_all` is set to `false` in `Vim::replace_command`, so as to have it only replace the next occurrence instead of all occurrences in the line. - Introduce `BufferSearchBar::select_first_match` so as to activate the first match on the line under the cursor. Closes #24450 Release Notes: - Improved vim's substitute command so as to only replace the first match by default, and replace all matches if the `'g'` flag is provided --------- Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
parent
60c420a2da
commit
af5318df98
8 changed files with 79 additions and 26 deletions
|
@ -445,6 +445,8 @@ impl Vim {
|
|||
}
|
||||
let vim = cx.entity().clone();
|
||||
pane.update(cx, |pane, cx| {
|
||||
let mut options = SearchOptions::REGEX;
|
||||
|
||||
let Some(search_bar) = pane.toolbar().read(cx).item_of_type::<BufferSearchBar>() else {
|
||||
return;
|
||||
};
|
||||
|
@ -453,7 +455,6 @@ impl Vim {
|
|||
return None;
|
||||
}
|
||||
|
||||
let mut options = SearchOptions::REGEX;
|
||||
if replacement.is_case_sensitive {
|
||||
options.set(SearchOptions::CASE_SENSITIVE, true)
|
||||
}
|
||||
|
@ -468,6 +469,11 @@ impl Vim {
|
|||
search_bar.is_contains_uppercase(&search),
|
||||
);
|
||||
}
|
||||
|
||||
if !replacement.should_replace_all {
|
||||
options.set(SearchOptions::ONE_MATCH_PER_LINE, true);
|
||||
}
|
||||
|
||||
search_bar.set_replacement(Some(&replacement.replacement), cx);
|
||||
Some(search_bar.search(&search, Some(options), window, cx))
|
||||
});
|
||||
|
@ -476,29 +482,35 @@ impl Vim {
|
|||
cx.spawn_in(window, async move |_, cx| {
|
||||
search.await?;
|
||||
search_bar.update_in(cx, |search_bar, window, cx| {
|
||||
if replacement.should_replace_all {
|
||||
search_bar.select_last_match(window, cx);
|
||||
search_bar.replace_all(&Default::default(), window, cx);
|
||||
cx.spawn(async move |_, cx| {
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(200))
|
||||
.await;
|
||||
editor
|
||||
.update(cx, |editor, cx| editor.clear_search_within_ranges(cx))
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
vim.update(cx, |vim, cx| {
|
||||
vim.move_cursor(
|
||||
Motion::StartOfLine {
|
||||
display_lines: false,
|
||||
},
|
||||
None,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
}
|
||||
search_bar.select_last_match(window, cx);
|
||||
search_bar.replace_all(&Default::default(), window, cx);
|
||||
|
||||
cx.spawn(async move |_, cx| {
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(200))
|
||||
.await;
|
||||
editor
|
||||
.update(cx, |editor, cx| editor.clear_search_within_ranges(cx))
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
vim.update(cx, |vim, cx| {
|
||||
vim.move_cursor(
|
||||
Motion::StartOfLine {
|
||||
display_lines: false,
|
||||
},
|
||||
None,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
// Disable the `ONE_MATCH_PER_LINE` search option when finished, as
|
||||
// this is not properly supported outside of vim mode, and
|
||||
// not disabling it makes the "Replace All Matches" button
|
||||
// actually replace only the first match on each line.
|
||||
options.set(SearchOptions::ONE_MATCH_PER_LINE, false);
|
||||
search_bar.set_search_options(options, cx);
|
||||
})?;
|
||||
anyhow::Ok(())
|
||||
})
|
||||
|
@ -564,15 +576,16 @@ impl Replacement {
|
|||
let mut replacement = Replacement {
|
||||
search,
|
||||
replacement,
|
||||
should_replace_all: true,
|
||||
should_replace_all: false,
|
||||
is_case_sensitive: true,
|
||||
};
|
||||
|
||||
for c in flags.chars() {
|
||||
match c {
|
||||
'g' | 'I' => {}
|
||||
'g' => replacement.should_replace_all = true,
|
||||
'c' | 'n' => replacement.should_replace_all = false,
|
||||
'i' => replacement.is_case_sensitive = false,
|
||||
'I' => replacement.is_case_sensitive = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue