Z 1618/extend comments (#2585)
Piotr Osiewicz
created 2 years ago
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.
Change summary
crates/editor/src/editor.rs | 96 ++++++++++++++++++++++-----------
crates/editor/src/editor_tests.rs | 27 +++++++++
2 files changed, 91 insertions(+), 32 deletions(-)
Detailed changes
@@ -2179,40 +2179,72 @@ impl Editor {
indent.len = cmp::min(indent.len, start_point.column);
let start = selection.start;
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 trailing_whitespace_len = buffer
+ .chars_at(end)
+ .take_while(|c| c.is_whitespace() && *c != '\n')
+ .map(|c| c.len_utf8())
+ .sum::<usize>();
+
+ let insert_extra_newline =
+ language.brackets().any(|(pair, enabled)| {
+ let pair_start = pair.start.trim_end();
+ let pair_end = pair.end.trim_start();
+
+ enabled
+ && pair.newline
+ && 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)
+ };
- let mut insert_extra_newline = false;
- if let Some(language) = buffer.language_scope_at(start) {
- 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 trailing_whitespace_len = buffer
- .chars_at(end)
- .take_while(|c| c.is_whitespace() && *c != '\n')
- .map(|c| c.len_utf8())
- .sum::<usize>();
-
- insert_extra_newline = language.brackets().any(|(pair, enabled)| {
- let pair_start = pair.start.trim_end();
- let pair_end = pair.end.trim_start();
-
- enabled
- && pair.newline
- && 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,
- )
- });
- }
-
- let mut new_text = String::with_capacity(1 + indent.len as usize);
- new_text.push('\n');
+ let capacity_for_delimiter = comment_delimiter
+ .as_deref()
+ .map(str::len)
+ .unwrap_or_default();
+ let mut new_text =
+ String::with_capacity(1 + capacity_for_delimiter + indent.len as usize);
+ new_text.push_str("\n");
new_text.extend(indent.chars());
+ if let Some(delimiter) = &comment_delimiter {
+ new_text.push_str(&delimiter);
+ }
if insert_extra_newline {
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]
fn test_insert_with_old_selections(cx: &mut TestAppContext) {
init_test(cx, |_| {});