helix-mods/helix-term/tests/test/commands.rs
Michael Davis 48a3965ab4
Fix range offsets in multi-selection paste (#4608)
* Fix range offsets in multi-selection paste

d6323b7cbc introduced a regression with
multi-selection paste where pasting would not adjust the ranges
correctly. To fix it, we need to track the total number of characters
inserted in each changed selection and use that offset to slide each
new range forwards.

* Inherit selection directions on paste

* Add an integration-test for multi-selection pasting
2022-11-06 23:56:45 +09:00

217 lines
5.4 KiB
Rust

use std::ops::RangeInclusive;
use helix_core::diagnostic::Severity;
use helix_term::application::Application;
use super::*;
#[tokio::test(flavor = "multi_thread")]
async fn test_write_quit_fail() -> anyhow::Result<()> {
let file = helpers::new_readonly_tempfile()?;
let mut app = helpers::AppBuilder::new()
.with_file(file.path(), None)
.build()?;
test_key_sequence(
&mut app,
Some("ihello<esc>:wq<ret>"),
Some(&|app| {
let mut docs: Vec<_> = app.editor.documents().collect();
assert_eq!(1, docs.len());
let doc = docs.pop().unwrap();
assert_eq!(Some(file.path()), doc.path().map(PathBuf::as_path));
assert_eq!(&Severity::Error, app.editor.get_status().unwrap().1);
}),
false,
)
.await?;
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn test_buffer_close_concurrent() -> anyhow::Result<()> {
test_key_sequences(
&mut helpers::AppBuilder::new().build()?,
vec![
(
None,
Some(&|app| {
assert_eq!(1, app.editor.documents().count());
assert!(!app.editor.is_err());
}),
),
(
Some("ihello<esc>:new<ret>"),
Some(&|app| {
assert_eq!(2, app.editor.documents().count());
assert!(!app.editor.is_err());
}),
),
(
Some(":buffer<minus>close<ret>"),
Some(&|app| {
assert_eq!(1, app.editor.documents().count());
assert!(!app.editor.is_err());
}),
),
],
false,
)
.await?;
// verify if writes are queued up, it finishes them before closing the buffer
let mut file = tempfile::NamedTempFile::new()?;
let mut command = String::new();
const RANGE: RangeInclusive<i32> = 1..=1000;
for i in RANGE {
let cmd = format!("%c{}<esc>:w<ret>", i);
command.push_str(&cmd);
}
command.push_str(":buffer<minus>close<ret>");
let mut app = helpers::AppBuilder::new()
.with_file(file.path(), None)
.build()?;
test_key_sequence(
&mut app,
Some(&command),
Some(&|app| {
assert!(!app.editor.is_err(), "error: {:?}", app.editor.get_status());
let doc = app.editor.document_by_path(file.path());
assert!(doc.is_none(), "found doc: {:?}", doc);
}),
false,
)
.await?;
helpers::assert_file_has_content(file.as_file_mut(), &RANGE.end().to_string())?;
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn test_selection_duplication() -> anyhow::Result<()> {
// Forward
test((
platform_line(indoc! {"\
#[lo|]#rem
ipsum
dolor
"})
.as_str(),
"CC",
platform_line(indoc! {"\
#(lo|)#rem
#(ip|)#sum
#[do|]#lor
"})
.as_str(),
))
.await?;
// Backward
test((
platform_line(indoc! {"\
#[|lo]#rem
ipsum
dolor
"})
.as_str(),
"CC",
platform_line(indoc! {"\
#(|lo)#rem
#(|ip)#sum
#[|do]#lor
"})
.as_str(),
))
.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?;
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn test_multi_selection_paste() -> anyhow::Result<()> {
test((
platform_line(indoc! {"\
#[|lorem]#
#(|ipsum)#
#(|dolor)#
"})
.as_str(),
"yp",
platform_line(indoc! {"\
lorem#[|lorem]#
ipsum#(|ipsum)#
dolor#(|dolor)#
"})
.as_str(),
))
.await?;
Ok(())
}