Skip to content

Commit 3e383d9

Browse files
authored
Merge pull request #3082 from jramosg/issue-3078-toggle-comemnts-off-indent-glitch
Issue 3078 toggle comemnts off indent glitch Fixes #3078
2 parents b9641d6 + 33442da commit 3e383d9

File tree

5 files changed

+54
-5
lines changed

5 files changed

+54
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Changes to Calva.
44

55
## [Unreleased]
66

7+
- Fix: [Toggle comments off, indent glitch](https://github.com/BetterThanTomorrow/calva/issues/3078)
78
- Fix: [Clojure-lsp not starting when offline](https://github.com/BetterThanTomorrow/calva/issues/1299)
89

910
## [2.0.555] - 2026-02-19

src/comment-prefix.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
/** Matches one or more leading semicolons (`;`, `;;`, `;;;`, etc.) */
22
export const commentPrefixPattern = /^;+/;
33

4+
/**
5+
* Calculates the end index for removing a comment prefix (semicolons + trailing space)
6+
* from a line of text. Returns the index up to which characters should be removed,
7+
* accounting for the semicolon(s) and a single trailing space (or all trailing spaces
8+
* if the line is otherwise empty after the prefix).
9+
*
10+
* @param lineText - The full text of the line
11+
* @param firstNonWhitespace - The index of the first non-whitespace character in the line
12+
* @returns The end index for removal, or `undefined` if no comment prefix is found
13+
*/
414
export function calculateCommentPrefixRemovalEnd(
515
lineText: string,
616
firstNonWhitespace: number
@@ -12,8 +22,20 @@ export function calculateCommentPrefixRemovalEnd(
1222
}
1323

1424
let removalEnd = firstNonWhitespace + match[0].length;
15-
while (removalEnd < lineText.length && lineText[removalEnd] === ' ') {
16-
removalEnd++;
25+
if (removalEnd < lineText.length && lineText[removalEnd] === ' ') {
26+
let spaceRunEnd = removalEnd;
27+
// If the line is otherwise empty after the comment prefix, remove all trailing spaces as well
28+
while (spaceRunEnd < lineText.length && lineText[spaceRunEnd] === ' ') {
29+
spaceRunEnd++;
30+
}
31+
32+
// If we reached the end of the line, remove all spaces.
33+
// Otherwise, just remove one space after the comment prefix.
34+
if (spaceRunEnd === lineText.length) {
35+
removalEnd = spaceRunEnd;
36+
} else {
37+
removalEnd++;
38+
}
1739
}
1840

1941
return removalEnd;

src/edit.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ async function updateLineComments(
395395
affectedLineNumbers: number[],
396396
shouldUncomment: boolean
397397
) {
398-
const descendingLineNumbers = [...new Set(affectedLineNumbers)].sort((a, b) => b - a);
398+
const descendingLineNumbers = affectedLineNumbers.sort((a, b) => b - a);
399399

400400
await editor.edit(
401401
(editBuilder) => {

src/extension-test/integration/suite/toggle-comment-test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,24 @@ suite(suiteName, () => {
157157
);
158158
});
159159

160+
it('should preserve nested indentation when uncommenting selected multiline block (issue #3078)', async () => {
161+
assert.equal(
162+
await toggleCommentUsingActiveEditor(
163+
'|;; (a (b c•;; (d e•;; f)•;; g•;; h)•;; i•;; j)|'
164+
),
165+
'|(a (b c• (d e• f)• g• h)• i• j)|'
166+
);
167+
});
168+
169+
it('should preserve nested indentation when uncommenting selected multiline block inside defn (issue #3078)', async () => {
170+
assert.equal(
171+
await toggleCommentUsingActiveEditor(
172+
'(defn foo []• |;; (a (b c• ;; (d e• ;; f)• ;; g• ;; h)• ;; i• ;; j)|• )'
173+
),
174+
'(defn foo []• |(a (b c• (d e• f)• g• h)• i• j)|)'
175+
);
176+
});
177+
160178
it('should comment an empty line inside assoc with alignment indent (issue #2872)', async () => {
161179
assert.equal(
162180
await toggleCommentUsingActiveEditor('(assoc m• :key :val•|)'),

src/extension-test/unit/edit/comment-prefix-test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,16 @@ describe('prefix removal', () => {
2323
expect(stripLeadingCommentPrefix(' ;;; header')).toBe(' header');
2424
});
2525

26-
it('strips semicolon prefix and all immediate following spaces', () => {
27-
expect(stripLeadingCommentPrefix(';;; header')).toBe('header');
26+
it('strips semicolon prefix and one separating space before content', () => {
27+
expect(stripLeadingCommentPrefix(';;; header')).toBe(' header');
28+
});
29+
30+
it('preserves indentation spaces after comment prefix', () => {
31+
expect(stripLeadingCommentPrefix(';; h)')).toBe(' h)');
32+
});
33+
34+
it('strips fully blank commented line to empty', () => {
35+
expect(stripLeadingCommentPrefix(';; ')).toBe('');
2836
});
2937

3038
it('keeps non-comment lines unchanged', () => {

0 commit comments

Comments
 (0)