From 4da270616d95822b1294d17ee9f6d00a4f25ef27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Losada=20Hern=C3=A1ndez?= Date: Fri, 27 Mar 2026 18:50:46 +0100 Subject: [PATCH] multiple cursors --- client/components/codeEditor/codeEditor.jsx | 32 ++++++++++++------- .../components/codeEditor/customHighlight.js | 7 ++-- client/components/codeEditor/customKeyMap.js | 16 ++++------ 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/client/components/codeEditor/codeEditor.jsx b/client/components/codeEditor/codeEditor.jsx index e2ccd6631..64717e546 100644 --- a/client/components/codeEditor/codeEditor.jsx +++ b/client/components/codeEditor/codeEditor.jsx @@ -11,7 +11,8 @@ import { scrollPastEnd, Decoration, ViewPlugin, - WidgetType + WidgetType, + drawSelection, } from '@codemirror/view'; import { EditorState, Compartment } from '@codemirror/state'; import { foldGutter, foldKeymap, syntaxHighlighting } from '@codemirror/language'; @@ -37,11 +38,11 @@ import { legacyCustomHighlightStyle, legacyTokenizeCustomMarkdown } from './lega const createHighlightPlugin = (renderer, tab)=>{ let tokenize; -if (tab === "brewStyles") { - tokenize = tokenizeCustomCSS; -} else { - tokenize = renderer === 'V3' ? tokenizeCustomMarkdown : legacyTokenizeCustomMarkdown; -} + if(tab === 'brewStyles') { + tokenize = tokenizeCustomCSS; + } else { + tokenize = renderer === 'V3' ? tokenizeCustomMarkdown : legacyTokenizeCustomMarkdown; + } /* eslint-disable no-restricted-syntax */ class countWidget extends WidgetType { constructor(count) { @@ -187,7 +188,9 @@ const CodeEditor = forwardRef( ...(tab !== 'brewStyles' ? [autocompleteEmoji] : []), search(), keymap.of([...defaultKeymap, foldKeymap, ...searchKeymap]), - customKeymap + customKeymap, + drawSelection(), + EditorState.allowMultipleSelections.of(true), ]; }; @@ -282,16 +285,23 @@ const CodeEditor = forwardRef( injectText : (text)=>{ const view = viewRef.current; - const { from, to } = view.state.selection.main; + const changes = view.state.selection.ranges.map((range)=>({ + from : range.from, + to : range.to, + insert : text + })); + + const newRanges = view.state.selection.ranges.map((range)=>({ + anchor : range.from + text.length + })); view.dispatch({ - changes : { from, to, insert: text }, - selection : { anchor: from + text.length }, + changes, + selection : { ranges: newRanges } }); view.focus(); }, - getCursorPosition : ()=>viewRef.current.state.selection.main.head, getScrollTop : ()=>viewRef.current.scrollDOM.scrollTop, diff --git a/client/components/codeEditor/customHighlight.js b/client/components/codeEditor/customHighlight.js index f13445720..3f62d6c9c 100644 --- a/client/components/codeEditor/customHighlight.js +++ b/client/components/codeEditor/customHighlight.js @@ -17,10 +17,9 @@ const customTags = { definitionDesc : 'definitionDesc', // .cm-definitionDesc definitionColon : 'definitionColon', // .cm-definitionColon - //CSS + //CSS - variable: 'variable', - colorMark: 'colorMark', + variable : 'variable', }; export function tokenizeCustomMarkdown(text) { @@ -237,7 +236,7 @@ export function tokenizeCustomCSS(text) { const lines = text.split('\n'); lines.forEach((lineText, lineNumber)=>{ - + if(/--[a-zA-Z0-9-_]+/gm.test(lineText)) { const varRegex =/--[a-zA-Z0-9-_]+/gm; let match; diff --git a/client/components/codeEditor/customKeyMap.js b/client/components/codeEditor/customKeyMap.js index 518248633..1c7560144 100644 --- a/client/components/codeEditor/customKeyMap.js +++ b/client/components/codeEditor/customKeyMap.js @@ -2,15 +2,13 @@ import { keymap } from '@codemirror/view'; import { undo, redo } from '@codemirror/commands'; -const insertTabAtCursor = (view) => { - const { from } = view.state.selection.main; - - view.dispatch({ - changes: { from, insert: ' ' }, - selection: { anchor: from + 1 } - }); - - return true; +const insertTabAtCursor = (view)=>{ + const { from } = view.state.selection.main; + view.dispatch({ + changes : { from, insert: ' ' }, + selection : { anchor: from + 1 } + }); + return true; }; const indentMore = (view)=>{