@@ -6,9 +6,9 @@ import * as select from './select';
66import * as printer from './printer' ;
77import { _semiColonWouldBreakStructureWhere } from './cursor-doc/paredit' ;
88import * as format from './calva-fmt/src/format' ;
9- import { calculateCommentPrefixRemovalEnd , commentPrefixPattern } from './comment-prefix' ;
9+ import { calculateCommentPrefixRemovalEnd , findCommentPrefixStart } from './comment-prefix' ;
1010
11- export { commentPrefixPattern } from './comment-prefix' ;
11+ type CandidatesMap = Map < number , number [ ] > ;
1212
1313// Relies on that `when` claus guards this from being called
1414// when the cursor is before the comment marker
@@ -58,19 +58,39 @@ function getAffectedLineNumbers(editor: vscode.TextEditor, lineCount: number): n
5858 . sort ( ( a , b ) => a - b ) ;
5959}
6060
61+ /**
62+ * Builds candidate positions where a comment prefix might start on a line:
63+ * first non-whitespace, then any selection start columns past that point.
64+ */
65+ function commentCandidatePositions (
66+ firstNonWhitespace : number ,
67+ lineNum : number ,
68+ selections ?: readonly vscode . Selection [ ]
69+ ) : number [ ] {
70+ const positions = [ firstNonWhitespace ] ;
71+ if ( selections ) {
72+ for ( const sel of selections ) {
73+ if ( sel . start . line === lineNum && sel . start . character > firstNonWhitespace ) {
74+ positions . push ( sel . start . character ) ;
75+ }
76+ }
77+ }
78+ return positions ;
79+ }
80+
6181function areAllNonEmptyTargetLinesCommented (
6282 document : vscode . TextDocument ,
63- lineNumbers : number [ ]
83+ lineNumbers : number [ ] ,
84+ candidatesMap : CandidatesMap
6485) : boolean {
6586 const nonEmptyLines = lineNumbers . filter (
6687 ( lineNum ) => ! document . lineAt ( lineNum ) . isEmptyOrWhitespace
6788 ) ;
6889 return (
6990 nonEmptyLines . length > 0 &&
7091 nonEmptyLines . every ( ( lineNum ) => {
71- const line = document . lineAt ( lineNum ) ;
72- const lineText = line . text . slice ( line . firstNonWhitespaceCharacterIndex ) ;
73- return commentPrefixPattern . test ( lineText ) ;
92+ const candidates = candidatesMap . get ( lineNum ) ?? [ ] ;
93+ return findCommentPrefixStart ( document . lineAt ( lineNum ) . text , candidates ) !== undefined ;
7494 } )
7595 ) ;
7696}
@@ -401,31 +421,38 @@ async function reformatEnclosingFormsForLines(
401421async function updateLineComments (
402422 editor : vscode . TextEditor ,
403423 affectedLineNumbers : number [ ] ,
404- shouldUncomment : boolean
424+ shouldUncomment : boolean ,
425+ candidatesMap : CandidatesMap
405426) {
406427 const descendingLineNumbers = affectedLineNumbers . sort ( ( a , b ) => b - a ) ;
407428
408429 await editor . edit (
409430 ( editBuilder ) => {
410431 for ( const lineNum of descendingLineNumbers ) {
411432 const line = editor . document . lineAt ( lineNum ) ;
412- const firstNonWhitespace = line . firstNonWhitespaceCharacterIndex ;
413433 const lineText = line . text ;
414434
415435 if ( shouldUncomment ) {
416- const removalEnd = calculateCommentPrefixRemovalEnd ( lineText , firstNonWhitespace ) ;
436+ const removalStart = findCommentPrefixStart ( lineText , candidatesMap . get ( lineNum ) ?? [ ] ) ;
437+ if ( removalStart === undefined ) {
438+ continue ;
439+ }
440+ const removalEnd = calculateCommentPrefixRemovalEnd ( lineText , removalStart ) ;
417441 if ( removalEnd === undefined ) {
418442 continue ;
419443 }
420444
421445 editBuilder . delete (
422446 new vscode . Range (
423- new vscode . Position ( lineNum , firstNonWhitespace ) ,
447+ new vscode . Position ( lineNum , removalStart ) ,
424448 new vscode . Position ( lineNum , removalEnd )
425449 )
426450 ) ;
427451 } else {
428- editBuilder . insert ( new vscode . Position ( lineNum , firstNonWhitespace ) , ';; ' ) ;
452+ editBuilder . insert (
453+ new vscode . Position ( lineNum , line . firstNonWhitespaceCharacterIndex ) ,
454+ ';; '
455+ ) ;
429456 }
430457 }
431458 } ,
@@ -444,9 +471,10 @@ async function updateLineComments(
444471async function toggleCommentsThenReformatEnclosingForms (
445472 editor : vscode . TextEditor ,
446473 affectedLineNumbers : number [ ] ,
447- shouldUncomment : boolean
474+ shouldUncomment : boolean ,
475+ candidatesMap : CandidatesMap
448476) {
449- await updateLineComments ( editor , affectedLineNumbers , shouldUncomment ) ;
477+ await updateLineComments ( editor , affectedLineNumbers , shouldUncomment , candidatesMap ) ;
450478 await reformatEnclosingFormsForLines ( editor , affectedLineNumbers ) ;
451479}
452480
@@ -475,9 +503,19 @@ export async function toggleLineCommentCommand() {
475503 return ;
476504 }
477505
506+ const candidatesMap = new Map < number , number [ ] > ( ) ;
507+ for ( const lineNum of affectedLineNumbers ) {
508+ const line = document . lineAt ( lineNum ) ;
509+ candidatesMap . set (
510+ lineNum ,
511+ commentCandidatePositions ( line . firstNonWhitespaceCharacterIndex , lineNum , editor . selections )
512+ ) ;
513+ }
514+
478515 const allNonEmptyLinesCommented = areAllNonEmptyTargetLinesCommented (
479516 document ,
480- affectedLineNumbers
517+ affectedLineNumbers ,
518+ candidatesMap
481519 ) ;
482520
483521 const isSingleSelection = editor . selections . length === 1 ;
@@ -489,7 +527,8 @@ export async function toggleLineCommentCommand() {
489527 await toggleCommentsThenReformatEnclosingForms (
490528 editor ,
491529 affectedLineNumbers ,
492- allNonEmptyLinesCommented
530+ allNonEmptyLinesCommented ,
531+ candidatesMap
493532 ) ;
494533}
495534
0 commit comments