mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2026-06-22 09:18:39 +00:00
Merge branch 'master' of https://github.com/naturalcrit/homebrewery into add-cm-features
This commit is contained in:
@@ -17,8 +17,7 @@ import {
|
||||
crosshairCursor,
|
||||
} from '@codemirror/view';
|
||||
import { EditorState, Compartment, StateEffect, StateField } from '@codemirror/state';
|
||||
import { foldAll as foldAllCmd, unfoldAll as unfoldAllCmd, foldGutter, foldKeymap, syntaxHighlighting } from '@codemirror/language';
|
||||
import { foldEffect } from '@codemirror/language';
|
||||
import { foldAll as foldAllCmd, unfoldAll as unfoldAllCmd, foldGutter, foldKeymap, foldEffect, foldState, syntaxHighlighting } from '@codemirror/language';
|
||||
import { defaultKeymap, history, undo, redo, undoDepth, redoDepth } from '@codemirror/commands';
|
||||
import { languages } from '@codemirror/language-data';
|
||||
import { css } from '@codemirror/lang-css';
|
||||
@@ -38,8 +37,6 @@ const themes = { default: defaultCM5Theme, ...cm5Themes, darkbrewery };
|
||||
const themeCompartment = new Compartment();
|
||||
const highlightCompartment = new Compartment();
|
||||
|
||||
console.log(themes);
|
||||
|
||||
import { generalKeymap, markdownKeymap } from './customKeyMaps.js';
|
||||
import foldOnPages from './customFolding.js';
|
||||
import { customHighlightStyle, tokenizeCustomMarkdown, tokenizeCustomCSS } from './customHighlight.js';
|
||||
@@ -151,11 +148,14 @@ const CodeEditor = forwardRef(
|
||||
const editorRef = useRef(null);
|
||||
const viewRef = useRef(null);
|
||||
const docsRef = useRef({});
|
||||
const tabRef = useRef(tab);
|
||||
const prevTabRef = useRef(tab);
|
||||
|
||||
const scrollRef = useRef({});
|
||||
const foldsRef = useRef({});
|
||||
const pageMap = useRef([]);
|
||||
|
||||
const recomputePages = (doc)=>{
|
||||
if(tab !== 'brewText') return;
|
||||
const pages = [0];
|
||||
const text = doc.toString();
|
||||
let offset = 0;
|
||||
@@ -181,6 +181,14 @@ const CodeEditor = forwardRef(
|
||||
return page;
|
||||
};
|
||||
|
||||
const getFoldRanges = (state)=>{
|
||||
const folds = [];
|
||||
state.field(foldState, false)?.between(0, state.doc.length, (from, to)=>{
|
||||
folds.push({ from, to });
|
||||
});
|
||||
return folds;
|
||||
};
|
||||
|
||||
const createExtensions = ({ onChange, language, editorTheme })=>{
|
||||
const setEventListeners = EditorView.updateListener.of((update)=>{
|
||||
if(update.docChanged) {
|
||||
@@ -267,11 +275,10 @@ const CodeEditor = forwardRef(
|
||||
ticking = true;
|
||||
requestAnimationFrame(()=>{
|
||||
const top = view.scrollDOM.scrollTop;
|
||||
scrollRef.current[tabRef.current] = top;
|
||||
const block = view.lineBlockAtHeight(top);
|
||||
|
||||
const page = findPageFromPos(block.from); // CHANGED
|
||||
const page = findPageFromPos(block.from);
|
||||
onViewChange(page);
|
||||
|
||||
ticking = false;
|
||||
});
|
||||
};
|
||||
@@ -286,12 +293,23 @@ const CodeEditor = forwardRef(
|
||||
};
|
||||
}, []);
|
||||
|
||||
const restoreFolds = (view, folds)=>{
|
||||
if(!folds?.length) return;
|
||||
|
||||
view.dispatch({
|
||||
effects : folds.map((f)=>foldEffect.of(f))
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(()=>{
|
||||
const view = viewRef.current;
|
||||
if(!view) return;
|
||||
|
||||
tabRef.current = tab;
|
||||
const prevTab = prevTabRef.current;
|
||||
|
||||
foldsRef.current[prevTab] = getFoldRanges(view.state);
|
||||
|
||||
if(prevTab !== tab) {
|
||||
docsRef.current[prevTab] = view.state;
|
||||
|
||||
@@ -305,6 +323,16 @@ const CodeEditor = forwardRef(
|
||||
}
|
||||
|
||||
view.setState(nextState);
|
||||
restoreFolds(view, foldsRef.current[tab]);
|
||||
|
||||
const savedScroll = scrollRef.current[tab];
|
||||
|
||||
if(savedScroll != null) {
|
||||
requestAnimationFrame(()=>{
|
||||
view.scrollDOM.scrollTop = savedScroll;
|
||||
});
|
||||
}
|
||||
|
||||
prevTabRef.current = tab;
|
||||
}
|
||||
view.focus();
|
||||
|
||||
@@ -100,6 +100,10 @@
|
||||
vertical-align : sub;
|
||||
color : rgb(123, 123, 15);
|
||||
}
|
||||
.cm-strikethrough {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.cm-definitionList {
|
||||
.cm-definitionTerm { color : rgb(96, 117, 143); }
|
||||
.cm-definitionColon:not(:has(.cm-comment)) {
|
||||
|
||||
@@ -16,6 +16,7 @@ const customTags = {
|
||||
definitionTerm : 'definitionTerm', // .cm-definitionTerm
|
||||
definitionDesc : 'definitionDesc', // .cm-definitionDesc
|
||||
definitionColon : 'definitionColon', // .cm-definitionColon
|
||||
strikethrough : 'strikethrough', // .cm-strikethrough
|
||||
|
||||
//CSS
|
||||
|
||||
@@ -81,6 +82,23 @@ export function tokenizeCustomMarkdown(text) {
|
||||
}
|
||||
}
|
||||
|
||||
// --- Strikethrough ---
|
||||
if(/\~/.test(lineText)) {
|
||||
const strikethroughRegex = /~(?!\s)(.+?)(?<!\s)~/g;
|
||||
|
||||
let match = strikethroughRegex.exec(lineText);
|
||||
let type = customTags.strikethrough;
|
||||
|
||||
if(match) {
|
||||
tokens.push({
|
||||
line : lineNumber,
|
||||
type,
|
||||
from : match.index,
|
||||
to : match.index + match[0].length,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// --- single line def list ---
|
||||
const singleLineRegex = /^(?=.*[^:])(.+?)(\s*)(::)([^\n]*)$/dmy;
|
||||
const match = singleLineRegex.exec(lineText);
|
||||
@@ -182,13 +200,13 @@ export function tokenizeCustomMarkdown(text) {
|
||||
}
|
||||
|
||||
if(lineText.includes('{') && lineText.includes('}')) {
|
||||
const injectionRegex = /(?:^|[^{\n])({(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\2})/gm;
|
||||
const injectionRegex = /(?:^|[^{\n])({(?=((?:[:=](?:"[\w,\-()#%. ]*"|[\w\-()#%.]*)|[^"':={}\s]*)*))\2})/gmd;
|
||||
let match;
|
||||
while ((match = injectionRegex.exec(lineText)) !== null) {
|
||||
tokens.push({
|
||||
line : lineNumber,
|
||||
from : match.index,
|
||||
to : match.index + match[1].length,
|
||||
from : match.indices[1][0],
|
||||
to : match.indices[1][1],
|
||||
type : customTags.injection,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,6 +22,17 @@ async function formatCSS(view) {
|
||||
});
|
||||
}
|
||||
|
||||
const insertTab = (view) => {
|
||||
const { from, to } = view.state.selection.main;
|
||||
|
||||
view.dispatch({
|
||||
changes: { from, to, insert: ' ' },
|
||||
selection: { anchor: from + 2 }
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const indentLess = (view)=>{
|
||||
const { from, to } = view.state.selection.main;
|
||||
const lines = [];
|
||||
@@ -37,27 +48,25 @@ const indentLess = (view)=>{
|
||||
};
|
||||
|
||||
const wrapSelection = (prefix, suffix) => (view) => {
|
||||
const { from, to } = view.state.selection.main;
|
||||
const selected = view.state.doc.sliceString(from, to);
|
||||
const changes = [];
|
||||
|
||||
let text, selection;
|
||||
for(const range of view.state.selection.ranges) {
|
||||
const { from, to } = range;
|
||||
const selected = view.state.doc.sliceString(from, to);
|
||||
|
||||
if(from === to) {
|
||||
text = prefix + suffix;
|
||||
selection = { anchor: from + prefix.length, head: from + prefix.length };
|
||||
}
|
||||
else if(selected.startsWith(prefix) && selected.endsWith(suffix)) {
|
||||
text = selected.slice(prefix.length, -suffix.length);
|
||||
selection = { anchor: from, head: from + text.length };
|
||||
}
|
||||
else {
|
||||
text = `${prefix}${selected}${suffix}`;
|
||||
selection = { anchor: from, head: from + text.length };
|
||||
let text;
|
||||
|
||||
if(from === to) { text = prefix + suffix }
|
||||
else if(selected.startsWith(prefix) && selected.endsWith(suffix)) {
|
||||
text = selected.slice(prefix.length, -suffix.length);
|
||||
}
|
||||
else {text = `${prefix}${selected}${suffix}`}
|
||||
|
||||
changes.push({ from, to, insert: text });
|
||||
}
|
||||
|
||||
view.dispatch({
|
||||
changes : { from, to, insert: text },
|
||||
selection
|
||||
changes
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -181,7 +190,7 @@ const newPage = (view)=>{
|
||||
};
|
||||
|
||||
export const generalKeymap = Prec.high(keymap.of([
|
||||
{ key: 'Tab', run: indentMore },
|
||||
{ key: 'Tab', run: insertTab },
|
||||
{ key: 'Mod-z', run: undo }, //i think it may be unnecessary
|
||||
{ key: 'Mod-Shift-z', run: redo },
|
||||
{ key: 'Mod-y', run: redo },
|
||||
|
||||
Reference in New Issue
Block a user