mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-25 19:03:30 +04:00
Compare commits
7 Commits
03bd4445c1
...
827e6eb2d6
Author | SHA1 | Date | |
---|---|---|---|
|
827e6eb2d6 | ||
|
f305c7299d | ||
|
9e0d2d0a19 | ||
|
109ede2e4b | ||
|
fa552f1c47 | ||
|
b917595e9b | ||
|
428c5c74fd |
@ -3,6 +3,7 @@
|
||||
| ada | ✓ | ✓ | | `ada_language_server` |
|
||||
| adl | ✓ | ✓ | ✓ | |
|
||||
| agda | ✓ | | | |
|
||||
| amber | ✓ | | | |
|
||||
| astro | ✓ | | | |
|
||||
| awk | ✓ | ✓ | | `awk-language-server` |
|
||||
| bash | ✓ | ✓ | ✓ | `bash-language-server` |
|
||||
|
@ -160,7 +160,7 @@ ### Search
|
||||
| `?` | Search for previous pattern | `rsearch` |
|
||||
| `n` | Select next search match | `search_next` |
|
||||
| `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
|
||||
|
||||
|
@ -2266,19 +2266,37 @@ fn extend_search_prev(cx: &mut Context) {
|
||||
|
||||
fn search_selection(cx: &mut Context) {
|
||||
let register = cx.register.unwrap_or('/');
|
||||
let count = cx.count();
|
||||
let (view, doc) = current!(cx.editor);
|
||||
let contents = doc.text().slice(..);
|
||||
|
||||
let regex = doc
|
||||
.selection(view.id)
|
||||
// Checks whether there is only one selection with a width of 1
|
||||
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()
|
||||
.map(|selection| regex::escape(&selection.fragment(contents)))
|
||||
.collect::<HashSet<_>>() // Collect into hashset to deduplicate identical regexes
|
||||
.into_iter()
|
||||
.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) {
|
||||
Ok(_) => {
|
||||
cx.editor.registers.last_search_register = register;
|
||||
|
@ -178,6 +178,56 @@ fn match_paths(app: &Application, matches: Vec<&str>) -> usize {
|
||||
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")]
|
||||
async fn test_multi_selection_paste() -> anyhow::Result<()> {
|
||||
test((
|
||||
|
@ -3931,3 +3931,14 @@ indent = { tab-width = 4, unit = " " }
|
||||
[[grammar]]
|
||||
name = "spade"
|
||||
source = { git = "https://gitlab.com/spade-lang/tree-sitter-spade/", rev = "4d5b141017c61fe7e168e0a5c5721ee62b0d9572" }
|
||||
|
||||
[[language]]
|
||||
name = "amber"
|
||||
scope = "source.ab"
|
||||
file-types = ["ab"]
|
||||
comment-token = "//"
|
||||
indent = { tab-width = 4, unit = " " }
|
||||
|
||||
[[grammar]]
|
||||
name = "amber"
|
||||
source = { git = "https://github.com/amber-lang/tree-sitter-amber", rev = "c6df3ec2ec243ed76550c525e7ac3d9a10c6c814" }
|
||||
|
60
runtime/queries/amber/highlights.scm
Normal file
60
runtime/queries/amber/highlights.scm
Normal file
@ -0,0 +1,60 @@
|
||||
(comment) @comment
|
||||
|
||||
[
|
||||
"if"
|
||||
"loop"
|
||||
"for"
|
||||
"return"
|
||||
"fun"
|
||||
"else"
|
||||
"then"
|
||||
"break"
|
||||
"continue"
|
||||
"and"
|
||||
"or"
|
||||
"not"
|
||||
"let"
|
||||
"pub"
|
||||
"main"
|
||||
"echo"
|
||||
"exit"
|
||||
"fun"
|
||||
"import"
|
||||
"from"
|
||||
"as"
|
||||
"in"
|
||||
"fail"
|
||||
"failed"
|
||||
"silent"
|
||||
"nameof"
|
||||
"is"
|
||||
"unsafe"
|
||||
"trust"
|
||||
] @keyword
|
||||
|
||||
; Literals
|
||||
(boolean) @constant.builtin.boolean
|
||||
(number) @constant.numeric
|
||||
(null) @constant.numeric
|
||||
(string) @string
|
||||
(status) @keyword
|
||||
(command) @string
|
||||
(handler) @keyword
|
||||
(block) @punctuation.delimiter
|
||||
(variable_init) @keyword
|
||||
(variable_assignment) @punctuation.delimiter
|
||||
(variable) @variable
|
||||
(escape_sequence) @constant.character.escape
|
||||
(type_name_symbol) @type
|
||||
(interpolation) @punctuation.delimiter
|
||||
(reference) @keyword
|
||||
(preprocessor_directive) @comment
|
||||
(shebang) @comment
|
||||
(function_definition
|
||||
name: (variable) @function.method)
|
||||
(function_call
|
||||
name: (variable) @function.method)
|
||||
(import_statement
|
||||
"pub" @keyword
|
||||
"import" @keyword
|
||||
"from" @keyword)
|
@ -12,6 +12,8 @@
|
||||
(unicode_string_literal)
|
||||
(yul_string_literal)
|
||||
] @string
|
||||
(hex_string_literal "hex" @string.special.symbol)
|
||||
(unicode_string_literal "unicode" @string.special.symbol)
|
||||
[
|
||||
(number_literal)
|
||||
(yul_decimal_number)
|
||||
@ -20,6 +22,7 @@
|
||||
[
|
||||
(true)
|
||||
(false)
|
||||
(yul_boolean)
|
||||
] @constant.builtin.boolean
|
||||
|
||||
(comment) @comment
|
||||
|
Loading…
Reference in New Issue
Block a user