Skip to content

Toggle comments#3047

Merged
jramosg merged 37 commits intoBetterThanTomorrow:devfrom
jramosg:toggle-comments
Feb 16, 2026
Merged

Toggle comments#3047
jramosg merged 37 commits intoBetterThanTomorrow:devfrom
jramosg:toggle-comments

Conversation

@jramosg
Copy link
Copy Markdown
Contributor

@jramosg jramosg commented Feb 13, 2026

What has changed?

  • Created calva.toggleLineComment with same keybinding as editor.action.commentLine
  • Created toggleLineCommentCommand wich is executed with calva.toggleLineComment and wraps editor.action.commentLine with the extra feature of indenting commented/uncommented lines.
  • Created integration tests

Fixes #2872

My Calva PR Checklist

I have:

  • Read How to Contribute.
  • Directed this pull request at the dev branch. (Or have specific reasons to target some other branch.)
  • Made sure I have changed the PR base branch, so that it is not published. (Sorry for the nagging.)
  • Made sure there is an issue registered with a clear problem statement that this PR addresses, (created the issue if it was not present).
    • Updated the [Unreleased] entry in CHANGELOG.md, linking the issue(s) that the PR is addressing.
  • Figured if anything about the fix warrants tests on Mac/Linux/Windows/Remote/Whatever, and either tested it there if so, or mentioned it in the PR.
  • Added to or updated docs in this branch, if appropriate
  • Tests
    • Tested the particular change
    • Figured if the change might have some side effects and tested those as well.
  • Formatted all JavaScript and TypeScript code that was changed. (use the prettier extension or run npm run prettier-format)
  • Confirmed that there are no linter warnings or errors (use the eslint extension, run npm run eslint before creating your PR, or run npm run eslint-watch to eslint as you go).

This function wraps the default comment line command to ensure that
commented lines maintain proper Clojure-aware indentation. It calculates
the necessary indent fixes after commenting and applies them to the
affected lines, improving the alignment of code structures like
association arguments.
This commit introduces a new command to toggle line comments in
Clojure files. The command is registered in the package.json and
associated with the keybinding Ctrl+/ for ease of use. This
enhancement improves the editing experience for users by allowing
quick commenting and uncommenting of lines.

Fixes BetterThanTomorrow#2872
This commit introduces a suite of integration tests for the toggle
comment feature in the editor. The tests cover various scenarios,
including commenting and uncommenting lines with correct indentation,
handling multiple cursors, and ensuring alignment in nested forms.
These tests aim to improve the reliability and correctness of the
toggle comment functionality.
@jramosg jramosg requested a review from PEZ February 13, 2026 07:28
@netlify
Copy link
Copy Markdown

netlify Bot commented Feb 13, 2026

Deploy Preview for calva-docs ready!

Name Link
🔨 Latest commit 42b36d6
🔍 Latest deploy log https://app.netlify.com/projects/calva-docs/deploys/69935d8e7ae9080008f19fcd
😎 Deploy Preview https://deploy-preview-3047--calva-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

…r behavior in edit.ts:

- Added early returns for non-Clojure/no-op cases.
- Made affected-line handling deterministic (validated + sorted line numbers).
- Simplified indent-fix edit application by applying fix.delta directly (no intermediate TextEdit array).
Introduce a new keybinding for toggling line comments that preserves
Clojure-aware indentation. This enhancement improves usability by
allowing users to comment or uncomment lines while maintaining
structural integrity in their code.
This commit introduces an interface and a function to calculate
indent fixes for lines in a document. The new functionality allows
for determining the necessary adjustments to line indentation,
facilitating better formatting and code readability.
@PEZ
Copy link
Copy Markdown
Collaborator

PEZ commented Feb 13, 2026

Thanks for doing this! We should probably be overriding the built-in comment toggle command for people who run with calva.paredit.hijackVSCodeDefaults enabled.

