diff --git a/client/components/codeEditor/codeEditor.jsx b/client/components/codeEditor/codeEditor.jsx index db2a45be9..ed8fbb6ce 100644 --- a/client/components/codeEditor/codeEditor.jsx +++ b/client/components/codeEditor/codeEditor.jsx @@ -10,6 +10,7 @@ import { scrollPastEnd, Decoration, ViewPlugin, + WidgetType, } from '@codemirror/view'; import { EditorState, Compartment } from '@codemirror/state'; import { foldGutter, foldKeymap, syntaxHighlighting, HighlightStyle } from '@codemirror/language'; @@ -97,6 +98,59 @@ const customHighlightPlugin = ViewPlugin.fromClass( }, ); +// ######################### FOLDING ############################### + + +import { foldService } from '@codemirror/language'; + +class FoldPreviewWidget extends WidgetType { + constructor(text) { + super(); + this.text = text; + } + toDOM() { + console.log(this.text); + const span = document.createElement('span'); + span.className = 'cm-fold-placeholder'; + span.textContent = this.text; + return span; + } +} + +const homebreweryFold = foldService.of((state, lineStart)=>{ + const doc = state.doc; + const matcher = /^(?=\\page(?:break)?(?: *{[^\n{}]*})?$)/m; + + const startLine = doc.lineAt(lineStart); + const prevLineText = startLine.number > 1 ? doc.line(startLine.number - 1).text : ''; + + if(startLine.number > 1 && !matcher.test(prevLineText)) return null; + + let endLine = startLine.number; + while (endLine < doc.lines && !matcher.test(doc.line(endLine + 1).text)) { + endLine++; + } + + if(endLine === startLine.number) return null; + + let preview = ''; + for (let i = startLine.number; i <= endLine; i++) { + const text = doc.line(i).text.trim(); + if(text.length > 0) { + preview = text; + break; + } + } + + if(!preview) preview = `Lines ${startLine.number}-${endLine}`; + + preview = preview.replace('{', '').trim(); + if(preview.length > 50) preview = `${preview.slice(0, 50)}...`; + preview = `↤ ${preview} ↦`; + + return { from: startLine.from, to: doc.line(endLine).to, placeholder: new FoldPreviewWidget(preview) }; +}); + // ######################### COMPONENT ############################# const CodeEditor = forwardRef( @@ -174,6 +228,7 @@ const CodeEditor = forwardRef( keymap.of(foldKeymap), foldGutter(), lineNumbers(), + homebreweryFold, themeCompartment.of(themeExtension), // 👈 key line diff --git a/client/components/codeEditor/codeEditor.less b/client/components/codeEditor/codeEditor.less index 7dc3bf0fd..f28f66140 100644 --- a/client/components/codeEditor/codeEditor.less +++ b/client/components/codeEditor/codeEditor.less @@ -24,35 +24,6 @@ font-size: 16px; } - - /* Line numbers and gutters */ - .cm-gutters { - background-color: #f0f0f0; - color: #555; - border-right: 1px solid #ddd; - } - - /* Folding gutter */ - .cm-foldGutter { - cursor: pointer; - color: grey; - font-weight: 600; - transition: background 0.1s; - - &:hover { - background: #dddddd; - } - } - - /* Active line */ - .cm-activeLine { - background-color: #f5f5f5; - } - - .cm-activeLineGutter { - background-color: #e0e0e0; - } - /* Flash animation for source moves */ .sourceMoveFlash .cm-line { animation-name: sourceMoveAnimation; diff --git a/client/components/codeEditor/fold-css.js b/client/components/codeEditor/fold-css.js deleted file mode 100644 index 06bfd96a4..000000000 --- a/client/components/codeEditor/fold-css.js +++ /dev/null @@ -1,44 +0,0 @@ -export default { - registerHomebreweryHelper : function(CodeMirror) { - CodeMirror.registerHelper('fold', 'homebrewerycss', function(cm, start) { - - // BRACE FOLDING - const startMatcher = /\{[ \t]*$/; - const endMatcher = /\}[ \t]*$/; - const activeLine = cm.getLine(start.line); - - - if(activeLine.match(startMatcher)) { - const lastLineNo = cm.lastLine(); - let end = start.line + 1; - let braceCount = 1; - - while (end < lastLineNo) { - const curLine = cm.getLine(end); - if(curLine.match(startMatcher)) braceCount++; - if(curLine.match(endMatcher)) braceCount--; - if(braceCount == 0) break; - ++end; - } - - return { - from : CodeMirror.Pos(start.line, 0), - to : CodeMirror.Pos(end, cm.getLine(end).length) - }; - } - - // @import and data-url folding - const importMatcher = /^@import.*?;/; - const dataURLMatcher = /url\(.*?data\:.*\)/; - - if(activeLine.match(importMatcher) || activeLine.match(dataURLMatcher)) { - return { - from : CodeMirror.Pos(start.line, 0), - to : CodeMirror.Pos(start.line, activeLine.length) - }; - } - - return null; - }); - } -};