on master help sign in
Join empty lines with only one space in `join_selections` (#8989)

* fix: #8977 fixes the issue that lines with only spaces are getting joined as well * reverting some renamings * improve empty line check * adding integration test * reverting code block * fix conditon check for line end * applying suggested style

commitb81aacc5e1332bb01043a18e55dd9e9543711ec6 authorTornaxO7 <tornax@proton.me> dateWed 6 Dec 2023, 16:19 (3 years ago) parentc3cb179
2 files changed+56−10
helix-term/src/commands.rs+10−10 helix-term/tests/test/commands.rs+46
helix-term/src/commands.rs+10−10
@@ -4391,10 +4391,9 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
43914391 use movement::skip_while;
43924392 let (view, doc) = current!(cx.editor);
43934393 let text = doc.text();
4394− let slice = doc.text().slice(..);
4394+ let slice = text.slice(..);
43954395
43964396 let mut changes = Vec::new();
4397− let fragment = Tendril::from(" ");
43984397
43994398 for selection in doc.selection(view.id) {
44004399 let (start, mut end) = selection.line_range(slice);
@@ -4410,9 +4409,13 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
44104409 let mut end = text.line_to_char(line + 1);
44114410 end = skip_while(slice, end, |ch| matches!(ch, ' ' | '\t')).unwrap_or(end);
44124411
4413− // need to skip from start, not end
4414− let change = (start, end, Some(fragment.clone()));
4415− changes.push(change);
4412+ let separator = if end == line_end_char_index(&slice, line + 1) {
4413+ // the joining line contains only space-characters => don't include a whitespace when joining
4414+ None
4415+ } else {
4416+ Some(Tendril::from(" "))
4417+ };
4418+ changes.push((start, end, separator));
44164419 }
44174420 }
44184421
@@ -4424,9 +4427,6 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
44244427 changes.sort_unstable_by_key(|(from, _to, _text)| *from);
44254428 changes.dedup();
44264429
4427− // TODO: joining multiple empty lines should be replaced by a single space.
4428− // need to merge change ranges that touch
4429−
44304430 // select inserted spaces
44314431 let transaction = if select_space {
44324432 let ranges: SmallVec<_> = changes
@@ -4438,9 +4438,9 @@ fn join_selections_impl(cx: &mut Context, select_space: bool) {
44384438 })
44394439 .collect();
44404440 let selection = Selection::new(ranges, 0);
4441− Transaction::change(doc.text(), changes.into_iter()).with_selection(selection)
4441+ Transaction::change(text, changes.into_iter()).with_selection(selection)
44424442 } else {
4443− Transaction::change(doc.text(), changes.into_iter())
4443+ Transaction::change(text, changes.into_iter())
44444444 };
44454445
44464446 doc.apply(&transaction, view.id);
helix-term/tests/test/commands.rs+46
@@ -480,3 +480,49 @@ fn bar() {#(\n|)#\
480480
481481 Ok(())
482482}
483+
484+#[tokio::test(flavor = "multi_thread")]
485+async fn test_join_selections() -> anyhow::Result<()> {
486+ // normal join
487+ test((
488+ platform_line(indoc! {"\
489+ #[a|]#bc
490+ def
491+ "}),
492+ "J",
493+ platform_line(indoc! {"\
494+ #[a|]#bc def
495+ "}),
496+ ))
497+ .await?;
498+
499+ // join with empty line
500+ test((
501+ platform_line(indoc! {"\
502+ #[a|]#bc
503+
504+ def
505+ "}),
506+ "JJ",
507+ platform_line(indoc! {"\
508+ #[a|]#bc def
509+ "}),
510+ ))
511+ .await?;
512+
513+ // join with additional space in non-empty line
514+ test((
515+ platform_line(indoc! {"\
516+ #[a|]#bc
517+
518+ def
519+ "}),
520+ "JJ",
521+ platform_line(indoc! {"\
522+ #[a|]#bc def
523+ "}),
524+ ))
525+ .await?;
526+
527+ Ok(())
528+}