Skip to content

Commit 019fe67

Browse files
committed
refactor: extract a separate toggle_comment_impl function
1 parent 9431a53 commit 019fe67

File tree

2 files changed

+106
-139
lines changed

2 files changed

+106
-139
lines changed

helix-core/src/comment.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,50 @@ pub fn get_comment_token<'a, S: AsRef<str>>(
2525
.max_by_key(|token| token.len())
2626
}
2727

28+
pub fn get_injected_tokens(
29+
syntax: Option<&Syntax>,
30+
start: usize,
31+
end: usize,
32+
) -> (Option<Vec<String>>, Option<Vec<BlockCommentToken>>) {
33+
let mut best_fit = None;
34+
let mut min_gap = usize::MAX;
35+
36+
// Find the injection with the most tightly encompassing range.
37+
if let Some(syntax) = &syntax {
38+
for (layer_id, layer) in &syntax.layers {
39+
for ts_range in &layer.ranges {
40+
let is_encompassing = ts_range.start_byte <= start && ts_range.end_byte >= end;
41+
if is_encompassing {
42+
let this_gap = ts_range.end_byte - ts_range.start_byte;
43+
if this_gap < min_gap
44+
// ignore the "comment" language family
45+
// as that would mean we can't uncomment anything, or
46+
// the comments would be incorrect.
47+
//
48+
// Since uncommenting would attempt to use the comment
49+
// language's non-existing comment tokens
50+
// TODO: add this as a language configuration key?
51+
&& !matches!(syntax.layer_config(layer_id).language_name.as_ref(), "jsdoc" | "comment")
52+
{
53+
best_fit = Some(layer_id);
54+
min_gap = this_gap;
55+
}
56+
}
57+
}
58+
}
59+
60+
if let Some(best_fit) = best_fit {
61+
let config = syntax.layer_config(best_fit);
62+
return (
63+
config.comment_tokens.clone(),
64+
config.block_comment_tokens.clone(),
65+
);
66+
}
67+
}
68+
69+
(None, None)
70+
}
71+
2872
/// Given text, a comment token, and a set of line indices, returns the following:
2973
/// - Whether the given lines should be considered commented
3074
/// - If any of the lines are uncommented, all lines are considered as such.

helix-term/src/commands.rs

Lines changed: 62 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -5022,90 +5022,55 @@ pub fn completion(cx: &mut Context) {
50225022

50235023
// comments
50245024

5025-
pub type CommentTransactionFn<'a> =
5026-
Box<dyn FnMut(&mut Context, comment::GetInjectedTokens<'a>) + 'a>;
5027-
5028-
fn toggle_comments_impl<'a>(
5029-
cx: &'a mut Context,
5030-
mut comment_transaction: CommentTransactionFn<'a>,
5031-
) {
5032-
comment_transaction(
5033-
cx,
5034-
Box::new(move |syntax: Option<&Syntax>, start: usize, end: usize| {
5035-
let mut best_fit = None;
5036-
let mut min_gap = usize::MAX;
5037-
5038-
// Find the injection with the most tightly encompassing range.
5039-
if let Some(syntax) = &syntax {
5040-
for (layer_id, layer) in &syntax.layers {
5041-
for ts_range in &layer.ranges {
5042-
let is_encompassing =
5043-
ts_range.start_byte <= start && ts_range.end_byte >= end;
5044-
if is_encompassing {
5045-
let this_gap = ts_range.end_byte - ts_range.start_byte;
5046-
if this_gap < min_gap
5047-
// ignore the "comment" language family
5048-
// as that would mean we can't uncomment anything, or
5049-
// the comments would be incorrect.
5050-
//
5051-
// Since uncommenting would attempt to use the comment
5052-
// language's non-existing comment tokens
5053-
// TODO: add this as a language configuration key?
5054-
&& !matches!(syntax.layer_config(layer_id).language_name.as_ref(), "jsdoc" | "comment")
5055-
{
5056-
best_fit = Some(layer_id);
5057-
min_gap = this_gap;
5058-
}
5059-
}
5060-
}
5061-
}
5062-
5063-
if let Some(best_fit) = best_fit {
5064-
let config = syntax.layer_config(best_fit);
5065-
return (
5066-
config.comment_tokens.clone(),
5067-
config.block_comment_tokens.clone(),
5068-
);
5069-
}
5070-
}
5071-
5072-
(None, None)
5073-
}),
5074-
);
5075-
}
5076-
50775025
/// commenting behavior, for each range in selection:
50785026
/// 1. only line comment tokens -> line comment
50795027
/// 2. each line block commented -> uncomment all lines
50805028
/// 3. whole selection block commented -> uncomment selection
50815029
/// 4. all lines not commented and block tokens -> comment uncommented lines
50825030
/// 5. no comment tokens and not block commented -> line comment
5031+
fn toggle_comments_impl<F>(cx: &mut Context, comments_transaction: F)
5032+
where
5033+
F: Fn(
5034+
&Rope,
5035+
&Selection,
5036+
Option<&str>,
5037+
Option<&[BlockCommentToken]>,
5038+
Option<&Syntax>,
5039+
) -> Transaction,
5040+
{
5041+
let (view, doc) = current!(cx.editor);
5042+
let syntax = doc.syntax();
5043+
let rope = doc.text();
5044+
let selection = doc.selection(view.id);
5045+
5046+
// The comment tokens to fallback to if no comment tokens are found for the injection layer.
5047+
let doc_line_token: Option<&str> = doc
5048+
.language_config()
5049+
.and_then(|lc| lc.comment_tokens.as_ref())
5050+
.and_then(|tc| tc.first())
5051+
.map(|tc| tc.as_str());
5052+
let doc_block_tokens: Option<&[BlockCommentToken]> = doc
5053+
.language_config()
5054+
.and_then(|lc| lc.block_comment_tokens.as_ref())
5055+
.map(|tc| &tc[..]);
5056+
5057+
// Call the custom logic provided by the caller (the original functions).
5058+
let transaction =
5059+
comments_transaction(rope, selection, doc_line_token, doc_block_tokens, syntax);
5060+
5061+
doc.apply(&transaction, view.id);
5062+
exit_select_mode(cx);
5063+
}
5064+
50835065
fn toggle_comments(cx: &mut Context) {
50845066
toggle_comments_impl(
50855067
cx,
5086-
Box::new(|cx, mut get_comment_tokens| {
5087-
let (view, doc) = current!(cx.editor);
5088-
let syntax = doc.syntax();
5089-
let rope = doc.text();
5090-
let selection = doc.selection(view.id);
5091-
5092-
// The comment tokens to fallback to if no comment tokens are found for the injection layer.
5093-
let doc_line_token: Option<&str> = doc
5094-
.language_config()
5095-
.and_then(|lc| lc.comment_tokens.as_ref())
5096-
.and_then(|tc| tc.first())
5097-
.map(|tc| tc.as_str());
5098-
let doc_block_tokens: Option<&[BlockCommentToken]> = doc
5099-
.language_config()
5100-
.and_then(|lc| lc.block_comment_tokens.as_ref())
5101-
.map(|tc| &tc[..]);
5102-
5103-
let transaction = Transaction::change(
5068+
|rope, selection, doc_line_token, doc_block_tokens, syntax| {
5069+
Transaction::change(
51045070
rope,
51055071
selection.iter().flat_map(|range| {
5106-
let text = rope.slice(..);
51075072
let (injected_line_tokens, injected_block_tokens) =
5108-
get_comment_tokens(syntax, range.from(), range.to());
5073+
comment::get_injected_tokens(syntax, range.from(), range.to());
51095074

51105075
let line_token = injected_line_tokens
51115076
.as_ref()
@@ -5115,20 +5080,21 @@ fn toggle_comments(cx: &mut Context) {
51155080

51165081
let block_tokens = injected_block_tokens.as_deref().or(doc_block_tokens);
51175082

5118-
// only have line tokens
51195083
if line_token.is_some() && block_tokens.is_none() {
51205084
return comment::toggle_line_comments(rope, range, line_token);
51215085
}
51225086

5123-
let split_lines = comment::split_lines_of_range(text, range);
5087+
let split_lines = comment::split_lines_of_range(rope.slice(..), range);
51245088

51255089
let default_block_tokens = &[BlockCommentToken::default()];
51265090
let block_comment_tokens = block_tokens.unwrap_or(default_block_tokens);
51275091

5128-
let (line_commented, line_comment_changes) =
5129-
comment::find_block_comments(block_comment_tokens, text, &split_lines);
5092+
let (line_commented, line_comment_changes) = comment::find_block_comments(
5093+
block_comment_tokens,
5094+
rope.slice(..),
5095+
&split_lines,
5096+
);
51305097

5131-
// block commented by line would also be block commented so check this first
51325098
if line_commented {
51335099
return comment::create_block_comment_transaction(
51345100
&split_lines,
@@ -5138,20 +5104,21 @@ fn toggle_comments(cx: &mut Context) {
51385104
.0;
51395105
}
51405106

5141-
let (block_commented, comment_changes) =
5142-
comment::find_block_comments(block_comment_tokens, text, &vec![*range]);
5107+
let (block_commented, comment_changes) = comment::find_block_comments(
5108+
block_comment_tokens,
5109+
rope.slice(..),
5110+
&vec![*range],
5111+
);
51435112

5144-
// check if selection has block comments
51455113
if block_commented {
51465114
return comment::create_block_comment_transaction(
51475115
&[*range],
51485116
block_commented,
51495117
comment_changes,
51505118
)
51515119
.0;
5152-
};
5120+
}
51535121

5154-
// not commented and only have block comment tokens
51555122
if line_token.is_none() && block_tokens.is_some() {
51565123
return comment::create_block_comment_transaction(
51575124
&split_lines,
@@ -5161,47 +5128,26 @@ fn toggle_comments(cx: &mut Context) {
51615128
.0;
51625129
}
51635130

5164-
// not block commented at all and don't have any tokens
51655131
comment::toggle_line_comments(rope, range, line_token)
51665132
}),
5167-
);
5168-
5169-
doc.apply(&transaction, view.id);
5170-
exit_select_mode(cx);
5171-
}),
5172-
)
5133+
)
5134+
},
5135+
);
51735136
}
51745137

51755138
fn toggle_line_comments(cx: &mut Context) {
51765139
toggle_comments_impl(
51775140
cx,
5178-
Box::new(|cx, mut get_comment_tokens| {
5179-
let (view, doc) = current!(cx.editor);
5180-
let syntax = doc.syntax();
5181-
let rope = doc.text();
5182-
let selection = doc.selection(view.id);
5183-
5184-
// The comment tokens to fallback to if no comment tokens are found for the injection layer.
5185-
let doc_line_token: Option<&str> = doc
5186-
.language_config()
5187-
.and_then(|lc| lc.comment_tokens.as_ref())
5188-
.and_then(|tc| tc.first())
5189-
.map(|tc| tc.as_str());
5190-
let doc_block_tokens: Option<&[BlockCommentToken]> = doc
5191-
.language_config()
5192-
.and_then(|lc| lc.block_comment_tokens.as_ref())
5193-
.map(|tc| &tc[..]);
5194-
5195-
// when we add comment tokens, we want to extend our selection to
5196-
// also include the added tokens.
5141+
|rope, selection, doc_line_token, doc_block_tokens, syntax| {
51975142
let mut selections = SmallVec::new();
51985143
let mut added_chars = 0;
51995144
let mut removed_chars = 0;
5145+
52005146
let transaction = Transaction::change(
52015147
rope,
52025148
selection.iter().flat_map(|range| {
52035149
let (injected_line_tokens, injected_block_tokens) =
5204-
get_comment_tokens(syntax, range.from(), range.to());
5150+
comment::get_injected_tokens(syntax, range.from(), range.to());
52055151

52065152
let line_token = injected_line_tokens
52075153
.as_ref()
@@ -5229,43 +5175,24 @@ fn toggle_line_comments(cx: &mut Context) {
52295175
}),
52305176
);
52315177

5232-
let transaction =
5233-
transaction.with_selection(Selection::new(selections, selection.primary_index()));
5234-
5235-
doc.apply(&transaction, view.id);
5236-
exit_select_mode(cx);
5237-
}),
5178+
transaction.with_selection(Selection::new(selections, selection.primary_index()))
5179+
},
52385180
);
52395181
}
52405182

52415183
fn toggle_block_comments(cx: &mut Context) {
52425184
toggle_comments_impl(
52435185
cx,
5244-
Box::new(|cx, mut get_injected_tokens| {
5245-
let (view, doc) = current!(cx.editor);
5246-
let syntax = doc.syntax();
5247-
let rope = doc.text();
5248-
let selection = doc.selection(view.id);
5249-
5250-
// The comment tokens to fallback to if no comment tokens are found for the injection layer.
5251-
let doc_line_token: Option<&str> = doc
5252-
.language_config()
5253-
.and_then(|lc| lc.comment_tokens.as_ref())
5254-
.and_then(|tc| tc.first())
5255-
.map(|tc| tc.as_str());
5256-
let doc_block_tokens: Option<&[BlockCommentToken]> = doc
5257-
.language_config()
5258-
.and_then(|lc| lc.block_comment_tokens.as_ref())
5259-
.map(|tc| &tc[..]);
5260-
5186+
|rope, selection, doc_line_token, doc_block_tokens, syntax| {
52615187
let mut selections = SmallVec::new();
52625188
let mut added_chars = 0;
52635189
let mut removed_chars = 0;
5190+
52645191
let transaction = Transaction::change(
52655192
rope,
52665193
selection.iter().flat_map(|range| {
52675194
let (injected_line_tokens, injected_block_tokens) =
5268-
get_injected_tokens(syntax, range.from(), range.to());
5195+
comment::get_injected_tokens(syntax, range.from(), range.to());
52695196

52705197
let line_token = injected_line_tokens
52715198
.as_ref()
@@ -5293,12 +5220,8 @@ fn toggle_block_comments(cx: &mut Context) {
52935220
}),
52945221
);
52955222

5296-
let transaction =
5297-
transaction.with_selection(Selection::new(selections, selection.primary_index()));
5298-
5299-
doc.apply(&transaction, view.id);
5300-
exit_select_mode(cx);
5301-
}),
5223+
transaction.with_selection(Selection::new(selections, selection.primary_index()))
5224+
},
53025225
);
53035226
}
53045227

0 commit comments

Comments
 (0)