Z 1618/extend comments (#2585)
Fixes Z-1618. In the current state, this only works for line comments such as `//` (and whatever's set in `{language}.toml` as a line_comment). Release Notes: - Comments are now extended on new line.
This commit is contained in:
parent
d5441ba386
commit
e94129446d
2 changed files with 88 additions and 29 deletions
|
@ -2179,40 +2179,72 @@ impl Editor {
|
||||||
indent.len = cmp::min(indent.len, start_point.column);
|
indent.len = cmp::min(indent.len, start_point.column);
|
||||||
let start = selection.start;
|
let start = selection.start;
|
||||||
let end = selection.end;
|
let end = selection.end;
|
||||||
|
let is_cursor = start == end;
|
||||||
|
let language_scope = buffer.language_scope_at(start);
|
||||||
|
let (comment_delimiter, insert_extra_newline) =
|
||||||
|
if let Some(language) = &language_scope {
|
||||||
|
let leading_whitespace_len = buffer
|
||||||
|
.reversed_chars_at(start)
|
||||||
|
.take_while(|c| c.is_whitespace() && *c != '\n')
|
||||||
|
.map(|c| c.len_utf8())
|
||||||
|
.sum::<usize>();
|
||||||
|
|
||||||
let mut insert_extra_newline = false;
|
let trailing_whitespace_len = buffer
|
||||||
if let Some(language) = buffer.language_scope_at(start) {
|
.chars_at(end)
|
||||||
let leading_whitespace_len = buffer
|
.take_while(|c| c.is_whitespace() && *c != '\n')
|
||||||
.reversed_chars_at(start)
|
.map(|c| c.len_utf8())
|
||||||
.take_while(|c| c.is_whitespace() && *c != '\n')
|
.sum::<usize>();
|
||||||
.map(|c| c.len_utf8())
|
|
||||||
.sum::<usize>();
|
|
||||||
|
|
||||||
let trailing_whitespace_len = buffer
|
let insert_extra_newline =
|
||||||
.chars_at(end)
|
language.brackets().any(|(pair, enabled)| {
|
||||||
.take_while(|c| c.is_whitespace() && *c != '\n')
|
let pair_start = pair.start.trim_end();
|
||||||
.map(|c| c.len_utf8())
|
let pair_end = pair.end.trim_start();
|
||||||
.sum::<usize>();
|
|
||||||
|
|
||||||
insert_extra_newline = language.brackets().any(|(pair, enabled)| {
|
enabled
|
||||||
let pair_start = pair.start.trim_end();
|
&& pair.newline
|
||||||
let pair_end = pair.end.trim_start();
|
&& buffer.contains_str_at(
|
||||||
|
end + trailing_whitespace_len,
|
||||||
|
pair_end,
|
||||||
|
)
|
||||||
|
&& buffer.contains_str_at(
|
||||||
|
(start - leading_whitespace_len)
|
||||||
|
.saturating_sub(pair_start.len()),
|
||||||
|
pair_start,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
// Comment extension on newline is allowed only for cursor selections
|
||||||
|
let comment_delimiter =
|
||||||
|
language.line_comment_prefix().filter(|_| is_cursor);
|
||||||
|
let comment_delimiter = if let Some(delimiter) = comment_delimiter {
|
||||||
|
buffer
|
||||||
|
.buffer_line_for_row(start_point.row)
|
||||||
|
.is_some_and(|(snapshot, range)| {
|
||||||
|
snapshot
|
||||||
|
.chars_for_range(range)
|
||||||
|
.skip_while(|c| c.is_whitespace())
|
||||||
|
.take(delimiter.len())
|
||||||
|
.eq(delimiter.chars())
|
||||||
|
})
|
||||||
|
.then(|| delimiter.clone())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
(comment_delimiter, insert_extra_newline)
|
||||||
|
} else {
|
||||||
|
(None, false)
|
||||||
|
};
|
||||||
|
|
||||||
enabled
|
let capacity_for_delimiter = comment_delimiter
|
||||||
&& pair.newline
|
.as_deref()
|
||||||
&& buffer
|
.map(str::len)
|
||||||
.contains_str_at(end + trailing_whitespace_len, pair_end)
|
.unwrap_or_default();
|
||||||
&& buffer.contains_str_at(
|
let mut new_text =
|
||||||
(start - leading_whitespace_len)
|
String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
|
||||||
.saturating_sub(pair_start.len()),
|
new_text.push_str("\n");
|
||||||
pair_start,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut new_text = String::with_capacity(1 + indent.len as usize);
|
|
||||||
new_text.push('\n');
|
|
||||||
new_text.extend(indent.chars());
|
new_text.extend(indent.chars());
|
||||||
|
if let Some(delimiter) = &comment_delimiter {
|
||||||
|
new_text.push_str(&delimiter);
|
||||||
|
}
|
||||||
if insert_extra_newline {
|
if insert_extra_newline {
|
||||||
new_text = new_text.repeat(2);
|
new_text = new_text.repeat(2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1719,6 +1719,33 @@ async fn test_newline_below(cx: &mut gpui::TestAppContext) {
|
||||||
"});
|
"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_newline_comments(cx: &mut gpui::TestAppContext) {
|
||||||
|
init_test(cx, |settings| {
|
||||||
|
settings.defaults.tab_size = NonZeroU32::new(4)
|
||||||
|
});
|
||||||
|
|
||||||
|
let language = Arc::new(Language::new(
|
||||||
|
LanguageConfig {
|
||||||
|
line_comment: Some("//".into()),
|
||||||
|
..LanguageConfig::default()
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
|
||||||
|
let mut cx = EditorTestContext::new(cx).await;
|
||||||
|
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
|
||||||
|
cx.set_state(indoc! {"
|
||||||
|
// Fooˇ
|
||||||
|
"});
|
||||||
|
|
||||||
|
cx.update_editor(|e, cx| e.newline(&Newline, cx));
|
||||||
|
cx.assert_editor_state(indoc! {"
|
||||||
|
// Foo
|
||||||
|
//ˇ
|
||||||
|
"});
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
fn test_insert_with_old_selections(cx: &mut TestAppContext) {
|
fn test_insert_with_old_selections(cx: &mut TestAppContext) {
|
||||||
init_test(cx, |_| {});
|
init_test(cx, |_| {});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue