mirror of
https://github.com/helix-editor/helix.git
synced 2024-12-18 22:11:55 +04:00
Fix continuing comment token for first line (#12215)
This commit is contained in:
parent
51ac3e05e0
commit
89a7cde2f0
@ -3458,43 +3458,42 @@ fn open(cx: &mut Context, open: Open) {
|
|||||||
let selection = doc.selection(view.id);
|
let selection = doc.selection(view.id);
|
||||||
|
|
||||||
let mut ranges = SmallVec::with_capacity(selection.len());
|
let mut ranges = SmallVec::with_capacity(selection.len());
|
||||||
let mut offs = 0;
|
|
||||||
|
|
||||||
let mut transaction = Transaction::change_by_selection(contents, selection, |range| {
|
let mut transaction = Transaction::change_by_selection(contents, selection, |range| {
|
||||||
let cursor_line = text.char_to_line(match open {
|
// the line number, where the cursor is currently
|
||||||
|
let curr_line_num = text.char_to_line(match open {
|
||||||
Open::Below => graphemes::prev_grapheme_boundary(text, range.to()),
|
Open::Below => graphemes::prev_grapheme_boundary(text, range.to()),
|
||||||
Open::Above => range.from(),
|
Open::Above => range.from(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let new_line = match open {
|
// the next line number, where the cursor will be, after finishing the transaction
|
||||||
// adjust position to the end of the line (next line - 1)
|
let next_new_line_num = match open {
|
||||||
Open::Below => cursor_line + 1,
|
Open::Below => curr_line_num + 1,
|
||||||
// adjust position to the end of the previous line (current line - 1)
|
Open::Above => curr_line_num,
|
||||||
Open::Above => cursor_line,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let line_num = new_line.saturating_sub(1);
|
let above_next_new_line_num = next_new_line_num.saturating_sub(1);
|
||||||
|
|
||||||
// Index to insert newlines after, as well as the char width
|
|
||||||
// to use to compensate for those inserted newlines.
|
|
||||||
let (line_end_index, line_end_offset_width) = if new_line == 0 {
|
|
||||||
(0, 0)
|
|
||||||
} else {
|
|
||||||
(
|
|
||||||
line_end_char_index(&text, line_num),
|
|
||||||
doc.line_ending.len_chars(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let continue_comment_token = if doc.config.load().continue_comments {
|
let continue_comment_token = if doc.config.load().continue_comments {
|
||||||
doc.language_config()
|
doc.language_config()
|
||||||
.and_then(|config| config.comment_tokens.as_ref())
|
.and_then(|config| config.comment_tokens.as_ref())
|
||||||
.and_then(|tokens| comment::get_comment_token(text, tokens, cursor_line))
|
.and_then(|tokens| comment::get_comment_token(text, tokens, curr_line_num))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let line = text.line(cursor_line);
|
// Index to insert newlines after, as well as the char width
|
||||||
|
// to use to compensate for those inserted newlines.
|
||||||
|
let (above_next_line_end_index, above_next_line_end_width) = if next_new_line_num == 0 {
|
||||||
|
(0, 0)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
line_end_char_index(&text, above_next_new_line_num),
|
||||||
|
doc.line_ending.len_chars(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let line = text.line(curr_line_num);
|
||||||
let indent = match line.first_non_whitespace_char() {
|
let indent = match line.first_non_whitespace_char() {
|
||||||
Some(pos) if continue_comment_token.is_some() => line.slice(..pos).to_string(),
|
Some(pos) if continue_comment_token.is_some() => line.slice(..pos).to_string(),
|
||||||
_ => indent::indent_for_newline(
|
_ => indent::indent_for_newline(
|
||||||
@ -3504,14 +3503,23 @@ fn open(cx: &mut Context, open: Open) {
|
|||||||
&doc.indent_style,
|
&doc.indent_style,
|
||||||
doc.tab_width(),
|
doc.tab_width(),
|
||||||
text,
|
text,
|
||||||
line_num,
|
above_next_new_line_num,
|
||||||
line_end_index,
|
above_next_line_end_index,
|
||||||
cursor_line,
|
curr_line_num,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let indent_len = indent.len();
|
let indent_len = indent.len();
|
||||||
let mut text = String::with_capacity(1 + indent_len);
|
let mut text = String::with_capacity(1 + indent_len);
|
||||||
|
|
||||||
|
if open == Open::Above && next_new_line_num == 0 {
|
||||||
|
text.push_str(&indent);
|
||||||
|
if let Some(token) = continue_comment_token {
|
||||||
|
text.push_str(token);
|
||||||
|
text.push(' ');
|
||||||
|
}
|
||||||
|
text.push_str(doc.line_ending.as_str());
|
||||||
|
} else {
|
||||||
text.push_str(doc.line_ending.as_str());
|
text.push_str(doc.line_ending.as_str());
|
||||||
text.push_str(&indent);
|
text.push_str(&indent);
|
||||||
|
|
||||||
@ -3519,11 +3527,12 @@ fn open(cx: &mut Context, open: Open) {
|
|||||||
text.push_str(token);
|
text.push_str(token);
|
||||||
text.push(' ');
|
text.push(' ');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let text = text.repeat(count);
|
let text = text.repeat(count);
|
||||||
|
|
||||||
// calculate new selection ranges
|
// calculate new selection ranges
|
||||||
let pos = offs + line_end_index + line_end_offset_width;
|
let pos = above_next_line_end_index + above_next_line_end_width;
|
||||||
let comment_len = continue_comment_token
|
let comment_len = continue_comment_token
|
||||||
.map(|token| token.len() + 1) // `+ 1` for the extra space added
|
.map(|token| token.len() + 1) // `+ 1` for the extra space added
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
@ -3536,9 +3545,11 @@ fn open(cx: &mut Context, open: Open) {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
offs += text.chars().count();
|
(
|
||||||
|
above_next_line_end_index,
|
||||||
(line_end_index, line_end_index, Some(text.into()))
|
above_next_line_end_index,
|
||||||
|
Some(text.into()),
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index()));
|
transaction = transaction.with_selection(Selection::new(ranges, selection.primary_index()));
|
||||||
|
@ -119,3 +119,128 @@ async fn insert_newline_continue_line_comment() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// NOTE: Language is set to markdown to check if the indentation is correct for the new line
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn test_open_above() -> anyhow::Result<()> {
|
||||||
|
// `O` is pressed in the first line
|
||||||
|
test((
|
||||||
|
indoc! {"Helix #[is|]# cool"},
|
||||||
|
":lang markdown<ret>O",
|
||||||
|
indoc! {"\
|
||||||
|
#[\n|]#
|
||||||
|
Helix is cool
|
||||||
|
"},
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// `O` is pressed in the first line, but the current line has some indentation
|
||||||
|
test((
|
||||||
|
indoc! {"\
|
||||||
|
··This line has 2 spaces in front of it#[\n|]#
|
||||||
|
"}
|
||||||
|
.replace('·', " "),
|
||||||
|
":lang markdown<ret>Oa",
|
||||||
|
indoc! {"\
|
||||||
|
··a#[\n|]#
|
||||||
|
··This line has 2 spaces in front of it
|
||||||
|
"}
|
||||||
|
.replace('·', " "),
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// `O` is pressed but *not* in the first line
|
||||||
|
test((
|
||||||
|
indoc! {"\
|
||||||
|
I use
|
||||||
|
b#[t|]#w.
|
||||||
|
"},
|
||||||
|
":lang markdown<ret>Oarch",
|
||||||
|
indoc! {"\
|
||||||
|
I use
|
||||||
|
arch#[\n|]#
|
||||||
|
btw.
|
||||||
|
"},
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// `O` is pressed but *not* in the first line and the line has some indentation
|
||||||
|
test((
|
||||||
|
indoc! {"\
|
||||||
|
I use
|
||||||
|
····b#[t|]#w.
|
||||||
|
"}
|
||||||
|
.replace("·", " "),
|
||||||
|
":lang markdown<ret>Ohelix",
|
||||||
|
indoc! {"\
|
||||||
|
I use
|
||||||
|
····helix#[\n|]#
|
||||||
|
····btw.
|
||||||
|
"}
|
||||||
|
.replace("·", " "),
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// NOTE: To make the `open_above` comment-aware, we're setting the language for each test to rust.
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn test_open_above_with_comments() -> anyhow::Result<()> {
|
||||||
|
// `O` is pressed in the first line inside a line comment
|
||||||
|
test((
|
||||||
|
indoc! {"// a commen#[t|]#"},
|
||||||
|
":lang rust<ret>O",
|
||||||
|
indoc! {"\
|
||||||
|
// #[\n|]#
|
||||||
|
// a comment
|
||||||
|
"},
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// `O` is pressed in the first line inside a line comment, but with indentation
|
||||||
|
test((
|
||||||
|
indoc! {"····// a comm#[e|]#nt"}.replace("·", " "),
|
||||||
|
":lang rust<ret>O",
|
||||||
|
indoc! {"\
|
||||||
|
····// #[\n|]#
|
||||||
|
····// a comment
|
||||||
|
"}
|
||||||
|
.replace("·", " "),
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// `O` is pressed but not in the first line but inside a line comment
|
||||||
|
test((
|
||||||
|
indoc! {"\
|
||||||
|
fn main() { }
|
||||||
|
// yeetus deletus#[\n|]#
|
||||||
|
"},
|
||||||
|
":lang rust<ret>O",
|
||||||
|
indoc! {"\
|
||||||
|
fn main() { }
|
||||||
|
// #[\n|]#
|
||||||
|
// yeetus deletus
|
||||||
|
"},
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// `O` is pressed but not in the first line but inside a line comment and with indentation
|
||||||
|
test((
|
||||||
|
indoc! {"\
|
||||||
|
fn main() { }
|
||||||
|
····// yeetus deletus#[\n|]#
|
||||||
|
"}
|
||||||
|
.replace("·", " "),
|
||||||
|
":lang rust<ret>O",
|
||||||
|
indoc! {"\
|
||||||
|
fn main() { }
|
||||||
|
····// #[\n|]#
|
||||||
|
····// yeetus deletus
|
||||||
|
"}
|
||||||
|
.replace("·", " "),
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user