Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-term/tests/test/commands.rs')
-rw-r--r--helix-term/tests/test/commands.rs846
1 files changed, 0 insertions, 846 deletions
diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs
deleted file mode 100644
index 90ff4cf0..00000000
--- a/helix-term/tests/test/commands.rs
+++ /dev/null
@@ -1,846 +0,0 @@
-use helix_term::application::Application;
-
-use super::*;
-
-mod insert;
-mod movement;
-mod reverse_selection_contents;
-mod rotate_selection_contents;
-mod write;
-
-#[tokio::test(flavor = "multi_thread")]
-async fn search_selection_detect_word_boundaries_at_eof() -> anyhow::Result<()> {
- // <https://github.com/helix-editor/helix/issues/12609>
- test((
- indoc! {"\
- #[o|]#ne
- two
- three"},
- "gej*h",
- indoc! {"\
- one
- two
- three#[
- |]#"},
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_selection_duplication() -> anyhow::Result<()> {
- // Forward
- test((
- indoc! {"\
- #[lo|]#rem
- ipsum
- dolor
- "},
- "CC",
- indoc! {"\
- #(lo|)#rem
- #(ip|)#sum
- #[do|]#lor
- "},
- ))
- .await?;
-
- // Backward
- test((
- indoc! {"\
- #[|lo]#rem
- ipsum
- dolor
- "},
- "CC",
- indoc! {"\
- #(|lo)#rem
- #(|ip)#sum
- #[|do]#lor
- "},
- ))
- .await?;
-
- // Copy the selection to previous line, skipping the first line in the file
- test((
- indoc! {"\
- test
- #[testitem|]#
- "},
- "<A-C>",
- indoc! {"\
- test
- #[testitem|]#
- "},
- ))
- .await?;
-
- // Copy the selection to previous line, including the first line in the file
- test((
- indoc! {"\
- test
- #[test|]#
- "},
- "<A-C>",
- indoc! {"\
- #[test|]#
- #(test|)#
- "},
- ))
- .await?;
-
- // Copy the selection to next line, skipping the last line in the file
- test((
- indoc! {"\
- #[testitem|]#
- test
- "},
- "C",
- indoc! {"\
- #[testitem|]#
- test
- "},
- ))
- .await?;
-
- // Copy the selection to next line, including the last line in the file
- test((
- indoc! {"\
- #[test|]#
- test
- "},
- "C",
- indoc! {"\
- #(test|)#
- #[test|]#
- "},
- ))
- .await?;
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_goto_file_impl() -> anyhow::Result<()> {
- let file = tempfile::NamedTempFile::new()?;
-
- fn match_paths(app: &Application, matches: Vec<&str>) -> usize {
- app.editor
- .documents()
- .filter_map(|d| d.path()?.file_name())
- .filter(|n| matches.iter().any(|m| *m == n.to_string_lossy()))
- .count()
- }
-
- // Single selection
- test_key_sequence(
- &mut AppBuilder::new().with_file(file.path(), None).build()?,
- Some("ione.js<esc>%gf"),
- Some(&|app| {
- assert_eq!(1, match_paths(app, vec!["one.js"]));
- }),
- false,
- )
- .await?;
-
- // Multiple selection
- test_key_sequence(
- &mut AppBuilder::new().with_file(file.path(), None).build()?,
- Some("ione.js<ret>two.js<esc>%<A-s>gf"),
- Some(&|app| {
- assert_eq!(2, match_paths(app, vec!["one.js", "two.js"]));
- }),
- false,
- )
- .await?;
-
- // Cursor on first quote
- test_key_sequence(
- &mut AppBuilder::new().with_file(file.path(), None).build()?,
- Some("iimport 'one.js'<esc>B;gf"),
- Some(&|app| {
- assert_eq!(1, match_paths(app, vec!["one.js"]));
- }),
- false,
- )
- .await?;
-
- // Cursor on last quote
- test_key_sequence(
- &mut AppBuilder::new().with_file(file.path(), None).build()?,
- Some("iimport 'one.js'<esc>bgf"),
- Some(&|app| {
- assert_eq!(1, match_paths(app, vec!["one.js"]));
- }),
- false,
- )
- .await?;
-
- // ';' is behind the path
- test_key_sequence(
- &mut AppBuilder::new().with_file(file.path(), None).build()?,
- Some("iimport 'one.js';<esc>B;gf"),
- Some(&|app| {
- assert_eq!(1, match_paths(app, vec!["one.js"]));
- }),
- false,
- )
- .await?;
-
- // allow numeric values in path
- test_key_sequence(
- &mut AppBuilder::new().with_file(file.path(), None).build()?,
- Some("iimport 'one123.js'<esc>B;gf"),
- Some(&|app| {
- assert_eq!(1, match_paths(app, vec!["one123.js"]));
- }),
- false,
- )
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_multi_selection_paste() -> anyhow::Result<()> {
- test((
- indoc! {"\
- #[|lorem]#
- #(|ipsum)#
- #(|dolor)#
- "},
- "yp",
- indoc! {"\
- lorem#[|lorem]#
- ipsum#(|ipsum)#
- dolor#(|dolor)#
- "},
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_multi_selection_shell_commands() -> anyhow::Result<()> {
- // pipe
- test((
- indoc! {"\
- #[|lorem]#
- #(|ipsum)#
- #(|dolor)#
- "},
- "|echo foo<ret>",
- indoc! {"\
- #[|foo]#
- #(|foo)#
- #(|foo)#"
- },
- ))
- .await?;
-
- // insert-output
- test((
- indoc! {"\
- #[|lorem]#
- #(|ipsum)#
- #(|dolor)#
- "},
- "!echo foo<ret>",
- indoc! {"\
- #[|foo]#lorem
- #(|foo)#ipsum
- #(|foo)#dolor
- "},
- ))
- .await?;
-
- // append-output
- test((
- indoc! {"\
- #[|lorem]#
- #(|ipsum)#
- #(|dolor)#
- "},
- "<A-!>echo foo<ret>",
- indoc! {"\
- lorem#[|foo]#
- ipsum#(|foo)#
- dolor#(|foo)#
- "},
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_undo_redo() -> anyhow::Result<()> {
- // A jumplist selection is created at a point which is undone.
- //
- // * 2[<space> Add two newlines at line start. We're now on line 3.
- // * <C-s> Save the selection on line 3 in the jumplist.
- // * u Undo the two newlines. We're now on line 1.
- // * <C-o><C-i> Jump forward an back again in the jumplist. This would panic
- // if the jumplist were not being updated correctly.
- test((
- "#[|]#",
- "2[<space><C-s>u<C-o><C-i>",
- "#[|]#",
- LineFeedHandling::AsIs,
- ))
- .await?;
-
- // A jumplist selection is passed through an edit and then an undo and then a redo.
- //
- // * [<space> Add a newline at line start. We're now on line 2.
- // * <C-s> Save the selection on line 2 in the jumplist.
- // * kd Delete line 1. The jumplist selection should be adjusted to the new line 1.
- // * uU Undo and redo the `kd` edit.
- // * <C-o> Jump back in the jumplist. This would panic if the jumplist were not being
- // updated correctly.
- // * <C-i> Jump forward to line 1.
- test((
- "#[|]#",
- "[<space><C-s>kduU<C-o><C-i>",
- "#[|]#",
- LineFeedHandling::AsIs,
- ))
- .await?;
-
- // In this case we 'redo' manually to ensure that the transactions are composing correctly.
- test((
- "#[|]#",
- "[<space>u[<space>u",
- "#[|]#",
- LineFeedHandling::AsIs,
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_extend_line() -> anyhow::Result<()> {
- // extend with line selected then count
- test((
- indoc! {"\
- #[l|]#orem
- ipsum
- dolor
-
- "},
- "x2x",
- indoc! {"\
- #[lorem
- ipsum
- dolor\n|]#
-
- "},
- ))
- .await?;
-
- // extend with count on partial selection
- test((
- indoc! {"\
- #[l|]#orem
- ipsum
-
- "},
- "2x",
- indoc! {"\
- #[lorem
- ipsum\n|]#
-
- "},
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_character_info() -> anyhow::Result<()> {
- // UTF-8, single byte
- test_key_sequence(
- &mut helpers::AppBuilder::new().build()?,
- Some("ih<esc>h:char<ret>"),
- Some(&|app| {
- assert_eq!(
- r#""h" (U+0068) Dec 104 Hex 68"#,
- app.editor.get_status().unwrap().0
- );
- }),
- false,
- )
- .await?;
-
- // UTF-8, multi-byte
- test_key_sequence(
- &mut helpers::AppBuilder::new().build()?,
- Some("ië<esc>h:char<ret>"),
- Some(&|app| {
- assert_eq!(
- r#""ë" (U+0065 U+0308) Hex 65 + cc 88"#,
- app.editor.get_status().unwrap().0
- );
- }),
- false,
- )
- .await?;
-
- // Multiple characters displayed as one, escaped characters
- test_key_sequence(
- &mut helpers::AppBuilder::new().build()?,
- Some(":line<minus>ending crlf<ret>:char<ret>"),
- Some(&|app| {
- assert_eq!(
- r#""\r\n" (U+000d U+000a) Hex 0d + 0a"#,
- app.editor.get_status().unwrap().0
- );
- }),
- false,
- )
- .await?;
-
- // Non-UTF-8
- test_key_sequence(
- &mut helpers::AppBuilder::new().build()?,
- Some(":encoding ascii<ret>ih<esc>h:char<ret>"),
- Some(&|app| {
- assert_eq!(r#""h" Dec 104 Hex 68"#, app.editor.get_status().unwrap().0);
- }),
- false,
- )
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_delete_char_backward() -> anyhow::Result<()> {
- // don't panic when deleting overlapping ranges
- test(("#(x|)# #[x|]#", "c<space><backspace><esc>", "#[\n|]#")).await?;
- test((
- "#( |)##( |)#a#( |)#axx#[x|]#a",
- "li<backspace><esc>",
- "#(a|)##(|a)#xx#[|a]#",
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_delete_word_backward() -> anyhow::Result<()> {
- // don't panic when deleting overlapping ranges
- test(("fo#[o|]#ba#(r|)#", "a<C-w><esc>", "#[\n|]#")).await?;
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_delete_word_forward() -> anyhow::Result<()> {
- // don't panic when deleting overlapping ranges
- test(("fo#[o|]#b#(|ar)#", "i<A-d><esc>", "fo#[\n|]#")).await?;
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_delete_char_forward() -> anyhow::Result<()> {
- test((
- indoc! {"\
- #[abc|]#def
- #(abc|)#ef
- #(abc|)#f
- #(abc|)#
- "},
- "a<del><esc>",
- indoc! {"\
- #[abc|]#ef
- #(abc|)#f
- #(abc|)#
- #(abc|)#
- "},
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_insert_with_indent() -> anyhow::Result<()> {
- const INPUT: &str = indoc! { "
- #[f|]#n foo() {
- if let Some(_) = None {
-
- }
-
- }
-
- fn bar() {
-
- }
- "
- };
-
- // insert_at_line_start
- test((
- INPUT,
- ":lang rust<ret>%<A-s>I",
- indoc! { "
- #[f|]#n foo() {
- #(i|)#f let Some(_) = None {
- #(\n|)#
- #(}|)#
- #( |)#
- #(}|)#
- #(\n|)#
- #(f|)#n bar() {
- #(\n|)#
- #(}|)#
- "
- },
- ))
- .await?;
-
- // insert_at_line_end
- test((
- INPUT,
- ":lang rust<ret>%<A-s>A",
- indoc! { "
- fn foo() {#[\n|]#
- if let Some(_) = None {#(\n|)#
- #(\n|)#
- }#(\n|)#
- #(\n|)#
- }#(\n|)#
- #(\n|)#
- fn bar() {#(\n|)#
- #(\n|)#
- }#(\n|)#
- "
- },
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_join_selections() -> anyhow::Result<()> {
- // normal join
- test((
- indoc! {"\
- #[a|]#bc
- def
- "},
- "J",
- indoc! {"\
- #[a|]#bc def
- "},
- ))
- .await?;
-
- // join with empty line
- test((
- indoc! {"\
- #[a|]#bc
-
- def
- "},
- "JJ",
- indoc! {"\
- #[a|]#bc def
- "},
- ))
- .await?;
-
- // join with additional space in non-empty line
- test((
- indoc! {"\
- #[a|]#bc
-
- def
- "},
- "JJ",
- indoc! {"\
- #[a|]#bc def
- "},
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_join_selections_space() -> anyhow::Result<()> {
- // join with empty lines panic
- test((
- indoc! {"\
- #[a
-
- b
-
- c
-
- d
-
- e|]#
- "},
- "<A-J>",
- indoc! {"\
- a#[ |]#b#( |)#c#( |)#d#( |)#e
- "},
- ))
- .await?;
-
- // normal join
- test((
- indoc! {"\
- #[a|]#bc
- def
- "},
- "<A-J>",
- indoc! {"\
- abc#[ |]#def
- "},
- ))
- .await?;
-
- // join with empty line
- test((
- indoc! {"\
- #[a|]#bc
-
- def
- "},
- "<A-J>",
- indoc! {"\
- #[a|]#bc
- def
- "},
- ))
- .await?;
-
- // join with additional space in non-empty line
- test((
- indoc! {"\
- #[a|]#bc
-
- def
- "},
- "<A-J><A-J>",
- indoc! {"\
- abc#[ |]#def
- "},
- ))
- .await?;
-
- // join with retained trailing spaces
- test((
- indoc! {"\
- #[aaa
-
- bb
-
- c |]#
- "},
- "<A-J>",
- indoc! {"\
- aaa #[ |]#bb #( |)#c
- "},
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_join_selections_comment() -> anyhow::Result<()> {
- test((
- indoc! {"\
- /// #[a|]#bc
- /// def
- "},
- ":lang rust<ret>J",
- indoc! {"\
- /// #[a|]#bc def
- "},
- ))
- .await?;
-
- // Only join if the comment token matches the previous line.
- test((
- indoc! {"\
- #[| // a
- // b
- /// c
- /// d
- e
- /// f
- // g]#
- "},
- ":lang rust<ret>J",
- indoc! {"\
- #[| // a b /// c d e f // g]#
- "},
- ))
- .await?;
-
- test((
- "#[|\t// Join comments
-\t// with indent]#",
- ":lang go<ret>J",
- "#[|\t// Join comments with indent]#",
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn test_read_file() -> anyhow::Result<()> {
- let mut file = tempfile::NamedTempFile::new()?;
- let contents_to_read = "some contents";
- let output_file = helpers::temp_file_with_contents(contents_to_read)?;
-
- test_key_sequence(
- &mut helpers::AppBuilder::new()
- .with_file(file.path(), None)
- .build()?,
- Some(&format!(":r {:?}<ret><esc>:w<ret>", output_file.path())),
- Some(&|app| {
- assert!(!app.editor.is_err(), "error: {:?}", app.editor.get_status());
- }),
- false,
- )
- .await?;
-
- let expected_contents = LineFeedHandling::Native.apply(contents_to_read);
- helpers::assert_file_has_content(&mut file, &expected_contents)?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn surround_delete() -> anyhow::Result<()> {
- // Test `surround_delete` when head < anchor
- test(("(#[| ]#)", "mdm", "#[| ]#")).await?;
- test(("(#[| ]#)", "md(", "#[| ]#")).await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn surround_replace_ts() -> anyhow::Result<()> {
- const INPUT: &str = r#"\
-fn foo() {
- if let Some(_) = None {
- testing!("f#[|o]#o)");
- }
-}
-"#;
- test((
- INPUT,
- ":lang rust<ret>mrm'",
- r#"\
-fn foo() {
- if let Some(_) = None {
- testing!('f#[|o]#o)');
- }
-}
-"#,
- ))
- .await?;
-
- test((
- INPUT,
- ":lang rust<ret>3mrm[",
- r#"\
-fn foo() {
- if let Some(_) = None [
- testing!("f#[|o]#o)");
- ]
-}
-"#,
- ))
- .await?;
-
- test((
- INPUT,
- ":lang rust<ret>2mrm{",
- r#"\
-fn foo() {
- if let Some(_) = None {
- testing!{"f#[|o]#o)"};
- }
-}
-"#,
- ))
- .await?;
-
- test((
- indoc! {"\
- #[a
- b
- c
- d
- e|]#
- f
- "},
- "s\\n<ret>r,",
- "a#[,|]#b#(,|)#c#(,|)#d#(,|)#e\nf\n",
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn macro_play_within_macro_record() -> anyhow::Result<()> {
- // <https://github.com/helix-editor/helix/issues/12697>
- //
- // * `"aQihello<esc>Q` record a macro to register 'a' which inserts "hello"
- // * `Q"aq<space>world<esc>Q` record a macro to the default macro register which plays the
- // macro in register 'a' and then inserts " world"
- // * `%d` clear the buffer
- // * `q` replay the macro in the default macro register
- // * `i<ret>` add a newline at the end
- //
- // The inner macro in register 'a' should replay within the outer macro exactly once to insert
- // "hello world".
- test((
- indoc! {"\
- #[|]#
- "},
- r#""aQihello<esc>QQ"aqi<space>world<esc>Q%dqi<ret>"#,
- indoc! {"\
- hello world
- #[|]#"},
- ))
- .await?;
-
- Ok(())
-}
-
-#[tokio::test(flavor = "multi_thread")]
-async fn global_search_with_multibyte_chars() -> anyhow::Result<()> {
- // Assert that `helix_term::commands::global_search` handles multibyte characters correctly.
- test((
- indoc! {"\
- // Hello world!
- // #[|
- ]#
- "},
- // start global search
- " /«十分に長い マルチバイトキャラクター列» で検索<ret><esc>",
- indoc! {"\
- // Hello world!
- // #[|
- ]#
- "},
- ))
- .await?;
-
- Ok(())
-}