mirror of
https://github.com/helix-editor/helix.git
synced 2025-04-05 11:57:43 +03:00
feat: gain access to injection-specific line and block comment tokens
This commit is contained in:
parent
b10fc21169
commit
d719f1572b
3 changed files with 314 additions and 256 deletions
|
@ -85,53 +85,54 @@ fn find_line_comment<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// for a given range and syntax, determine if there are additional tokens to consider
|
// for a given range and syntax, determine if there are additional tokens to consider
|
||||||
pub type InjectedTokens =
|
pub type GetCommentTokens<'a> =
|
||||||
Box<dyn FnMut(usize, usize) -> (Option<Vec<String>>, Option<Vec<BlockCommentToken>>)>;
|
Box<dyn FnMut(usize, usize) -> (Option<Vec<String>>, Option<Vec<BlockCommentToken>>) + 'a>;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn toggle_line_comments(
|
pub fn toggle_line_comments(
|
||||||
doc: &Rope,
|
doc: &Rope,
|
||||||
selection: &Selection,
|
selection: &Selection,
|
||||||
token: Option<&str>,
|
token: Option<&str>,
|
||||||
lol_fn: InjectedTokens,
|
lol_fn: GetCommentTokens,
|
||||||
) -> Transaction {
|
) -> Transaction {
|
||||||
let text = doc.slice(..);
|
todo!();
|
||||||
|
// let text = doc.slice(..);
|
||||||
|
|
||||||
let token = token.unwrap_or(DEFAULT_COMMENT_TOKEN);
|
// let token = token.unwrap_or(DEFAULT_COMMENT_TOKEN);
|
||||||
let comment = Tendril::from(format!("{} ", token));
|
// let comment = Tendril::from(format!("{} ", token));
|
||||||
|
|
||||||
let mut lines: Vec<(usize, &str)> = Vec::with_capacity(selection.len());
|
// let mut lines: Vec<(usize, &str)> = Vec::with_capacity(selection.len());
|
||||||
|
|
||||||
let mut min_next_line = 0;
|
// let mut min_next_line = 0;
|
||||||
for selection in selection {
|
// for selection in selection {
|
||||||
let (start, end) = selection.line_range(text);
|
// let (start, end) = selection.line_range(text);
|
||||||
let start = start.clamp(min_next_line, text.len_lines());
|
// let start = start.clamp(min_next_line, text.len_lines());
|
||||||
let end = (end + 1).min(text.len_lines());
|
// let end = (end + 1).min(text.len_lines());
|
||||||
|
|
||||||
let start_byte = text.line_to_byte(start);
|
// let start_byte = text.line_to_byte(start);
|
||||||
let end_byte = text.line_to_byte(start);
|
// let end_byte = text.line_to_byte(start);
|
||||||
|
|
||||||
lines.extend(start..end);
|
// let tokens = lines.extend(start..end);
|
||||||
min_next_line = end;
|
// min_next_line = end;
|
||||||
}
|
// }
|
||||||
|
|
||||||
let (commented, to_change, min, margin) = find_line_comment(token, text, lines);
|
// let (commented, to_change, min, margin) = find_line_comment(token, text, lines);
|
||||||
|
|
||||||
let mut changes: Vec<Change> = Vec::with_capacity(to_change.len());
|
// let mut changes: Vec<Change> = Vec::with_capacity(to_change.len());
|
||||||
|
|
||||||
for line in to_change {
|
// for line in to_change {
|
||||||
let pos = text.line_to_char(line) + min;
|
// let pos = text.line_to_char(line) + min;
|
||||||
|
|
||||||
if !commented {
|
// if !commented {
|
||||||
// comment line
|
// // comment line
|
||||||
changes.push((pos, pos, Some(comment.clone())));
|
// changes.push((pos, pos, Some(comment.clone())));
|
||||||
} else {
|
// } else {
|
||||||
// uncomment line
|
// // uncomment line
|
||||||
changes.push((pos, pos + token.len() + margin, None));
|
// changes.push((pos, pos + token.len() + margin, None));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
Transaction::change(doc, changes.into_iter())
|
// Transaction::change(doc, changes.into_iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
@ -343,163 +344,163 @@ pub fn split_lines_of_selection(text: RopeSlice, selection: &Selection) -> Selec
|
||||||
Selection::new(ranges, 0)
|
Selection::new(ranges, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
// #[cfg(test)]
|
||||||
mod test {
|
// mod test {
|
||||||
use super::*;
|
// use super::*;
|
||||||
|
|
||||||
mod find_line_comment {
|
// mod find_line_comment {
|
||||||
use super::*;
|
// use super::*;
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn not_commented() {
|
// fn not_commented() {
|
||||||
// four lines, two space indented, except for line 1 which is blank.
|
// // four lines, two space indented, except for line 1 which is blank.
|
||||||
let doc = Rope::from(" 1\n\n 2\n 3");
|
// let doc = Rope::from(" 1\n\n 2\n 3");
|
||||||
|
|
||||||
let text = doc.slice(..);
|
// let text = doc.slice(..);
|
||||||
|
|
||||||
let res = find_line_comment("//", text, 0..3);
|
// let res = find_line_comment("//", text, 0..3);
|
||||||
// (commented = false, to_change = [line 0, line 2], min = col 2, margin = 0)
|
// // (commented = false, to_change = [line 0, line 2], min = col 2, margin = 0)
|
||||||
assert_eq!(res, (false, vec![0, 2], 2, 0));
|
// assert_eq!(res, (false, vec![0, 2], 2, 0));
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn is_commented() {
|
// fn is_commented() {
|
||||||
// three lines where the second line is empty.
|
// // three lines where the second line is empty.
|
||||||
let doc = Rope::from("// hello\n\n// there");
|
// let doc = Rope::from("// hello\n\n// there");
|
||||||
|
|
||||||
let res = find_line_comment("//", doc.slice(..), 0..3);
|
// let res = find_line_comment("//", doc.slice(..), 0..3);
|
||||||
|
|
||||||
// (commented = true, to_change = [line 0, line 2], min = col 0, margin = 1)
|
// // (commented = true, to_change = [line 0, line 2], min = col 0, margin = 1)
|
||||||
assert_eq!(res, (true, vec![0, 2], 0, 1));
|
// assert_eq!(res, (true, vec![0, 2], 0, 1));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// TODO: account for uncommenting with uneven comment indentation
|
// // TODO: account for uncommenting with uneven comment indentation
|
||||||
mod toggle_line_comment {
|
// mod toggle_line_comment {
|
||||||
use super::*;
|
// use super::*;
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn comment() {
|
// fn comment() {
|
||||||
// four lines, two space indented, except for line 1 which is blank.
|
// // four lines, two space indented, except for line 1 which is blank.
|
||||||
let mut doc = Rope::from(" 1\n\n 2\n 3");
|
// let mut doc = Rope::from(" 1\n\n 2\n 3");
|
||||||
// select whole document
|
// // select whole document
|
||||||
let selection = Selection::single(0, doc.len_chars() - 1);
|
// let selection = Selection::single(0, doc.len_chars() - 1);
|
||||||
|
|
||||||
let transaction = toggle_line_comments(&doc, &selection, None);
|
// let transaction = toggle_line_comments(&doc, &selection, None);
|
||||||
transaction.apply(&mut doc);
|
// transaction.apply(&mut doc);
|
||||||
|
|
||||||
assert_eq!(doc, " # 1\n\n # 2\n # 3");
|
// assert_eq!(doc, " # 1\n\n # 2\n # 3");
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn uncomment() {
|
// fn uncomment() {
|
||||||
let mut doc = Rope::from(" # 1\n\n # 2\n # 3");
|
// let mut doc = Rope::from(" # 1\n\n # 2\n # 3");
|
||||||
let mut selection = Selection::single(0, doc.len_chars() - 1);
|
// let mut selection = Selection::single(0, doc.len_chars() - 1);
|
||||||
|
|
||||||
let transaction = toggle_line_comments(&doc, &selection, None);
|
// let transaction = toggle_line_comments(&doc, &selection, None);
|
||||||
transaction.apply(&mut doc);
|
// transaction.apply(&mut doc);
|
||||||
selection = selection.map(transaction.changes());
|
// selection = selection.map(transaction.changes());
|
||||||
|
|
||||||
assert_eq!(doc, " 1\n\n 2\n 3");
|
// assert_eq!(doc, " 1\n\n 2\n 3");
|
||||||
assert!(selection.len() == 1); // to ignore the selection unused warning
|
// assert!(selection.len() == 1); // to ignore the selection unused warning
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn uncomment_0_margin_comments() {
|
// fn uncomment_0_margin_comments() {
|
||||||
let mut doc = Rope::from(" #1\n\n #2\n #3");
|
// let mut doc = Rope::from(" #1\n\n #2\n #3");
|
||||||
let mut selection = Selection::single(0, doc.len_chars() - 1);
|
// let mut selection = Selection::single(0, doc.len_chars() - 1);
|
||||||
|
|
||||||
let transaction = toggle_line_comments(&doc, &selection, None);
|
// let transaction = toggle_line_comments(&doc, &selection, None);
|
||||||
transaction.apply(&mut doc);
|
// transaction.apply(&mut doc);
|
||||||
selection = selection.map(transaction.changes());
|
// selection = selection.map(transaction.changes());
|
||||||
|
|
||||||
assert_eq!(doc, " 1\n\n 2\n 3");
|
// assert_eq!(doc, " 1\n\n 2\n 3");
|
||||||
assert!(selection.len() == 1); // to ignore the selection unused warning
|
// assert!(selection.len() == 1); // to ignore the selection unused warning
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn uncomment_0_margin_comments_with_no_space() {
|
// fn uncomment_0_margin_comments_with_no_space() {
|
||||||
let mut doc = Rope::from("#");
|
// let mut doc = Rope::from("#");
|
||||||
let mut selection = Selection::single(0, doc.len_chars() - 1);
|
// let mut selection = Selection::single(0, doc.len_chars() - 1);
|
||||||
|
|
||||||
let transaction = toggle_line_comments(&doc, &selection, None);
|
// let transaction = toggle_line_comments(&doc, &selection, None);
|
||||||
transaction.apply(&mut doc);
|
// transaction.apply(&mut doc);
|
||||||
selection = selection.map(transaction.changes());
|
// selection = selection.map(transaction.changes());
|
||||||
assert_eq!(doc, "");
|
// assert_eq!(doc, "");
|
||||||
assert!(selection.len() == 1); // to ignore the selection unused warning
|
// assert!(selection.len() == 1); // to ignore the selection unused warning
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// #[test]
|
||||||
fn test_find_block_comments() {
|
// fn test_find_block_comments() {
|
||||||
// three lines 5 characters.
|
// // three lines 5 characters.
|
||||||
let mut doc = Rope::from("1\n2\n3");
|
// let mut doc = Rope::from("1\n2\n3");
|
||||||
// select whole document
|
// // select whole document
|
||||||
let selection = Selection::single(0, doc.len_chars());
|
// let selection = Selection::single(0, doc.len_chars());
|
||||||
|
|
||||||
let text = doc.slice(..);
|
// let text = doc.slice(..);
|
||||||
|
|
||||||
let res = find_block_comments(&[BlockCommentToken::default()], text, &selection);
|
// let res = find_block_comments(&[BlockCommentToken::default()], text, &selection);
|
||||||
|
|
||||||
assert_eq!(
|
// assert_eq!(
|
||||||
res,
|
// res,
|
||||||
(
|
// (
|
||||||
false,
|
// false,
|
||||||
vec![CommentChange::Uncommented {
|
// vec![CommentChange::Uncommented {
|
||||||
range: Range::new(0, 5),
|
// range: Range::new(0, 5),
|
||||||
start_pos: 0,
|
// start_pos: 0,
|
||||||
end_pos: 4,
|
// end_pos: 4,
|
||||||
start_token: "/*".to_string(),
|
// start_token: "/*".to_string(),
|
||||||
end_token: "*/".to_string(),
|
// end_token: "*/".to_string(),
|
||||||
}]
|
// }]
|
||||||
)
|
// )
|
||||||
);
|
// );
|
||||||
|
|
||||||
// comment
|
// // comment
|
||||||
let transaction = toggle_block_comments(&doc, &selection, &[BlockCommentToken::default()]);
|
// let transaction = toggle_block_comments(&doc, &selection, &[BlockCommentToken::default()]);
|
||||||
transaction.apply(&mut doc);
|
// transaction.apply(&mut doc);
|
||||||
|
|
||||||
assert_eq!(doc, "/* 1\n2\n3 */");
|
// assert_eq!(doc, "/* 1\n2\n3 */");
|
||||||
|
|
||||||
// uncomment
|
// // uncomment
|
||||||
let selection = Selection::single(0, doc.len_chars());
|
// let selection = Selection::single(0, doc.len_chars());
|
||||||
let transaction = toggle_block_comments(&doc, &selection, &[BlockCommentToken::default()]);
|
// let transaction = toggle_block_comments(&doc, &selection, &[BlockCommentToken::default()]);
|
||||||
transaction.apply(&mut doc);
|
// transaction.apply(&mut doc);
|
||||||
assert_eq!(doc, "1\n2\n3");
|
// assert_eq!(doc, "1\n2\n3");
|
||||||
|
|
||||||
// don't panic when there is just a space in comment
|
// // don't panic when there is just a space in comment
|
||||||
doc = Rope::from("/* */");
|
// doc = Rope::from("/* */");
|
||||||
let selection = Selection::single(0, doc.len_chars());
|
// let selection = Selection::single(0, doc.len_chars());
|
||||||
let transaction = toggle_block_comments(&doc, &selection, &[BlockCommentToken::default()]);
|
// let transaction = toggle_block_comments(&doc, &selection, &[BlockCommentToken::default()]);
|
||||||
transaction.apply(&mut doc);
|
// transaction.apply(&mut doc);
|
||||||
assert_eq!(doc, "");
|
// assert_eq!(doc, "");
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Test, if `get_comment_tokens` works, even if the content of the file includes chars, whose
|
// /// Test, if `get_comment_tokens` works, even if the content of the file includes chars, whose
|
||||||
/// byte size unequal the amount of chars
|
// /// byte size unequal the amount of chars
|
||||||
#[test]
|
// #[test]
|
||||||
fn test_get_comment_with_char_boundaries() {
|
// fn test_get_comment_with_char_boundaries() {
|
||||||
let rope = Rope::from("··");
|
// let rope = Rope::from("··");
|
||||||
let tokens = ["//", "///"];
|
// let tokens = ["//", "///"];
|
||||||
|
|
||||||
assert_eq!(
|
// assert_eq!(
|
||||||
super::get_comment_token(rope.slice(..), tokens.as_slice(), 0),
|
// super::get_comment_token(rope.slice(..), tokens.as_slice(), 0),
|
||||||
None
|
// None
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Test for `get_comment_token`.
|
// /// Test for `get_comment_token`.
|
||||||
///
|
// ///
|
||||||
/// Assuming the comment tokens are stored as `["///", "//"]`, `get_comment_token` should still
|
// /// Assuming the comment tokens are stored as `["///", "//"]`, `get_comment_token` should still
|
||||||
/// return `///` instead of `//` if the user is in a doc-comment section.
|
// /// return `///` instead of `//` if the user is in a doc-comment section.
|
||||||
#[test]
|
// #[test]
|
||||||
fn test_use_longest_comment() {
|
// fn test_use_longest_comment() {
|
||||||
let text = Rope::from(" /// amogus");
|
// let text = Rope::from(" /// amogus");
|
||||||
let tokens = ["///", "//"];
|
// let tokens = ["///", "//"];
|
||||||
|
|
||||||
assert_eq!(
|
// assert_eq!(
|
||||||
super::get_comment_token(text.slice(..), tokens.as_slice(), 0),
|
// super::get_comment_token(text.slice(..), tokens.as_slice(), 0),
|
||||||
Some("///")
|
// Some("///")
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
|
@ -1095,7 +1095,7 @@ thread_local! {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Syntax {
|
pub struct Syntax {
|
||||||
pub layers: HopSlotMap<LayerId, LanguageLayer>,
|
pub layers: HopSlotMap<LayerId, LanguageLayer>,
|
||||||
root: LayerId,
|
root: LayerId,
|
||||||
|
@ -1561,7 +1561,7 @@ impl Syntax {
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Flags that track the status of a layer
|
/// Flags that track the status of a layer
|
||||||
/// in the `Sytaxn::update` function
|
/// in the `Sytaxn::update` function
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
struct LayerUpdateFlags : u32{
|
struct LayerUpdateFlags : u32{
|
||||||
const MODIFIED = 0b001;
|
const MODIFIED = 0b001;
|
||||||
const MOVED = 0b010;
|
const MOVED = 0b010;
|
||||||
|
@ -1569,7 +1569,7 @@ bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LanguageLayer {
|
pub struct LanguageLayer {
|
||||||
// mode
|
// mode
|
||||||
// grammar
|
// grammar
|
||||||
|
|
|
@ -20,7 +20,8 @@ pub use typed::*;
|
||||||
use helix_core::{
|
use helix_core::{
|
||||||
char_idx_at_visual_offset,
|
char_idx_at_visual_offset,
|
||||||
chars::char_is_word,
|
chars::char_is_word,
|
||||||
command_line, comment,
|
command_line,
|
||||||
|
comment::{self, DEFAULT_COMMENT_TOKEN},
|
||||||
doc_formatter::TextFormat,
|
doc_formatter::TextFormat,
|
||||||
encoding, find_workspace,
|
encoding, find_workspace,
|
||||||
graphemes::{self, next_grapheme_boundary},
|
graphemes::{self, next_grapheme_boundary},
|
||||||
|
@ -61,6 +62,7 @@ use crate::{
|
||||||
compositor::{self, Component, Compositor},
|
compositor::{self, Component, Compositor},
|
||||||
filter_picker_entry,
|
filter_picker_entry,
|
||||||
job::Callback,
|
job::Callback,
|
||||||
|
keymap::default,
|
||||||
ui::{self, overlay::overlaid, Picker, PickerColumn, Popup, Prompt, PromptEvent},
|
ui::{self, overlay::overlaid, Picker, PickerColumn, Popup, Prompt, PromptEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5089,51 +5091,63 @@ pub fn completion(cx: &mut Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// comments
|
// comments
|
||||||
type CommentTransactionFn = Box<
|
// type CommentTransactionFn =
|
||||||
|
// Box<dyn FnMut(&Rope, &Selection, comment::GetCommentTokens) -> Transaction>;
|
||||||
|
|
||||||
|
pub type CommentTransactionFn<'a> = Box<
|
||||||
dyn FnMut(
|
dyn FnMut(
|
||||||
Option<&str>,
|
Option<&str>,
|
||||||
Option<&[BlockCommentToken]>,
|
Option<&[BlockCommentToken]>,
|
||||||
&Rope,
|
&Rope,
|
||||||
&Selection,
|
&Selection,
|
||||||
comment::InjectedTokens,
|
comment::GetCommentTokens<'a>,
|
||||||
) -> Transaction,
|
) -> Transaction
|
||||||
|
+ 'a,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
fn toggle_comments_impl(cx: &mut Context, mut comment_transaction: CommentTransactionFn) {
|
fn toggle_comments_impl<'a>(
|
||||||
|
cx: &'a mut Context,
|
||||||
|
mut comment_transaction: CommentTransactionFn<'a>,
|
||||||
|
) {
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
let line_token: Option<&str> = doc
|
|
||||||
|
let rope = doc.text();
|
||||||
|
let selection = doc.selection(view.id);
|
||||||
|
|
||||||
|
// The default comment tokens to fallback to if no comment tokens are found for the injection layer.
|
||||||
|
let doc_line_token: Option<&str> = doc
|
||||||
.language_config()
|
.language_config()
|
||||||
.and_then(|lc| lc.comment_tokens.as_ref())
|
.and_then(|lc| lc.comment_tokens.as_ref())
|
||||||
.and_then(|tc| tc.first())
|
.and_then(|tc| tc.first())
|
||||||
.map(|tc| tc.as_str());
|
.map(|tc| tc.as_str());
|
||||||
let block_tokens: Option<&[BlockCommentToken]> = doc
|
let doc_block_tokens: Option<&[BlockCommentToken]> = doc
|
||||||
.language_config()
|
.language_config()
|
||||||
.and_then(|lc| lc.block_comment_tokens.as_ref())
|
.and_then(|lc| lc.block_comment_tokens.as_ref())
|
||||||
.map(|tc| &tc[..]);
|
.map(|tc| &tc[..]);
|
||||||
|
|
||||||
let syntax = doc.syntax();
|
let syntax = doc.syntax().cloned();
|
||||||
let rope = doc.text().slice(..);
|
|
||||||
|
|
||||||
let transaction = comment_transaction(
|
let transaction = comment_transaction(
|
||||||
line_token,
|
doc_line_token,
|
||||||
block_tokens,
|
doc_block_tokens,
|
||||||
doc.text(),
|
rope,
|
||||||
doc.selection(view.id),
|
selection,
|
||||||
Box::new(|range: Range| {
|
Box::new(move |start: usize, end: usize| {
|
||||||
let mut best_fit = None;
|
let mut best_fit = None;
|
||||||
let mut min_gap = usize::MAX;
|
let mut min_gap = usize::MAX;
|
||||||
|
|
||||||
// TODO: improve performance of this
|
// TODO: improve performance of this
|
||||||
if let Some(syntax) = syntax {
|
if let Some(syntax) = &syntax {
|
||||||
for (layer_id, layer) in syntax.layers {
|
for (layer_id, layer) in &syntax.layers {
|
||||||
for ts_range in layer.ranges {
|
for ts_range in &layer.ranges {
|
||||||
let (start, end) = range.into_byte_range(rope);
|
// let (start, end) = range.into_byte_range(rope);
|
||||||
let is_encompassing =
|
let is_encompassing =
|
||||||
ts_range.start_byte <= start && ts_range.end_byte >= end;
|
ts_range.start_byte <= start && ts_range.end_byte >= end;
|
||||||
if is_encompassing {
|
if is_encompassing {
|
||||||
let this_gap = ts_range.end_byte - ts_range.start_byte;
|
let this_gap = ts_range.end_byte - ts_range.start_byte;
|
||||||
if this_gap < min_gap {
|
if this_gap < min_gap {
|
||||||
best_fit = Some(layer_id);
|
best_fit = Some(layer_id);
|
||||||
|
min_gap = this_gap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5141,7 +5155,10 @@ fn toggle_comments_impl(cx: &mut Context, mut comment_transaction: CommentTransa
|
||||||
|
|
||||||
if let Some(best_fit) = best_fit {
|
if let Some(best_fit) = best_fit {
|
||||||
let config = syntax.layer_config(best_fit);
|
let config = syntax.layer_config(best_fit);
|
||||||
return (config.comment_tokens, config.block_comment_tokens);
|
return (
|
||||||
|
config.comment_tokens.clone(),
|
||||||
|
config.block_comment_tokens.clone(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5153,7 +5170,7 @@ fn toggle_comments_impl(cx: &mut Context, mut comment_transaction: CommentTransa
|
||||||
exit_select_mode(cx);
|
exit_select_mode(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// commenting behavior:
|
/// commenting behavior, for each line in selection:
|
||||||
/// 1. only line comment tokens -> line comment
|
/// 1. only line comment tokens -> line comment
|
||||||
/// 2. each line block commented -> uncomment all lines
|
/// 2. each line block commented -> uncomment all lines
|
||||||
/// 3. whole selection block commented -> uncomment selection
|
/// 3. whole selection block commented -> uncomment selection
|
||||||
|
@ -5162,92 +5179,132 @@ fn toggle_comments_impl(cx: &mut Context, mut comment_transaction: CommentTransa
|
||||||
fn toggle_comments(cx: &mut Context) {
|
fn toggle_comments(cx: &mut Context) {
|
||||||
toggle_comments_impl(
|
toggle_comments_impl(
|
||||||
cx,
|
cx,
|
||||||
Box::new(|line_token, block_tokens, doc, selection, lol_fn| {
|
Box::new(
|
||||||
let text = doc.slice(..);
|
|doc_line_token, doc_block_tokens, doc, selection, mut get_comment_tokens| {
|
||||||
|
let text = doc.slice(..);
|
||||||
|
|
||||||
// only have line comment tokens
|
Transaction::change_by_selection(doc, selection, |range| {
|
||||||
if line_token.is_some() && block_tokens.is_none() {
|
let (injected_line_tokens, injected_block_tokens) =
|
||||||
return comment::toggle_line_comments(doc, selection, line_token, lol_fn);
|
get_comment_tokens(range.from(), range.to());
|
||||||
}
|
|
||||||
|
|
||||||
let split_lines = comment::split_lines_of_selection(text, selection);
|
let line_token = injected_line_tokens
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|lt| lt.first())
|
||||||
|
.map(|lt| lt.as_str())
|
||||||
|
.unwrap_or(doc_line_token.unwrap_or(DEFAULT_COMMENT_TOKEN));
|
||||||
|
|
||||||
let default_block_tokens = &[BlockCommentToken::default()];
|
let default_block_tokens = &[BlockCommentToken::default()];
|
||||||
let block_comment_tokens = block_tokens.unwrap_or(default_block_tokens);
|
|
||||||
|
|
||||||
let (line_commented, line_comment_changes) =
|
let block_tokens = injected_block_tokens
|
||||||
comment::find_block_comments(block_comment_tokens, text, &split_lines);
|
.as_deref()
|
||||||
|
.unwrap_or(doc_block_tokens.unwrap_or(default_block_tokens));
|
||||||
|
|
||||||
// block commented by line would also be block commented so check this first
|
log::error!("{line_token:?}, {block_tokens:?}");
|
||||||
if line_commented {
|
|
||||||
return comment::create_block_comment_transaction(
|
|
||||||
doc,
|
|
||||||
&split_lines,
|
|
||||||
line_commented,
|
|
||||||
line_comment_changes,
|
|
||||||
)
|
|
||||||
.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (block_commented, comment_changes) =
|
todo!();
|
||||||
comment::find_block_comments(block_comment_tokens, text, selection);
|
|
||||||
|
|
||||||
// check if selection has block comments
|
// if line_tokens.is_some() && block_tokens.is_none() {
|
||||||
if block_commented {
|
|
||||||
return comment::create_block_comment_transaction(
|
|
||||||
doc,
|
|
||||||
selection,
|
|
||||||
block_commented,
|
|
||||||
comment_changes,
|
|
||||||
)
|
|
||||||
.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// not commented and only have block comment tokens
|
// }
|
||||||
if line_token.is_none() && block_tokens.is_some() {
|
});
|
||||||
return comment::create_block_comment_transaction(
|
|
||||||
doc,
|
|
||||||
&split_lines,
|
|
||||||
line_commented,
|
|
||||||
line_comment_changes,
|
|
||||||
)
|
|
||||||
.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// not block commented at all and don't have any tokens
|
// // only have line comment tokens
|
||||||
comment::toggle_line_comments(doc, selection, line_token, lol_fn)
|
// if line_token.is_some() && block_tokens.is_none() {
|
||||||
}),
|
// return comment::toggle_line_comments(
|
||||||
|
// doc,
|
||||||
|
// selection,
|
||||||
|
// line_token,
|
||||||
|
// get_comment_tokens,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
todo!();
|
||||||
|
|
||||||
|
// let split_lines = comment::split_lines_of_selection(text, selection);
|
||||||
|
|
||||||
|
// let default_block_tokens = &[BlockCommentToken::default()];
|
||||||
|
// let block_comment_tokens = block_tokens.unwrap_or(default_block_tokens);
|
||||||
|
|
||||||
|
// let (line_commented, line_comment_changes) =
|
||||||
|
// comment::find_block_comments(block_comment_tokens, text, &split_lines);
|
||||||
|
|
||||||
|
// // block commented by line would also be block commented so check this first
|
||||||
|
// if line_commented {
|
||||||
|
// return comment::create_block_comment_transaction(
|
||||||
|
// doc,
|
||||||
|
// &split_lines,
|
||||||
|
// line_commented,
|
||||||
|
// line_comment_changes,
|
||||||
|
// )
|
||||||
|
// .0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let (block_commented, comment_changes) =
|
||||||
|
// comment::find_block_comments(block_comment_tokens, text, selection);
|
||||||
|
|
||||||
|
// // check if selection has block comments
|
||||||
|
// if block_commented {
|
||||||
|
// return comment::create_block_comment_transaction(
|
||||||
|
// doc,
|
||||||
|
// selection,
|
||||||
|
// block_commented,
|
||||||
|
// comment_changes,
|
||||||
|
// )
|
||||||
|
// .0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // not commented and only have block comment tokens
|
||||||
|
// if line_token.is_none() && block_tokens.is_some() {
|
||||||
|
// return comment::create_block_comment_transaction(
|
||||||
|
// doc,
|
||||||
|
// &split_lines,
|
||||||
|
// line_commented,
|
||||||
|
// line_comment_changes,
|
||||||
|
// )
|
||||||
|
// .0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // not block commented at all and don't have any tokens
|
||||||
|
// comment::toggle_line_comments(doc, selection, line_token, lol_fn)
|
||||||
|
},
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_line_comments(cx: &mut Context) {
|
fn toggle_line_comments(cx: &mut Context) {
|
||||||
toggle_comments_impl(cx, |line_token, block_tokens, doc, selection| {
|
toggle_comments_impl(
|
||||||
todo!();
|
cx,
|
||||||
// if line_token.is_none() && block_tokens.is_some() {
|
Box::new(|a, b, doc, selection, comment_fn| {
|
||||||
// let default_block_tokens = &[BlockCommentToken::default()];
|
todo!();
|
||||||
// let block_comment_tokens = block_tokens.unwrap_or(default_block_tokens);
|
// if line_token.is_none() && block_tokens.is_some() {
|
||||||
// comment::toggle_block_comments(
|
// let default_block_tokens = &[BlockCommentToken::default()];
|
||||||
// doc,
|
// let block_comment_tokens = block_tokens.unwrap_or(default_block_tokens);
|
||||||
// &comment::split_lines_of_selection(doc.slice(..), selection),
|
// comment::toggle_block_comments(
|
||||||
// block_comment_tokens,
|
// doc,
|
||||||
// )
|
// &comment::split_lines_of_selection(doc.slice(..), selection),
|
||||||
// } else {
|
// block_comment_tokens,
|
||||||
// comment::toggle_line_comments(doc, selection, line_token)
|
// )
|
||||||
// }
|
// } else {
|
||||||
});
|
// comment::toggle_line_comments(doc, selection, line_token)
|
||||||
|
// }
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_block_comments(cx: &mut Context) {
|
fn toggle_block_comments(cx: &mut Context) {
|
||||||
toggle_comments_impl(cx, |line_token, block_tokens, doc, selection| {
|
toggle_comments_impl(
|
||||||
todo!();
|
cx,
|
||||||
// if line_token.is_some() && block_tokens.is_none() {
|
Box::new(|a, b, doc, selection, comment_fn| {
|
||||||
// comment::toggle_line_comments(doc, selection, line_token)
|
todo!();
|
||||||
// } else {
|
// if line_token.is_some() && block_tokens.is_none() {
|
||||||
// let default_block_tokens = &[BlockCommentToken::default()];
|
// comment::toggle_line_comments(doc, selection, line_token)
|
||||||
// let block_comment_tokens = block_tokens.unwrap_or(default_block_tokens);
|
// } else {
|
||||||
// comment::toggle_block_comments(doc, selection, block_comment_tokens)
|
// let default_block_tokens = &[BlockCommentToken::default()];
|
||||||
// }
|
// let block_comment_tokens = block_tokens.unwrap_or(default_block_tokens);
|
||||||
});
|
// comment::toggle_block_comments(doc, selection, block_comment_tokens)
|
||||||
|
// }
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotate_selections(cx: &mut Context, direction: Direction) {
|
fn rotate_selections(cx: &mut Context, direction: Direction) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue