diff options
Diffstat (limited to 'helix-term')
-rw-r--r-- | helix-term/src/commands.rs | 2 | ||||
-rw-r--r-- | helix-term/tests/test/movement.rs | 301 |
2 files changed, 302 insertions, 1 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 38a62364..f8a96074 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -4791,7 +4791,7 @@ fn select_textobject(cx: &mut Context, objtype: textobject::TextObject) { ("a", "Argument/parameter (tree-sitter)"), ("c", "Comment (tree-sitter)"), ("T", "Test (tree-sitter)"), - ("m", "Closest surrounding pair to cursor"), + ("m", "Closest surrounding pair"), (" ", "... or any character acting as a pair"), ]; diff --git a/helix-term/tests/test/movement.rs b/helix-term/tests/test/movement.rs index fedf4b0e..e6ea3f95 100644 --- a/helix-term/tests/test/movement.rs +++ b/helix-term/tests/test/movement.rs @@ -64,6 +64,307 @@ async fn insert_to_normal_mode_cursor_position() -> anyhow::Result<()> { Ok(()) } +#[tokio::test(flavor = "multi_thread")] +async fn surround_by_character() -> anyhow::Result<()> { + // Only pairs matching the passed character count + test(( + "(so [many {go#[o|]#d} text] here)", + "mi{", + "(so [many {#[good|]#} text] here)", + )) + .await?; + test(( + "(so [many {go#[o|]#d} text] here)", + "mi[", + "(so [#[many {good} text|]#] here)", + )) + .await?; + test(( + "(so [many {go#[o|]#d} text] here)", + "mi(", + "(#[so [many {good} text] here|]#)", + )) + .await?; + + // Works with characters that aren't pairs too + test(( + "'so 'many 'go#[o|]#d' text' here'", + "mi'", + "'so 'many '#[good|]#' text' here'", + )) + .await?; + test(( + "'so 'many 'go#[o|]#d' text' here'", + "2mi'", + "'so '#[many 'good' text|]#' here'", + )) + .await?; + test(( + "'so \"many 'go#[o|]#d' text\" here'", + "mi\"", + "'so \"#[many 'good' text|]#\" here'", + )) + .await?; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn surround_inside_pair() -> anyhow::Result<()> { + // Works at first character of buffer + // TODO: Adjust test when opening pair failure is fixed + test(("#[(|]#something)", "mim", "#[(|]#something)")).await?; + + // Inside a valid pair selects pair + test(("some (#[t|]#ext) here", "mim", "some (#[text|]#) here")).await?; + + // On pair character selects pair + // TODO: Opening pair character is a known failure case that needs addressing + // test(("some #[(|]#text) here", "mim", "some (#[text|]#) here")).await?; + test(("some (text#[)|]# here", "mim", "some (#[text|]#) here")).await?; + + // No valid pair does nothing + test(("so#[m|]#e (text) here", "mim", "so#[m|]#e (text) here")).await?; + + // Count skips to outer pairs + test(( + "(so (many (go#[o|]#d) text) here)", + "1mim", + "(so (many (#[good|]#) text) here)", + )) + .await?; + test(( + "(so (many (go#[o|]#d) text) here)", + "2mim", + "(so (#[many (good) text|]#) here)", + )) + .await?; + test(( + "(so (many (go#[o|]#d) text) here)", + "3mim", + "(#[so (many (good) text) here|]#)", + )) + .await?; + + // Matching pairs outside selection don't match + test(( + "((so)((many) go#[o|]#d (text))(here))", + "mim", + "((so)(#[(many) good (text)|]#)(here))", + )) + .await?; + test(( + "((so)((many) go#[o|]#d (text))(here))", + "2mim", + "(#[(so)((many) good (text))(here)|]#)", + )) + .await?; + + // Works with mixed braces + test(( + "(so [many {go#[o|]#d} text] here)", + "mim", + "(so [many {#[good|]#} text] here)", + )) + .await?; + test(( + "(so [many {go#[o|]#d} text] here)", + "2mim", + "(so [#[many {good} text|]#] here)", + )) + .await?; + test(( + "(so [many {go#[o|]#d} text] here)", + "3mim", + "(#[so [many {good} text] here|]#)", + )) + .await?; + + // Selection direction is preserved + test(( + "(so [many {go#[|od]#} text] here)", + "mim", + "(so [many {#[|good]#} text] here)", + )) + .await?; + test(( + "(so [many {go#[|od]#} text] here)", + "2mim", + "(so [#[|many {good} text]#] here)", + )) + .await?; + test(( + "(so [many {go#[|od]#} text] here)", + "3mim", + "(#[|so [many {good} text] here]#)", + )) + .await?; + + // Only pairs outside of full selection range are considered + test(( + "(so (many (go#[od) |]#text) here)", + "mim", + "(so (#[many (good) text|]#) here)", + )) + .await?; + test(( + "(so (many#[ (go|]#od) text) here)", + "mim", + "(so (#[many (good) text|]#) here)", + )) + .await?; + test(( + "(so#[ (many (go|]#od) text) here)", + "mim", + "(#[so (many (good) text) here|]#)", + )) + .await?; + test(( + "(so (many (go#[od) text) |]#here)", + "mim", + "(#[so (many (good) text) here|]#)", + )) + .await?; + + // Works with multiple cursors + test(( + "(so (many (good) text) #[he|]#re\nso (many (good) text) #(|he)#re)", + "mim", + "(#[so (many (good) text) here\nso (many (good) text) here|]#)", + )) + .await?; + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn surround_around_pair() -> anyhow::Result<()> { + // Works at first character of buffer + // TODO: Adjust test when opening pair failure is fixed + test(("#[(|]#something)", "mam", "#[(|]#something)")).await?; + + // Inside a valid pair selects pair + test(("some (#[t|]#ext) here", "mam", "some #[(text)|]# here")).await?; + + // On pair character selects pair + // TODO: Opening pair character is a known failure case that needs addressing + // test(("some #[(|]#text) here", "mam", "some #[(text)|]# here")).await?; + test(("some (text#[)|]# here", "mam", "some #[(text)|]# here")).await?; + + // No valid pair does nothing + test(("so#[m|]#e (text) here", "mam", "so#[m|]#e (text) here")).await?; + + // Count skips to outer pairs + test(( + "(so (many (go#[o|]#d) text) here)", + "1mam", + "(so (many #[(good)|]# text) here)", + )) + .await?; + test(( + "(so (many (go#[o|]#d) text) here)", + "2mam", + "(so #[(many (good) text)|]# here)", + )) + .await?; + test(( + "(so (many (go#[o|]#d) text) here)", + "3mam", + "#[(so (many (good) text) here)|]#", + )) + .await?; + + // Matching pairs outside selection don't match + test(( + "((so)((many) go#[o|]#d (text))(here))", + "mam", + "((so)#[((many) good (text))|]#(here))", + )) + .await?; + test(( + "((so)((many) go#[o|]#d (text))(here))", + "2mam", + "#[((so)((many) good (text))(here))|]#", + )) + .await?; + + // Works with mixed braces + test(( + "(so [many {go#[o|]#d} text] here)", + "mam", + "(so [many #[{good}|]# text] here)", + )) + .await?; + test(( + "(so [many {go#[o|]#d} text] here)", + "2mam", + "(so #[[many {good} text]|]# here)", + )) + .await?; + test(( + "(so [many {go#[o|]#d} text] here)", + "3mam", + "#[(so [many {good} text] here)|]#", + )) + .await?; + + // Selection direction is preserved + test(( + "(so [many {go#[|od]#} text] here)", + "mam", + "(so [many #[|{good}]# text] here)", + )) + .await?; + test(( + "(so [many {go#[|od]#} text] here)", + "2mam", + "(so #[|[many {good} text]]# here)", + )) + .await?; + test(( + "(so [many {go#[|od]#} text] here)", + "3mam", + "#[|(so [many {good} text] here)]#", + )) + .await?; + + // Only pairs outside of full selection range are considered + test(( + "(so (many (go#[od) |]#text) here)", + "mam", + "(so #[(many (good) text)|]# here)", + )) + .await?; + test(( + "(so (many#[ (go|]#od) text) here)", + "mam", + "(so #[(many (good) text)|]# here)", + )) + .await?; + test(( + "(so#[ (many (go|]#od) text) here)", + "mam", + "#[(so (many (good) text) here)|]#", + )) + .await?; + test(( + "(so (many (go#[od) text) |]#here)", + "mam", + "#[(so (many (good) text) here)|]#", + )) + .await?; + + // Works with multiple cursors + test(( + "(so (many (good) text) #[he|]#re\nso (many (good) text) #(|he)#re)", + "mam", + "#[(so (many (good) text) here\nso (many (good) text) here)|]#", + )) + .await?; + + Ok(()) +} + /// Ensure the very initial cursor in an opened file is the width of /// the first grapheme #[tokio::test(flavor = "multi_thread")] |