await new Promise((resolve) => setTimeout(resolve, 20 * pauseMs));
assert.equal(
await toggleCommentUsingActiveEditor('(defn foo []• |(println "test"))'),
'(defn foo []• |;; (println "test"))'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This breaks the structure of the document. The end result needs to be:

(defn foo []•  ;; |(println "test")•  )

There's a paredit function today which knows how to do this correctly: insertSemiColon.

@PEZ
Copy link
Copy Markdown
Collaborator

PEZ commented Feb 13, 2026

This command should to be structural, I think. It doesn't make sense with a Paredit command that breaks structure. 😄

Clarify the behavior of the Toggle Line Comment feature
to specify how it handles single selections and multi-cursor
cases, ensuring users understand the structural indentation
preservation and semicolon insertion.
@jramosg
Copy link
Copy Markdown
Contributor Author

jramosg commented Feb 13, 2026

I now use insertSemiColon for single selection lines and for multiple selection I apply editor.action.commentLine and then restore to structural clojure aware indentation


it('should uncomment a line and restore correct indentation', async () => {
assert.equal(
await toggleCommentUsingActiveEditor('(defn foo []• ;; |(println "test"))'),
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It hurts my eyes a bit with the unstructured code here. 😄 But it's good that we handle it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the uncomment case, it's testing how would be aligned after uncommenting that unstructured code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the test above is the comment case, where it throws the ) to the next line

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know. I guess I could see it as healing the broken code. 😄

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😬

@jramosg
Copy link
Copy Markdown
Contributor Author

jramosg commented Feb 13, 2026

screen-capture.webm

@PEZ
Copy link
Copy Markdown
Collaborator

PEZ commented Feb 13, 2026

I now use insertSemiColon for single selection lines and for multiple selection I apply editor.action.commentLine and then restore to structural clojure aware indentation

That's similar to what insertSemiColon does. Same day we should make both commands multi-cursor compliant! 💪

Comment thread package.json Outdated
"command": "calva.toggleLineComment",
"key": "ctrl+/",
"mac": "cmd+/",
"when": "calva:keybindingsEnabled && editorLangId == clojure && editorTextFocus && !editorReadOnly"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also check that the user wants us to highjack built-in shortcuts. There's a config for that, and prior art how to check the config from the when-expression.

@maxrothman
Copy link
Copy Markdown
Contributor

maxrothman commented Feb 15, 2026

Fixes #2872

Whoops, it was already linked 😅

Clarify the behavior of the Toggle Line Comment feature
to emphasize Clojure-aware behavior and reformatting
of enclosing forms, enhancing user understanding of
its functionality.
Enhanced the conditions for the toggle line comment command to include
the new configuration option for paredit. Added a new keybinding for
inserting a semicolon with specific conditions to improve user
experience in Clojure editing.
This commit introduces tests for the insertSemiColon function in the
paredit util. The tests verify that a semicolon is correctly inserted
at the cursor without breaking the structure, and that a newline is
added when necessary to preserve the document's structure.
Enhance the insertSemiColon function to maintain line indentation
when inserting a semicolon. This change ensures that the code
structure remains intact and improves readability.
This commit introduces unit tests for the insertSemiColon function
to ensure it behaves correctly when inserting semicolons without
breaking the structure of the code. The tests cover scenarios where
a semicolon is inserted at the cursor and where a newline is added
to preserve the structure.
…onfig

This change eliminates the normalize-newlines-at-file-end? setting
from the configuration, streamlining the formatting options and
ensuring consistency in newline handling across files.
Refactor the insertSemiColon function to enhance its behavior when
inserting semicolons. The changes ensure proper indentation and
line breaks when the insertion would disrupt the structure,
improving code formatting and readability.
@jramosg jramosg requested a review from PEZ February 15, 2026 16:19
Extract comment prefix pattern to const and use regex matching for
flexible semicolon recognition. This allows toggle comment to work
correctly with any number of leading semicolons (`;`, `;;`, `;;;`,
etc.), fixing toggles on lines starting with `;` or `;;;`.
Add a null check after calling util.getActiveTextEditor() to handle
the unlikely case where no active editor is available. This prevents
undefined behavior and makes the function more robust.
Refactored applyStructuralCommentsToSingleSelectionLines to perform all
comment insertions and structural breaks in a single atomic editor.edit()
call instead of per-line operations. This reduces intermediate document
mutations and improves correctness.

Also changed to directly import _semiColonWouldBreakStructureWhere from
paredit rather than the entire module. Cursor positions are now computed
after reformatting to account for indentation changes, fixing incorrect
cursor placement when formatting shifts line content.
Reformatting edits now share the same undo group as preceding comment
insertion/removal, enabling the entire toggle-comment operation
(comment + reformat) to be undone with a single Ctrl+Z.

Previously, reformatRanges used format.formatRange (which calls
workspace.applyEdit), creating separate undo groups. Now it uses
format.formatRangeEdits to obtain the TextEdit array, then applies
them via editor.edit() with proper undoStopBefore/undoStopAfter
coordination.

Also fixed updateLineComments to set undoStopBefore: true (necessary
for the uncomment and multi-selection paths that start undo groups).
Updated docstrings for reformatRanges, reformatEnclosingFormsForLines,
and toggleCommentsThenReformatEnclosingForms to clarify behavior.
Add documentation for updateLineComments (previously undocumented) and
update toggleLineCommentCommand docstring to accurately describe the current
implementation. Removes outdated reference to Paredit semicolon insertion and
clarifies the two code paths: structural analysis for single selections and
prefix-based toggling for multiple selections.
Update the changelog entry to explicitly state that paredit.insertSemiColon
requires both calva.paredit.hijackVSCodeDefaults to be enabled and Paredit
to be in strict mode, rather than implying it fires automatically when
typing semicolon.
Comment thread docs/site/paredit.md
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like we could make it clearer that ; is a Calva defaults binding.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you think now?

This update introduces several test cases to verify the behavior of
the toggle comment functionality when dealing with lines that have
single and triple semicolon prefixes. The tests ensure that the
toggleCommentUsingActiveEditor and toggleCommentTextUsingActiveEditor
functions correctly handle these scenarios, improving the overall
reliability of the comment toggling feature.
Update the documentation to explain how Calva protects the structure
from semi-colons in Strict mode. Enhance the description of the
`paredit.insertSemiColon` command and its default keybinding
conditions for better user understanding.
Introduce `commentPrefixPattern` and `calculateCommentPrefixRemovalEnd`
to manage leading semicolons in comments. This improves the ability to
toggle comments by accurately determining where to remove comment
prefixes, enhancing the overall functionality of the comment system.
This commit introduces a new test suite for the
stripLeadingCommentPrefix function, ensuring that
various semicolon prefixes are correctly stripped
from lines of code. The tests cover single, double,
and triple semicolon prefixes, as well as cases with
immediate following spaces and non-comment lines.
Comment thread docs/site/paredit.md Outdated
Comment on lines +50 to +51
"key": ";",
"when": "calva:keybindingsEnabled && editorLangId == clojure && editorTextFocus && paredit:keyMap == strict && !editorReadOnly && !editorHasMultipleSelections && !calva:cursorInComment"
"when": "calva:keybindingsEnabled && config.calva.paredit.hijackVSCodeDefaults && editorLangId == clojure && editorTextFocus && paredit:keyMap == strict && !editorReadOnly && !editorHasMultipleSelections && !calva:cursorInComment"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's my experience that this can diverge from what's in the maifest, so it is probably better to instruct users to use the VS Code Shortcuts editor UI to adapt the when clause.

Clarify the default keybinding for the `paredit.insertSemiColon`
command and how to customize it using the VS Code Keyboard Shortcuts
editor. This improves user understanding of the keybinding
configuration in relation to Strict mode conditions.
Copy link
Copy Markdown
Collaborator

@PEZ PEZ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Womderful stuff!

@jramosg jramosg merged commit 0ac0ec5 into BetterThanTomorrow:dev Feb 16, 2026
4 of 5 checks passed
@jramosg jramosg deleted the toggle-comments branch February 16, 2026 18:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants