diff --git a/packages/bruno-app/src/components/CodeEditor/index.js b/packages/bruno-app/src/components/CodeEditor/index.js index b822babcb..71cd3b901 100644 --- a/packages/bruno-app/src/components/CodeEditor/index.js +++ b/packages/bruno-app/src/components/CodeEditor/index.js @@ -8,7 +8,7 @@ import React from 'react'; import { isEqual, escapeRegExp } from 'lodash'; import { getEnvironmentVariables } from 'utils/collections'; -import { defineCodeMirrorBrunoVariablesMode } from 'utils/common/codemirror'; +import { defineCodeMirrorBrunoVariablesMode, toggleComment } from 'utils/common/codemirror'; import StyledWrapper from './StyledWrapper'; import jsonlint from 'jsonlint'; import { JSHINT } from 'jshint'; @@ -189,32 +189,8 @@ export default class CodeEditor extends React.Component { 'Cmd-Y': 'foldAll', 'Ctrl-I': 'unfoldAll', 'Cmd-I': 'unfoldAll', - 'Cmd-/': (cm) => { - // comment/uncomment every selected line(s) - const selections = cm.listSelections(); - selections.forEach((range) => { - for (let i = range.from().line; i <= range.to().line; i++) { - const selectedLine = cm.getLine(i); - // if commented line, remove comment - if (selectedLine.trim().startsWith('//')) { - cm.replaceRange( - selectedLine.replace(/^(\s*)\/\/\s?/, '$1'), - { line: i, ch: 0 }, - { line: i, ch: selectedLine.length } - ); - continue; - } - // otherwise add comment - cm.replaceRange( - selectedLine.search(/\S|$/) >= TAB_SIZE - ? ' '.repeat(TAB_SIZE) + '// ' + selectedLine.trim() - : '// ' + selectedLine, - { line: i, ch: 0 }, - { line: i, ch: selectedLine.length } - ); - } - }); - } + 'Cmd-/': toggleComment, + 'Ctrl-/': toggleComment }, foldOptions: { widget: (from, to) => { diff --git a/packages/bruno-app/src/utils/common/codemirror.js b/packages/bruno-app/src/utils/common/codemirror.js index cbb1a2b3a..ff233ab0a 100644 --- a/packages/bruno-app/src/utils/common/codemirror.js +++ b/packages/bruno-app/src/utils/common/codemirror.js @@ -159,3 +159,54 @@ export const getCodeMirrorModeBasedOnContentType = (contentType, body) => { return 'application/text'; } }; + +/** key-binding-logic 'Ctrl-/' and 'Cmd-/' */ +export const toggleComment = (cm) => { + const selections = cm.listSelections(); + // updates DOM structure after performing operation. + cm.operation(() => { + for (const range of selections) { + const from = Math.min(range.from().line, range.to().line); + const to = Math.max(range.from().line, range.to().line); + + let allCommented = true; + let minIndent = Infinity; + + // First pass: check if all lines are commented and find min indent + for (let i = from; i <= to; i++) { + const line = cm.getLine(i); + const trimmed = line.trim(); + if (!trimmed) continue; + + const indent = line.length - trimmed.length; + minIndent = Math.min(minIndent, indent); + + if (!trimmed.startsWith('//')) { + allCommented = false; + if (minIndent === 0) break; // No need to continue if we found a non-commented line and minIndent is 0 + } + } + + // Second pass: toggle comments + for (let i = from; i <= to; i++) { + const line = cm.getLine(i); + const trimmed = line.trim(); + if (!trimmed) continue; + + if (allCommented) { + // Remove comment + cm.replaceRange( + line.replace(/^(\s*)\/\/\s?/, '$1'), + { line: i, ch: 0 }, + { line: i } + ); + } else { + // Add comment + const commentPrefix = ' '.repeat(minIndent) + '// '; + const commentedLine = commentPrefix + line.slice(minIndent); + cm.replaceRange(commentedLine, { line: i, ch: 0 }, { line: i }); + } + } + } + }); +}; \ No newline at end of file