@@ -12,8 +12,8 @@ use std::borrow::Cow;
1212
1313pub const DEFAULT_COMMENT_TOKEN : & str = "#" ;
1414
15- /// Returns the longest matching comment token of the given line (if it exists).
16- pub fn get_comment_token (
15+ /// Returns the longest matching line comment token of the given line (if it exists).
16+ pub fn get_line_comment_token (
1717 loader : & syntax:: Loader ,
1818 syntax : Option < & Syntax > ,
1919 text : RopeSlice ,
@@ -24,30 +24,32 @@ pub fn get_comment_token(
2424 let start = line. first_non_whitespace_char ( ) ?;
2525 let start_char = text. line_to_char ( line_num) + start;
2626
27- let injected_tokens = get_injected_tokens ( loader , syntax , start_char as u32 , start_char as u32 )
28- // we only care about line comment tokens
29- . 0
30- . and_then ( |tokens| {
31- tokens
32- . into_iter ( )
33- . filter ( |token| line. slice ( start..) . starts_with ( token) )
34- . max_by_key ( |token| token. len ( ) )
35- } ) ;
36-
37- injected_tokens . or (
38- // no comment tokens found for injection, use doc comments if exists
27+ let injected_line_comment_tokens =
28+ injected_tokens_for_range ( loader , syntax , start_char as u32 , start_char as u32 )
29+ . 0
30+ . and_then ( |tokens| {
31+ tokens
32+ . into_iter ( )
33+ . filter ( |token| line. slice ( start..) . starts_with ( token) )
34+ . max_by_key ( |token| token. len ( ) )
35+ } ) ;
36+
37+ injected_line_comment_tokens . or_else ( ||
38+ // no line comment tokens found for injection, use doc comments if exists
3939 doc_default_tokens. and_then ( |tokens| {
4040 tokens
4141 . iter ( )
4242 . filter ( |token| line. slice ( start..) . starts_with ( token) )
4343 . max_by_key ( |token| token. len ( ) )
4444 . cloned ( )
45- } ) ,
46- )
45+ } ) )
4746}
4847
49- /// Find the injection with the most tightly encompassing range.
50- pub fn get_injected_tokens (
48+ /// Get the injected line and block comment of the smallest
49+ /// injection around the range which fully includes `start..=end`.
50+ ///
51+ /// Injections that do not have any comment tokens are skipped.
52+ pub fn injected_tokens_for_range (
5153 loader : & syntax:: Loader ,
5254 syntax : Option < & Syntax > ,
5355 start : u32 ,
@@ -69,8 +71,8 @@ pub fn get_injected_tokens(
6971 // if the language does not have any comment tokens, it does not make
7072 // any sense to consider it.
7173 //
72- // This includes languages such as comment, jsdoc and regex: These
73- // languages are injected and never found in files by themselves
74+ // This includes languages such as ` comment`, ` jsdoc` and ` regex`.
75+ // These languages are injected and never found in files by themselves
7476 has_any_comment_tokens. then_some ( (
7577 lang_config. comment_tokens . clone ( ) ,
7678 lang_config. block_comment_tokens . clone ( ) ,
@@ -80,27 +82,28 @@ pub fn get_injected_tokens(
8082 . unwrap_or_default ( )
8183}
8284
83- /// Given text, a comment token, and a set of line indices, returns the following:
84- /// - Whether the given lines should be considered commented
85+ /// Given `text`, a comment `token`, and a set of line indices `lines_to_modify`,
86+ /// Returns the following:
87+ /// 1. Whether the given lines should be considered commented
8588/// - If any of the lines are uncommented, all lines are considered as such.
86- /// - The lines to change for toggling comments
89+ /// 2. The lines to change for toggling comments
8790/// - This is all provided lines excluding blanks lines.
88- /// - The column of the comment tokens
91+ /// 3. The column of the comment tokens
8992/// - Column of existing tokens, if the lines are commented; column to place tokens at otherwise.
90- /// - The margin to the right of the comment tokens
93+ /// 4. The margin to the right of the comment tokens
9194/// - Defaults to `1`. If any existing comment token is not followed by a space, changes to `0`.
9295fn find_line_comment (
9396 token : & str ,
9497 text : RopeSlice ,
95- lines : impl IntoIterator < Item = usize > ,
98+ lines_to_modify : impl IntoIterator < Item = usize > ,
9699) -> ( bool , Vec < usize > , usize , usize ) {
97100 let mut commented = true ;
98101 let mut to_change = Vec :: new ( ) ;
99102 let mut min = usize:: MAX ; // minimum col for first_non_whitespace_char
100103 let mut margin = 1 ;
101104 let token_len = token. chars ( ) . count ( ) ;
102105
103- for line in lines {
106+ for line in lines_to_modify {
104107 let line_slice = text. line ( line) ;
105108 if let Some ( pos) = line_slice. first_non_whitespace_char ( ) {
106109 let len = line_slice. len_chars ( ) ;
@@ -130,39 +133,55 @@ fn find_line_comment(
130133 ( commented, to_change, min, margin)
131134}
132135
136+ /// Returns the edits required to toggle the comment `token` for the `range` in the `doc`
133137#[ must_use]
134138pub fn toggle_line_comments ( doc : & Rope , range : & Range , token : Option < & str > ) -> Vec < Change > {
135139 let text = doc. slice ( ..) ;
136140
137141 let token = token. unwrap_or ( DEFAULT_COMMENT_TOKEN ) ;
142+
143+ // Add a space between the comment token and the line.
138144 let comment = Tendril :: from ( format ! ( "{} " , token) ) ;
139145
140- let start = text. char_to_line ( range. from ( ) ) ;
141- let end = text. char_to_line ( range. to ( ) . saturating_sub ( 1 ) ) ;
142146 let line_count = text. len_lines ( ) ;
143- let start = start. clamp ( 0 , line_count) ;
144- let end = ( end + 1 ) . min ( line_count) ;
145-
146- let mut lines = vec ! [ ] ;
147- lines. extend ( start..end) ;
148147
149- let ( was_commented, to_change, min, margin) = find_line_comment ( token, text, lines) ;
148+ let start = text. char_to_line ( range. from ( ) ) . clamp ( 0 , line_count) ;
149+ let end = ( text. char_to_line ( range. to ( ) . saturating_sub ( 1 ) ) + 1 ) . min ( line_count) ;
150150
151- let mut changes : Vec < Change > = Vec :: with_capacity ( to_change . len ( ) ) ;
151+ let lines_to_modify = start..end ;
152152
153- for line in to_change {
154- let pos = text. line_to_char ( line) + min;
153+ let (
154+ was_commented,
155+ lines_to_modify,
156+ column_to_place_comment_tokens_at,
157+ comment_tokens_right_margin,
158+ ) = find_line_comment ( token, text, lines_to_modify) ;
155159
156- if !was_commented {
157- // comment line
158- changes. push ( ( pos, pos, Some ( comment. clone ( ) ) ) ) ;
159- } else {
160- // uncomment line
161- changes. push ( ( pos, pos + token. len ( ) + margin, None ) ) ;
162- }
163- }
160+ lines_to_modify
161+ . into_iter ( )
162+ . map ( |line| {
163+ let place_comment_tokens_at =
164+ text. line_to_char ( line) + column_to_place_comment_tokens_at;
164165
165- changes
166+ if !was_commented {
167+ // comment line
168+ (
169+ place_comment_tokens_at,
170+ place_comment_tokens_at,
171+ // insert the token
172+ Some ( comment. clone ( ) ) ,
173+ )
174+ } else {
175+ // uncomment line
176+ (
177+ place_comment_tokens_at,
178+ place_comment_tokens_at + token. len ( ) + comment_tokens_right_margin,
179+ // remove the token - replace range with nothing
180+ None ,
181+ )
182+ }
183+ } )
184+ . collect ( )
166185}
167186
168187#[ derive( Debug , PartialEq , Eq ) ]
@@ -582,33 +601,5 @@ mod test {
582601 transaction. apply ( & mut doc) ;
583602 assert_eq ! ( doc, "" ) ;
584603 }
585-
586- // Test, if `get_comment_tokens` works, even if the content of the file includes chars, whose
587- // byte size unequal the amount of chars
588- // #[test]
589- // fn test_get_comment_with_char_boundaries() {
590- // let rope = Rope::from("··");
591- // let tokens = vec!["//".to_owned(), "///".to_owned()];
592-
593- // assert_eq!(
594- // super::get_comment_token(None, rope.slice(..), Some(&tokens), 0),
595- // None
596- // );
597- // }
598-
599- // /// Test for `get_comment_token`.
600- // ///
601- // /// Assuming the comment tokens are stored as `["///", "//"]`, `get_comment_token` should still
602- // /// return `///` instead of `//` if the user is in a doc-comment section.
603- // #[test]
604- // fn test_use_longest_comment() {
605- // let text = Rope::from(" /// amogus ඞ");
606- // let tokens = vec!["///".to_owned(), "//".to_owned()];
607-
608- // assert_eq!(
609- // super::get_comment_token(None, text.slice(..), Some(&tokens), 0),
610- // Some("///".to_owned())
611- // );
612- // }
613604 }
614605}
0 commit comments