mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-22 09:26:19 +04:00
Merge 109ede2e4b
into b8313da5a8
This commit is contained in:
commit
03bd4445c1
@ -160,7 +160,7 @@ ### Search
|
|||||||
| `?` | Search for previous pattern | `rsearch` |
|
| `?` | Search for previous pattern | `rsearch` |
|
||||||
| `n` | Select next search match | `search_next` |
|
| `n` | Select next search match | `search_next` |
|
||||||
| `N` | Select previous search match | `search_prev` |
|
| `N` | Select previous search match | `search_prev` |
|
||||||
| `*` | Use current selection as the search pattern | `search_selection` |
|
| `*` | Use current selection as the search pattern, if only a single char is selected the current word (miW) is used instead | `search_selection` |
|
||||||
|
|
||||||
### Minor modes
|
### Minor modes
|
||||||
|
|
||||||
|
@ -2266,19 +2266,37 @@ fn extend_search_prev(cx: &mut Context) {
|
|||||||
|
|
||||||
fn search_selection(cx: &mut Context) {
|
fn search_selection(cx: &mut Context) {
|
||||||
let register = cx.register.unwrap_or('/');
|
let register = cx.register.unwrap_or('/');
|
||||||
|
let count = cx.count();
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
let contents = doc.text().slice(..);
|
let contents = doc.text().slice(..);
|
||||||
|
|
||||||
let regex = doc
|
// Checks whether there is only one selection with a width of 1
|
||||||
.selection(view.id)
|
let selections = doc.selection(view.id);
|
||||||
|
let primary = selections.primary();
|
||||||
|
let regex = if selections.len() == 1 && primary.len() == 1 {
|
||||||
|
let text = doc.text();
|
||||||
|
let text_slice = text.slice(..);
|
||||||
|
// In this case select the WORD under the cursor
|
||||||
|
let current_word = textobject::textobject_word(
|
||||||
|
text_slice,
|
||||||
|
primary,
|
||||||
|
textobject::TextObject::Inside,
|
||||||
|
count,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
let text_to_search = current_word.fragment(text_slice).to_string();
|
||||||
|
regex::escape(&text_to_search)
|
||||||
|
} else {
|
||||||
|
selections
|
||||||
.iter()
|
.iter()
|
||||||
.map(|selection| regex::escape(&selection.fragment(contents)))
|
.map(|selection| regex::escape(&selection.fragment(contents)))
|
||||||
.collect::<HashSet<_>>() // Collect into hashset to deduplicate identical regexes
|
.collect::<HashSet<_>>() // Collect into hashset to deduplicate identical regexes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("|");
|
.join("|")
|
||||||
|
};
|
||||||
|
|
||||||
let msg = format!("register '{}' set to '{}'", register, ®ex);
|
let msg = format!("register '{}' set to '{}'", '/', ®ex);
|
||||||
match cx.editor.registers.push(register, regex) {
|
match cx.editor.registers.push(register, regex) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
cx.editor.registers.last_search_register = register;
|
cx.editor.registers.last_search_register = register;
|
||||||
|
@ -178,6 +178,56 @@ fn match_paths(app: &Application, matches: Vec<&str>) -> usize {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn test_search_selection() -> anyhow::Result<()> {
|
||||||
|
// Single selection with a length of 1: search for the whole word
|
||||||
|
test_key_sequence(
|
||||||
|
&mut helpers::AppBuilder::new().build()?,
|
||||||
|
Some("ifoobar::baz<esc>3bl*"), // 3b places the cursor on the first letter of 'foobar', then move one to the right for good measure
|
||||||
|
Some(&|app| {
|
||||||
|
assert!(
|
||||||
|
r#"register '/' set to 'foobar'"# == app.editor.get_status().unwrap().0
|
||||||
|
&& Some(&"foobar".to_string()) == app.editor.registers.first('/')
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Single selection with a length greather than 1: only search for the selection
|
||||||
|
test_key_sequence(
|
||||||
|
&mut helpers::AppBuilder::new().build()?,
|
||||||
|
Some("ifoobar::baz<esc>3blvll*"), // 3b places the cursor on the first letter of 'foobar', then move one to the right for good measure, then select two more chars for a total of three
|
||||||
|
Some(&|app| {
|
||||||
|
assert!(
|
||||||
|
r#"register '/' set to 'oob'"# == app.editor.get_status().unwrap().0
|
||||||
|
&& Some(&"oob".to_string()) == app.editor.registers.first('/')
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// Multiple selection of length 1 each : should still only search for the selection
|
||||||
|
test_key_sequence(
|
||||||
|
&mut helpers::AppBuilder::new().build()?,
|
||||||
|
Some("ifoobar::baz<ret>bar::crux<esc>k3blC*"), // k3b places the cursor on the first letter of 'foobar', then move one to the right for good measure, then adds a cursor on the line below
|
||||||
|
Some(&|app| {
|
||||||
|
assert!(
|
||||||
|
// The selections don't seem to be ordered, so we have to test for the two possible orders.
|
||||||
|
(r#"register '/' set to 'o|a'"# == app.editor.get_status().unwrap().0
|
||||||
|
|| r#"register '/' set to 'a|o'"# == app.editor.get_status().unwrap().0)
|
||||||
|
&& (Some(&"o|a".to_string()) == app.editor.registers.first('/')
|
||||||
|
|| Some(&"a|o".to_string()) == app.editor.registers.first('/'))
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn test_multi_selection_paste() -> anyhow::Result<()> {
|
async fn test_multi_selection_paste() -> anyhow::Result<()> {
|
||||||
test((
|
test((
|
||||||
|
Loading…
Reference in New Issue
Block a user