Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions assets/settings/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,11 @@
//
// Default: 100
"minimum_split_diff_width": 100,
// Whether to insert comment markers on empty lines when toggling comments
// in a multi-line selection.
//
// Default: false
"comment_on_empty_lines": false,
// Show method signatures in the editor, when inside parentheses.
"auto_signature_help": false,
// Whether to show the signature help after completion or a bracket pair inserted.
Expand Down
2 changes: 2 additions & 0 deletions crates/editor/src/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,8 @@ actions!(
ToggleEditPrediction,
/// Toggles line numbers display.
ToggleLineNumbers,
/// Toggles comment on empty lines when toggling comments in a multi-line selection.
ToggleCommentOnEmptyLines,
/// Toggles the minimap display.
ToggleMinimap,
/// Swaps the start and end of the current selection.
Expand Down
11 changes: 11 additions & 0 deletions crates/editor/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ impl Editor {
EditorSettings::override_global(editor_settings, cx);
}

pub fn toggle_comment_on_empty_lines(
&mut self,
_: &ToggleCommentOnEmptyLines,
_: &mut Window,
cx: &mut Context<Self>,
) {
let mut editor_settings = EditorSettings::get_global(cx).clone();
editor_settings.comment_on_empty_lines = !editor_settings.comment_on_empty_lines;
EditorSettings::override_global(editor_settings, cx);
}

pub fn line_numbers_enabled(&self, cx: &App) -> bool {
if let Some(show_line_numbers) = self.show_line_numbers {
return show_line_numbers;
Expand Down
2 changes: 2 additions & 0 deletions crates/editor/src/editor_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pub struct EditorSettings {
pub completion_menu_item_kind: CompletionMenuItemKind,
pub diff_view_style: DiffViewStyle,
pub minimum_split_diff_width: f32,
pub comment_on_empty_lines: bool,
}
#[derive(Debug, Clone)]
pub struct Jupyter {
Expand Down Expand Up @@ -311,6 +312,7 @@ impl Settings for EditorSettings {
completion_menu_item_kind: editor.completion_menu_item_kind.unwrap(),
diff_view_style: editor.diff_view_style.unwrap(),
minimum_split_diff_width: editor.minimum_split_diff_width.unwrap(),
comment_on_empty_lines: editor.comment_on_empty_lines.unwrap_or(false),
}
}
}
Expand Down
53 changes: 53 additions & 0 deletions crates/editor/src/editor_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21193,6 +21193,59 @@ async fn test_toggle_comment_ignore_indent(cx: &mut TestAppContext) {
"});
}

#[gpui::test]
async fn test_toggle_comment_with_blank_lines_when_comment_on_empty_lines(
cx: &mut TestAppContext,
) {
init_test(cx, |_| {});
let mut cx = EditorTestContext::new(cx).await;
let language = Arc::new(Language::new(
LanguageConfig {
line_comments: vec!["// ".into()],
..Default::default()
},
Some(tree_sitter_rust::LANGUAGE.into()),
));
cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));

cx.update(|_window, cx| {
let mut editor_settings = EditorSettings::get_global(cx).clone();
editor_settings.comment_on_empty_lines = true;
EditorSettings::override_global(editor_settings, cx);
});

// Toggle comment on a multi-line selection with blank lines
cx.set_state(indoc! {"
fn a() {
«a();

c();ˇ»
}
"});

cx.update_editor(|e, window, cx| e.toggle_comments(&ToggleComments::default(), window, cx));

cx.assert_editor_state(indoc! {"
fn a() {
// «a();
//
// c();ˇ»
}
"});

// Uncomment: blank line should remain blank (trailing whitespace from padding is OK)
cx.update_editor(|e, window, cx| e.toggle_comments(&ToggleComments::default(), window, cx));

let editor = cx.editor.clone();
let text = cx.update(|_window, cx| {
editor.update(cx, |editor, cx| {
editor.buffer.read(cx).read(cx).text()
})
});
assert!(text.contains(" a();"));
assert!(text.contains(" c();"));
}

#[gpui::test]
async fn test_advance_downward_on_toggle_comment(cx: &mut TestAppContext) {
init_test(cx, |_| {});
Expand Down
1 change: 1 addition & 0 deletions crates/editor/src/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ impl EditorElement {
register_action(editor, window, Editor::toggle_breadcrumb);
register_action(editor, window, Editor::toggle_line_numbers);
register_action(editor, window, Editor::toggle_relative_line_numbers);
register_action(editor, window, Editor::toggle_comment_on_empty_lines);
register_action(editor, window, Editor::toggle_indent_guides);
register_action(editor, window, Editor::toggle_inlay_hints);
register_action(editor, window, Editor::toggle_inline_values);
Expand Down
45 changes: 40 additions & 5 deletions crates/editor/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1545,11 +1545,22 @@ impl Editor {
.map(|p| p.trim_end_matches(' ').len())
.collect::<SmallVec<[usize; 4]>>();

let comment_on_empty_lines =
EditorSettings::get_global(cx).comment_on_empty_lines;

let mut all_selection_lines_are_comments = true;
let mut blank_prefix_ranges = Vec::new();

for row in start_row.0..=end_row.0 {
let row = MultiBufferRow(row);
if start_row < end_row && snapshot.is_line_blank(row) {
let is_blank_multiline = comment_on_empty_lines
&& start_row < end_row
&& snapshot.is_line_blank(row);

if !comment_on_empty_lines
&& start_row < end_row
&& snapshot.is_line_blank(row)
{
continue;
}

Expand All @@ -1568,11 +1579,14 @@ impl Editor {
.max_by_key(|range| range.end.column - range.start.column)
.expect("prefixes is non-empty");

if prefix_range.is_empty() {
all_selection_lines_are_comments = false;
if is_blank_multiline {
blank_prefix_ranges.push((row, prefix_range));
} else {
if prefix_range.is_empty() {
all_selection_lines_are_comments = false;
}
selection_edit_ranges.push(prefix_range);
}

selection_edit_ranges.push(prefix_range);
}

if all_selection_lines_are_comments {
Expand All @@ -1582,6 +1596,11 @@ impl Editor {
.cloned()
.map(|range| (range, empty_str.clone())),
);
for (_, range) in &blank_prefix_ranges {
if !range.is_empty() {
edits.push((range.clone(), empty_str.clone()));
}
}
} else {
let min_column = selection_edit_ranges
.iter()
Expand All @@ -1592,6 +1611,22 @@ impl Editor {
let position = Point::new(range.start.row, min_column);
(position..position, first_prefix.clone())
}));
let trimmed_prefix = first_prefix.trim_end();
for (row, range) in &blank_prefix_ranges {
if range.is_empty() {
let len = snapshot.line_len(*row);
let (col, text) = if len >= min_column {
(min_column, Arc::from(trimmed_prefix))
} else {
let padding = (min_column - len) as usize;
let mut s = String::with_capacity(padding + trimmed_prefix.len());
s.extend(std::iter::repeat(' ').take(padding));
s.push_str(trimmed_prefix);
(len, s.into())
};
edits.push((Point::new(row.0, col)..Point::new(row.0, col), text));
}
}
}
} else if let Some(BlockCommentConfig {
start: full_comment_prefix,
Expand Down
1 change: 1 addition & 0 deletions crates/settings/src/vscode_import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ impl VsCodeSettings {
completion_menu_item_kind: None,
diff_view_style: None,
minimum_split_diff_width: None,
comment_on_empty_lines: None,
}
}

Expand Down
6 changes: 6 additions & 0 deletions crates/settings_content/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,12 @@ pub struct EditorSettingsContent {
///
/// Default: 100
pub minimum_split_diff_width: Option<f32>,

/// Whether to insert comment markers on empty lines when toggling comments
/// in a multi-line selection.
///
/// Default: false
pub comment_on_empty_lines: Option<bool>,
}

#[derive(
Expand Down
Loading