Fix block-comment prefix stripping when joining lines (#63916)
Closes https://github.com/zed-industries/zed/issues/63273#issuecomment-5580302020 https://github.com/user-attachments/assets/0945d43d-9a19-4af6-bc85-c3369d8babb3 Release Notes: - Fixed block-comment prefix stripping when joining lines
This commit is contained in:
1 parent
e2534d2357
commit
20d3cd1d79
3 files changed
+185
-26
No files matched your search
@@ -5790,20 +5790,21 @@ impl Editor {
|
||||
.collect::<String>();
|
||||
|
||||
if !line_text_after_indent.is_empty() {
|
||||
let block_prefix = language_scope
|
||||
let block_prefixes = language_scope
|
||||
.block_comment()
|
||||
.map(|c| c.prefix.as_ref())
|
||||
.filter(|p| !p.is_empty());
|
||||
let doc_prefix = language_scope
|
||||
.documentation_comment()
|
||||
.map(|c| c.prefix.as_ref())
|
||||
.filter(|p| !p.is_empty());
|
||||
.into_iter()
|
||||
.chain(language_scope.documentation_comment())
|
||||
.filter(|comment| {
|
||||
language_scope.override_name() == Some("comment")
|
||||
&& !comment.prefix.is_empty()
|
||||
&& !line_text_after_indent.starts_with(comment.end.as_ref())
|
||||
})
|
||||
.map(|comment| comment.prefix.as_ref());
|
||||
let comment_prefixes = language_scope
|
||||
.line_comment_prefixes()
|
||||
.iter()
|
||||
.map(|p| p.as_ref())
|
||||
.chain(block_prefix)
|
||||
.chain(doc_prefix)
|
||||
.chain(block_prefixes)
|
||||
.map(|prefix| (prefix, false));
|
||||
let all_prefixes = comment_prefixes.chain(
|
||||
language_scope
|
||||
|
||||
@@ -23,7 +23,7 @@ use gpui::{
|
||||
BackgroundExecutor, DismissEvent, Task, TaskExt, TestAppContext, UpdateGlobal,
|
||||
VisualTestContext, WindowBounds, WindowOptions, div,
|
||||
};
|
||||
use indoc::indoc;
|
||||
use indoc::{formatdoc, indoc};
|
||||
use language::{
|
||||
BracketPair, BracketPairConfig,
|
||||
Capability::{Read, ReadOnly, ReadWrite},
|
||||
@@ -7038,22 +7038,8 @@ async fn test_join_lines_strips_comment_prefix(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
{
|
||||
let language = Arc::new(Language::new(
|
||||
LanguageConfig {
|
||||
line_comments: vec!["// ".into(), "/// ".into()],
|
||||
documentation_comment: Some(BlockCommentConfig {
|
||||
start: "/*".into(),
|
||||
end: "*/".into(),
|
||||
prefix: "* ".into(),
|
||||
tab_size: 1,
|
||||
}),
|
||||
..LanguageConfig::default()
|
||||
},
|
||||
None,
|
||||
));
|
||||
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(rust_lang()), cx));
|
||||
|
||||
// Strips the comment prefix (with trailing space) from the joined-in line.
|
||||
cx.set_state(indoc! {"
|
||||
@@ -7117,22 +7103,30 @@ async fn test_join_lines_strips_comment_prefix(cx: &mut TestAppContext) {
|
||||
|
||||
// Strips block comment body prefix (`* `) from the joined-in line.
|
||||
cx.set_state(indoc! {"
|
||||
/*
|
||||
* ˇfoo
|
||||
* bar
|
||||
*/
|
||||
"});
|
||||
cx.update_editor(|e, window, cx| e.join_lines(&JoinLines, window, cx));
|
||||
cx.assert_editor_state(indoc! {"
|
||||
/*
|
||||
* fooˇ bar
|
||||
*/
|
||||
"});
|
||||
|
||||
// Strips bare block comment body prefix (`*` without trailing space).
|
||||
cx.set_state(indoc! {"
|
||||
/*
|
||||
* ˇfoo
|
||||
*
|
||||
*/
|
||||
"});
|
||||
cx.update_editor(|e, window, cx| e.join_lines(&JoinLines, window, cx));
|
||||
cx.assert_editor_state(indoc! {"
|
||||
/*
|
||||
* fooˇ
|
||||
*/
|
||||
"});
|
||||
}
|
||||
|
||||
@@ -7208,6 +7202,92 @@ async fn test_join_lines_strips_comment_prefix(cx: &mut TestAppContext) {
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_join_lines_preserves_rust_operators(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(rust_lang()), cx));
|
||||
|
||||
for insert_whitespace in [true, false] {
|
||||
let separator = if insert_whitespace { " " } else { "" };
|
||||
for indent in ["", " ", "\t"] {
|
||||
for (first_line, next_line) in [
|
||||
("let value =", "*pointer;"),
|
||||
("let value =", "* pointer;"),
|
||||
("let value =", "**pointer;"),
|
||||
("let value =", "*指针;"),
|
||||
("let value = 2", "* 3;"),
|
||||
("let value = \"text", "*text\";"),
|
||||
("let value = r#\"text", "*text\"#;"),
|
||||
] {
|
||||
cx.set_state(&formatdoc! {"
|
||||
fn main() {{
|
||||
{first_line}ˇ
|
||||
{indent}{next_line}
|
||||
}}"});
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.join_lines_impl(insert_whitespace, window, cx)
|
||||
});
|
||||
cx.assert_editor_state(&formatdoc! {"
|
||||
fn main() {{
|
||||
{first_line}ˇ{separator}{next_line}
|
||||
}}"});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_join_lines_rust_block_comments(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
cx.update_buffer(|buffer, cx| buffer.set_language(Some(rust_lang()), cx));
|
||||
|
||||
for insert_whitespace in [true, false] {
|
||||
let separator = if insert_whitespace { " " } else { "" };
|
||||
for start in ["/*", "/**", "/*!"] {
|
||||
for next_line in ["* bar", "*bar"] {
|
||||
cx.set_state(&formatdoc! {"
|
||||
{start}
|
||||
* fooˇ
|
||||
{next_line}
|
||||
*/"});
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.join_lines_impl(insert_whitespace, window, cx)
|
||||
});
|
||||
cx.assert_editor_state(&formatdoc! {"
|
||||
{start}
|
||||
* fooˇ{separator}bar
|
||||
*/"});
|
||||
}
|
||||
|
||||
cx.set_state(&formatdoc! {"
|
||||
{start}
|
||||
* fooˇ
|
||||
*
|
||||
*/"});
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.join_lines_impl(insert_whitespace, window, cx)
|
||||
});
|
||||
cx.assert_editor_state(&formatdoc! {"
|
||||
{start}
|
||||
* fooˇ
|
||||
*/"});
|
||||
|
||||
cx.set_state(&formatdoc! {"
|
||||
{start}
|
||||
* fooˇ
|
||||
*/"});
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.join_lines_impl(insert_whitespace, window, cx)
|
||||
});
|
||||
cx.assert_editor_state(&formatdoc! {"
|
||||
{start}
|
||||
* fooˇ{separator}*/"});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_custom_newlines_cause_no_false_positive_diffs(
|
||||
executor: BackgroundExecutor,
|
||||
|
||||
+79
-1
@@ -26,7 +26,7 @@ use util::{path, test::marked_text_ranges};
|
||||
pub use vim_test_context::*;
|
||||
|
||||
use gpui::VisualTestContext;
|
||||
use indoc::indoc;
|
||||
use indoc::{formatdoc, indoc};
|
||||
use project::FakeFs;
|
||||
use search::BufferSearchBar;
|
||||
use search::{ProjectSearchView, project_search};
|
||||
@@ -621,6 +621,84 @@ async fn test_join_lines(cx: &mut gpui::TestAppContext) {
|
||||
"});
|
||||
}
|
||||
|
||||
#[perf]
|
||||
#[gpui::test]
|
||||
async fn test_join_lines_rust_dereference(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
||||
for dereference in ["*value.get()", "* value.get()"] {
|
||||
let initial = formatdoc! {"
|
||||
ˇlet another_value = unsafe {{
|
||||
{dereference}
|
||||
}};"};
|
||||
let joined = formatdoc! {"
|
||||
let another_value = unsafe {{ˇ {dereference}
|
||||
}};"};
|
||||
let fully_joined = format!("let another_value = unsafe {{ {dereference}ˇ }};");
|
||||
|
||||
for keystrokes in [
|
||||
"shift-j",
|
||||
"1 shift-j",
|
||||
"2 shift-j",
|
||||
"v j shift-j",
|
||||
"shift-v j shift-j",
|
||||
"j v k shift-j",
|
||||
"j shift-v k shift-j",
|
||||
] {
|
||||
cx.assert_binding_normal(keystrokes, &initial, &joined);
|
||||
}
|
||||
|
||||
for keystrokes in [
|
||||
"3 shift-j",
|
||||
"v 2 j shift-j",
|
||||
"shift-v 2 j shift-j",
|
||||
"2 j v 2 k shift-j",
|
||||
"2 j shift-v 2 k shift-j",
|
||||
] {
|
||||
cx.assert_binding_normal(keystrokes, &initial, &fully_joined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[perf]
|
||||
#[gpui::test]
|
||||
async fn test_join_lines_rust_dereference_without_whitespace(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
||||
for dereference in ["*value.get()", "* value.get()"] {
|
||||
let initial = formatdoc! {"
|
||||
ˇlet another_value = unsafe {{
|
||||
{dereference}
|
||||
}};"};
|
||||
let joined = formatdoc! {"
|
||||
let another_value = unsafe {{ˇ{dereference}
|
||||
}};"};
|
||||
let fully_joined = format!("let another_value = unsafe {{{dereference}ˇ}};");
|
||||
|
||||
for keystrokes in [
|
||||
"g shift-j",
|
||||
"1 g shift-j",
|
||||
"2 g shift-j",
|
||||
"v j g shift-j",
|
||||
"shift-v j g shift-j",
|
||||
"j v k g shift-j",
|
||||
"j shift-v k g shift-j",
|
||||
] {
|
||||
cx.assert_binding_normal(keystrokes, &initial, &joined);
|
||||
}
|
||||
|
||||
for keystrokes in [
|
||||
"3 g shift-j",
|
||||
"v 2 j g shift-j",
|
||||
"shift-v 2 j g shift-j",
|
||||
"2 j v 2 k g shift-j",
|
||||
"2 j shift-v 2 k g shift-j",
|
||||
] {
|
||||
cx.assert_binding_normal(keystrokes, &initial, &fully_joined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[perf]
|
||||
#[gpui::test]
|
||||
|
||||
Reference in new issue
Block a user