feat: enhance frontmatter lists handling and styling for YAML fields

This commit is contained in:
Vadim Melnicuk
2026-02-23 08:38:37 +00:00
parent c4cb2a90a2
commit 1bf633e98f
6 changed files with 463 additions and 39 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
import { EditorState, Compartment, Transaction, StateEffect, StateField, RangeSetBuilder } from '@codemirror/state';
import { EditorView, keymap, highlightActiveLine, lineNumbers, highlightActiveLineGutter, scrollPastEnd, Decoration } from '@codemirror/view';
import { defaultKeymap, history, historyKeymap, indentWithTab, indentLess, undo, redo } from '@codemirror/commands';
import { defaultKeymap, history, historyKeymap, indentMore, indentLess, undo, redo } from '@codemirror/commands';
import { markdown, markdownKeymap, markdownLanguage } from '@codemirror/lang-markdown';
import { indentUnit, syntaxHighlighting, syntaxTree, forceParsing } from '@codemirror/language';
import { highlightStyle } from './theme';
@@ -366,7 +366,7 @@ export function createEditor({
EditorState.tabSize.of(4),
indentUnit.of(' '),
keymap.of([
{ key: 'Tab', run: (view) => indentListByTwoSpaces(view) || indentWithTab(view) },
{ key: 'Tab', run: (view) => indentListByTwoSpaces(view) || indentMore(view) },
{ key: 'Shift-Tab', run: (view) => outdentListByTwoSpaces(view) || indentLess(view) },
{ key: 'Backspace', run: deleteBackwardSmart },
{
+110 -8
View File
@@ -16,6 +16,14 @@ export function isThematicBreakLine(lineText) {
return thematicBreakRe.test(lineText);
}
export function isInsideFrontmatter(frontmatter, pos) {
return Boolean(frontmatter && pos >= frontmatter.from && pos < frontmatter.to);
}
export function isInsideFrontmatterContent(frontmatter, pos) {
return Boolean(frontmatter && pos >= frontmatter.contentFrom && pos < frontmatter.contentTo);
}
export function parseFrontmatter(state) {
const { doc } = state;
const cached = frontmatterCache.get(doc);
@@ -76,6 +84,92 @@ export const sourceFrontmatterField = StateField.define({
const sourceFrontmatterContentLineDeco = Decoration.line({ class: 'meo-md-frontmatter-line meo-md-frontmatter-content' });
const sourceFrontmatterDelimiterLineDeco = Decoration.line({ class: 'meo-md-frontmatter-delimiter-line' });
const sourceFrontmatterKeyDeco = Decoration.mark({ class: 'meo-md-frontmatter-key' });
const sourceFrontmatterValueDeco = Decoration.mark({ class: 'meo-md-frontmatter-value' });
export function yamlFrontmatterFieldOffsets(lineText) {
let offset = 0;
while (offset < lineText.length && (lineText[offset] === ' ' || lineText[offset] === '\t')) {
offset += 1;
}
if (lineText[offset] === '-' && /\s/.test(lineText[offset + 1] ?? '')) {
offset += 1;
while (offset < lineText.length && (lineText[offset] === ' ' || lineText[offset] === '\t')) {
offset += 1;
}
}
if (offset >= lineText.length || lineText[offset] === '#') {
return null;
}
const colonOffset = lineText.indexOf(':', offset);
if (colonOffset < 0) {
return null;
}
let keyEndOffset = colonOffset;
while (keyEndOffset > offset && (lineText[keyEndOffset - 1] === ' ' || lineText[keyEndOffset - 1] === '\t')) {
keyEndOffset -= 1;
}
if (keyEndOffset <= offset) {
return null;
}
let valueStartOffset = colonOffset + 1;
while (
valueStartOffset < lineText.length &&
(lineText[valueStartOffset] === ' ' || lineText[valueStartOffset] === '\t')
) {
valueStartOffset += 1;
}
return {
keyFromOffset: offset,
keyToOffset: colonOffset + 1,
valueFromOffset: valueStartOffset < lineText.length ? valueStartOffset : null
};
}
function frontmatterContentLineRange(state, frontmatter) {
if (!frontmatter || frontmatter.contentTo <= frontmatter.contentFrom) {
return null;
}
return {
startLineNo: state.doc.lineAt(frontmatter.contentFrom).number,
endLineNo: state.doc.lineAt(frontmatter.contentTo - 1).number
};
}
export function forEachFrontmatterContentLine(state, frontmatter, callback) {
const range = frontmatterContentLineRange(state, frontmatter);
if (!range) {
return;
}
for (let lineNo = range.startLineNo; lineNo <= range.endLineNo; lineNo += 1) {
callback(state.doc.line(lineNo));
}
}
export function forEachYamlFrontmatterField(state, frontmatter, callback) {
forEachFrontmatterContentLine(state, frontmatter, (line) => {
const offsets = yamlFrontmatterFieldOffsets(line.text);
if (!offsets) {
return;
}
callback({
line,
keyFrom: line.from + offsets.keyFromOffset,
keyTo: line.from + offsets.keyToOffset,
valueFrom: offsets.valueFromOffset === null ? null : line.from + offsets.valueFromOffset,
valueTo: line.to
});
});
}
function buildSourceFrontmatterDecorations(state) {
const builder = new RangeSetBuilder();
@@ -87,15 +181,23 @@ function buildSourceFrontmatterDecorations(state) {
const openingLine = state.doc.lineAt(frontmatter.openingFrom);
builder.add(openingLine.from, openingLine.from, sourceFrontmatterDelimiterLineDeco);
const contentStartLineNo = state.doc.lineAt(frontmatter.contentFrom).number;
const contentEndLineNo = frontmatter.contentTo > frontmatter.contentFrom
? state.doc.lineAt(frontmatter.contentTo - 1).number
: contentStartLineNo - 1;
for (let lineNo = contentStartLineNo; lineNo <= contentEndLineNo; lineNo++) {
const line = state.doc.line(lineNo);
forEachFrontmatterContentLine(state, frontmatter, (line) => {
builder.add(line.from, line.from, sourceFrontmatterContentLineDeco);
}
const offsets = yamlFrontmatterFieldOffsets(line.text);
if (!offsets) {
return;
}
builder.add(line.from + offsets.keyFromOffset, line.from + offsets.keyToOffset, sourceFrontmatterKeyDeco);
if (offsets.valueFromOffset !== null) {
const valueFrom = line.from + offsets.valueFromOffset;
if (valueFrom < line.to) {
builder.add(valueFrom, line.to, sourceFrontmatterValueDeco);
}
}
});
const closingLine = state.doc.lineAt(frontmatter.closingFrom);
builder.add(closingLine.from, closingLine.from, sourceFrontmatterDelimiterLineDeco);
+9
View File
@@ -1,6 +1,7 @@
import { StateField, RangeSetBuilder } from '@codemirror/state';
import { Decoration, WidgetType, EditorView } from '@codemirror/view';
import { base02 } from '../theme';
import { parseFrontmatter, isInsideFrontmatterContent } from './frontmatter';
const sourceListMarkerDeco = Decoration.mark({ class: 'meo-md-list-prefix' });
const taskCompleteDeco = Decoration.mark({ class: 'meo-task-complete' });
@@ -61,6 +62,10 @@ function forEachSelectionLine(state, callback) {
}
}
function lineIsInFrontmatterContent(frontmatter, line) {
return isInsideFrontmatterContent(frontmatter, line.from);
}
function isListLine(lineText) {
return listItemRegex.test(lineText);
}
@@ -561,9 +566,13 @@ export function collectOrderedListRenumberChanges(state) {
function computeSourceListBorders(state) {
const stylesByLine = detectListIndentStylesByLine(state);
const frontmatter = parseFrontmatter(state);
const ranges = new RangeSetBuilder();
for (let lineNo = 1; lineNo <= state.doc.lines; lineNo += 1) {
const line = state.doc.line(lineNo);
if (lineIsInFrontmatterContent(frontmatter, line)) {
continue;
}
const lineText = state.doc.sliceString(line.from, line.to);
const style = lineIndentStyle(lineNo, stylesByLine);
const marker = listMarkerData(lineText, null, style);
+276 -20
View File
@@ -15,6 +15,15 @@ let latestWikiLinkRequestId = '';
let pendingWikiStatusRefresh = null;
const wikiStatusDebounceMs = 1000;
const vscodeEditorFontFamily = 'var(--vscode-editor-font-family)';
const largeDocThresholds = Object.freeze({
charCount: 300_000,
lineCount: 6_000,
maxLineLength: 12_000
});
const largeDocGuardNoticeMessage = 'Large document opened in Source mode for stability. You can switch to Live mode manually.';
const largeDocLiveRetryNoticeMessage = 'Large document is in Live mode (manual retry). Rendering may be slow or fail.';
const liveModeFailureNoticeMessage = 'Live mode failed to render this document. Switched to Source mode.';
const editorUpdateFailureNoticeMessage = 'Editor failed to update this document. Try reopening the file.';
const normalizeThemeLineHeight = (value, fallback) => {
if (typeof value !== 'number' || !Number.isFinite(value)) {
@@ -23,6 +32,55 @@ const normalizeThemeLineHeight = (value, fallback) => {
return Math.min(maxThemeLineHeight, Math.max(minThemeLineHeight, value));
};
const getDocumentComplexity = (text) => {
const value = typeof text === 'string' ? text : String(text ?? '');
const charCount = value.length;
if (charCount === 0) {
return {
charCount: 0,
lineCount: 0,
maxLineLength: 0,
isLarge: false
};
}
let lineCount = 1;
let currentLineLength = 0;
let maxLineLength = 0;
for (let i = 0; i < value.length; i += 1) {
const code = value.charCodeAt(i);
if (code === 13) {
maxLineLength = Math.max(maxLineLength, currentLineLength);
currentLineLength = 0;
lineCount += 1;
if (value.charCodeAt(i + 1) === 10) {
i += 1;
}
continue;
}
if (code === 10) {
maxLineLength = Math.max(maxLineLength, currentLineLength);
currentLineLength = 0;
lineCount += 1;
continue;
}
currentLineLength += 1;
}
maxLineLength = Math.max(maxLineLength, currentLineLength);
return {
charCount,
lineCount,
maxLineLength,
isLarge:
charCount >= largeDocThresholds.charCount ||
lineCount >= largeDocThresholds.lineCount ||
maxLineLength >= largeDocThresholds.maxLineLength
};
};
const applyThemeSettings = (theme) => {
const rootStyle = document.documentElement.style;
const colors = theme?.colors ?? {};
@@ -615,11 +673,80 @@ let hasLocalModePreference = false;
let findPanelVisible = false;
let pendingInitialText = null;
let initialEditorMountQueued = false;
let initialMountRecoveryAttempted = false;
let largeDocGuardActive = false;
let largeDocManualLiveOverride = false;
let lastDocumentComplexity = null;
let editorFailureNoticeMessage = '';
let editorFailureNoticeKind = 'error';
const hideSelectionMenu = () => {
selectionMenu.classList.remove('is-visible');
};
const setEditorNotice = (_message, _kind = 'info') => {};
const clearEditorNotice = () => {};
const updateEditorNotice = () => {
if (editorFailureNoticeMessage) {
setEditorNotice(editorFailureNoticeMessage, editorFailureNoticeKind);
return;
}
if (largeDocGuardActive && !largeDocManualLiveOverride && currentMode === 'source') {
setEditorNotice(largeDocGuardNoticeMessage, 'warning');
return;
}
if (largeDocGuardActive && largeDocManualLiveOverride && currentMode === 'live') {
setEditorNotice(largeDocLiveRetryNoticeMessage, 'warning');
return;
}
clearEditorNotice();
};
const setFailureNotice = (message, kind = 'error') => {
editorFailureNoticeMessage = message;
editorFailureNoticeKind = kind;
updateEditorNotice();
};
const clearFailureNotice = () => {
if (!editorFailureNoticeMessage) {
return;
}
editorFailureNoticeMessage = '';
editorFailureNoticeKind = 'error';
updateEditorNotice();
};
const updateDocumentComplexityState = (text) => {
lastDocumentComplexity = getDocumentComplexity(text);
largeDocGuardActive = lastDocumentComplexity.isLarge;
if (!largeDocGuardActive) {
largeDocManualLiveOverride = false;
}
updateEditorNotice();
return lastDocumentComplexity;
};
const logWebviewRenderError = (context, error, extra = {}) => {
const metrics = lastDocumentComplexity ?? getDocumentComplexity(getCurrentExportText());
console.error('[MEO webview] render error', {
context,
mode: currentMode,
largeDocGuardActive,
largeDocManualLiveOverride,
charCount: metrics.charCount,
lineCount: metrics.lineCount,
maxLineLength: metrics.maxLineLength,
...extra,
error
});
};
const setFindStatus = (text, isError = false) => {
findStatus.textContent = text;
findStatus.classList.toggle('is-error', isError);
@@ -776,11 +903,18 @@ const updateModeUI = () => {
}
};
const applyMode = (mode, { post = true, persist = true, userTriggered = false } = {}) => {
const applyMode = (mode, { post = true, persist = true, userTriggered = false, reason = 'user' } = {}) => {
if (mode !== 'live' && mode !== 'source') {
return;
return false;
}
if (reason === 'large-doc-guard') {
largeDocManualLiveOverride = false;
} else if (userTriggered && largeDocGuardActive) {
largeDocManualLiveOverride = mode === 'live';
}
const previousMode = currentMode;
currentMode = mode;
if (userTriggered) {
hasLocalModePreference = true;
@@ -788,7 +922,40 @@ const applyMode = (mode, { post = true, persist = true, userTriggered = false }
updateModeUI();
if (editor) {
editor.setMode(mode);
try {
editor.setMode(mode);
if (mode === 'live') {
clearFailureNotice();
}
} catch (error) {
logWebviewRenderError('applyMode', error, { requestedMode: mode, reason });
if (mode === 'live') {
setFailureNotice(liveModeFailureNoticeMessage, 'warning');
if (largeDocGuardActive) {
largeDocManualLiveOverride = false;
}
try {
editor.setMode('source');
currentMode = 'source';
updateModeUI();
updateEditorNotice();
if (post) {
vscode.postMessage({ type: 'setMode', mode: 'source' });
}
return false;
} catch (fallbackError) {
logWebviewRenderError('applyMode.fallbackSource', fallbackError, { requestedMode: mode, reason });
setFailureNotice(editorUpdateFailureNoticeMessage, 'error');
}
}
currentMode = previousMode;
updateModeUI();
updateEditorNotice();
return false;
}
}
if (persist) {
@@ -798,6 +965,54 @@ const applyMode = (mode, { post = true, persist = true, userTriggered = false }
if (post) {
vscode.postMessage({ type: 'setMode', mode });
}
updateEditorNotice();
return true;
};
const enforceLargeDocGuardMode = ({ post = true } = {}) => {
if (!largeDocGuardActive || largeDocManualLiveOverride || currentMode === 'source') {
updateEditorNotice();
return false;
}
applyMode('source', { post, persist: false, reason: 'large-doc-guard' });
updateEditorNotice();
return true;
};
const setEditorTextSafely = (text, context) => {
if (!editor) {
return false;
}
try {
editor.setText(text);
return true;
} catch (error) {
logWebviewRenderError('setText', error, { context });
if (currentMode === 'live') {
setFailureNotice(liveModeFailureNoticeMessage, 'warning');
if (largeDocGuardActive) {
largeDocManualLiveOverride = false;
}
applyMode('source', { post: true, persist: false, reason: 'render-failure' });
if (!editor) {
return false;
}
try {
editor.setText(text);
return true;
} catch (retryError) {
logWebviewRenderError('setText.retryInSource', retryError, { context });
setFailureNotice(editorUpdateFailureNoticeMessage, 'error');
return false;
}
}
setFailureNotice(editorUpdateFailureNoticeMessage, 'error');
return false;
}
};
const flushChanges = () => {
@@ -1054,19 +1269,41 @@ const mountInitialEditor = () => {
return;
}
const initialText = pendingInitialText;
pendingInitialText = null;
editor = createEditor({
parent: editorHost,
text: initialText,
initialMode: currentMode,
initialLineNumbers: lineNumbersVisible,
onApplyChanges: queueChanges,
onOpenLink: (href) => {
vscode.postMessage({ type: 'openLink', href });
},
onSelectionChange: updateSelectionMenu
});
requestWikiLinkStatuses(initialText);
try {
editor = createEditor({
parent: editorHost,
text: initialText,
initialMode: currentMode,
initialLineNumbers: lineNumbersVisible,
onApplyChanges: queueChanges,
onOpenLink: (href) => {
vscode.postMessage({ type: 'openLink', href });
},
onSelectionChange: updateSelectionMenu
});
pendingInitialText = null;
initialMountRecoveryAttempted = false;
if (currentMode === 'live') {
clearFailureNotice();
}
requestWikiLinkStatuses(initialText);
updateEditorNotice();
} catch (error) {
logWebviewRenderError('mountInitialEditor', error);
if (currentMode === 'live' && !initialMountRecoveryAttempted) {
initialMountRecoveryAttempted = true;
setFailureNotice(liveModeFailureNoticeMessage, 'warning');
if (largeDocGuardActive) {
largeDocManualLiveOverride = false;
}
applyMode('source', { post: true, persist: false, reason: 'render-failure' });
scheduleInitialEditorMount();
return;
}
setFailureNotice(editorUpdateFailureNoticeMessage, 'error');
}
};
const scheduleInitialEditorMount = () => {
@@ -1091,7 +1328,7 @@ const handleInit = (message) => {
pendingInitialText = message.text;
scheduleInitialEditorMount();
} else {
editor.setText(message.text);
setEditorTextSafely(message.text, 'init');
}
if (typeof message.autoSave === 'boolean') {
autoSaveEnabled = message.autoSave;
@@ -1117,7 +1354,11 @@ window.addEventListener('message', (event) => {
if (message.type === 'init') {
applyThemeSettings(message.theme);
initialMountRecoveryAttempted = false;
clearFailureNotice();
updateDocumentComplexityState(message.text);
const nextMode = hasLocalModePreference ? currentMode : message.mode;
const guardedMode = largeDocGuardActive && !largeDocManualLiveOverride ? 'source' : nextMode;
documentVersion = message.version;
syncedText = message.text;
pendingText = null;
@@ -1127,10 +1368,19 @@ window.addEventListener('message', (event) => {
handleInit(message);
if (hasLocalModePreference) {
applyMode(nextMode, { post: true, persist: true });
applyMode(guardedMode, {
post: true,
persist: guardedMode === nextMode,
reason: guardedMode === 'source' && guardedMode !== nextMode ? 'large-doc-guard' : 'init'
});
} else {
applyMode(nextMode, { post: false, persist: false });
applyMode(guardedMode, {
post: guardedMode !== nextMode,
persist: false,
reason: guardedMode === 'source' && guardedMode !== nextMode ? 'large-doc-guard' : 'init'
});
}
updateEditorNotice();
return;
}
@@ -1140,13 +1390,17 @@ window.addEventListener('message', (event) => {
}
if (message.type === 'docChanged' && !editor && pendingInitialText !== null) {
updateDocumentComplexityState(message.text);
documentVersion = message.version;
syncedText = message.text;
pendingInitialText = message.text;
enforceLargeDocGuardMode({ post: true });
return;
}
if (message.type === 'docChanged' && editor) {
updateDocumentComplexityState(message.text);
enforceLargeDocGuardMode({ post: true });
const incomingText = normalizeEol(message.text);
const currentText = normalizeEol(editor.getText());
const pendingNormalized = pendingText === null ? null : normalizeEol(pendingText);
@@ -1204,7 +1458,9 @@ window.addEventListener('message', (event) => {
pendingDebounce = null;
}
editor.setText(message.text);
if (!setEditorTextSafely(message.text, 'docChanged')) {
return;
}
scheduleWikiLinkStatusRefresh(message.text);
updateFindStatusSummary();
return;
+44 -9
View File
@@ -22,7 +22,13 @@ import {
} from './helpers/headingCollapse';
import { addListMarkerDecoration, listMarkerData, detectListIndentStylesByLine } from './helpers/listMarkers';
import { addTableDecorations, addTableDecorationsForLineRange, isTableDelimiterLine, parseTableInfo } from './helpers/tables';
import { parseFrontmatter, isThematicBreakLine } from './helpers/frontmatter';
import {
forEachYamlFrontmatterField,
parseFrontmatter,
isInsideFrontmatter,
isInsideFrontmatterContent,
isThematicBreakLine
} from './helpers/frontmatter';
import { isWikiLinkNode, parseWikiLinkData, getWikiLinkStatus } from './helpers/wikiLinks';
const markerDeco = Decoration.mark({ class: 'meo-md-marker' });
@@ -63,6 +69,8 @@ const lineStyleDecos = {
hrActive: Decoration.line({ class: 'meo-md-hr-active' }),
hr: Decoration.line({ class: 'meo-md-hr' })
};
const frontmatterKeyDeco = Decoration.mark({ class: 'meo-md-frontmatter-key' });
const frontmatterValueDeco = Decoration.mark({ class: 'meo-md-frontmatter-value' });
const listLineDecoCache = new Map();
const listIndentWidgetCache = new Map();
@@ -142,6 +150,12 @@ const inlineStyleDecos = {
function addFrontmatterBoundaryDecorations(builder, state, frontmatter, activeLines) {
if (frontmatter.contentTo > frontmatter.contentFrom) {
addLineClass(builder, state, frontmatter.contentFrom, frontmatter.contentTo, lineStyleDecos.frontmatterContent);
forEachYamlFrontmatterField(state, frontmatter, ({ keyFrom, keyTo, valueFrom, valueTo }) => {
addRange(builder, keyFrom, keyTo, frontmatterKeyDeco);
if (valueFrom !== null && valueFrom < valueTo) {
addRange(builder, valueFrom, valueTo, frontmatterValueDeco);
}
});
}
const boundaries = [
@@ -161,10 +175,6 @@ function addFrontmatterBoundaryDecorations(builder, state, frontmatter, activeLi
}
}
function isInsideFrontmatter(frontmatter, pos) {
return Boolean(frontmatter && pos >= frontmatter.from && pos < frontmatter.to);
}
function addThematicBreakDecorations(builder, state, from, to, activeLines) {
addLineClass(builder, state, from, to, lineStyleDecos.hr);
const lineNo = state.doc.lineAt(from).number;
@@ -458,7 +468,7 @@ function addAtxHeadingPrefixMarkers(builder, state, from, activeLines) {
addRange(builder, line.from, prefixTo, markerDeco);
}
function addListLineDecorations(builder, state, indentSelectedLines) {
function addListLineDecorations(builder, state, indentSelectedLines, frontmatter = null) {
const stylesByLine = detectListIndentStylesByLine(state);
const orderedCountsByLevel = [];
@@ -483,6 +493,14 @@ function addListLineDecorations(builder, state, indentSelectedLines) {
orderedCountsByLevel[level] = 0;
}
const inFrontmatterContent = isInsideFrontmatterContent(frontmatter, line.from);
if (inFrontmatterContent) {
// Preserve visible list markers inside YAML front matter, but avoid list-line
// layout widgets/styles that reinterpret YAML indentation as Markdown layout.
addListMarkerDecoration(builder, state, line.from, orderedDisplayIndex, style);
continue;
}
if (marker.fromOffset > 0 && (marker.indentColumns ?? 0) > 0) {
builder.push(
Decoration.replace({
@@ -692,7 +710,7 @@ function buildDecorations(state) {
addFallbackTableDecorations(ranges, state, tree, parsedTableRanges);
addSingleTildeStrikeDecorations(ranges, state, activeLines, strikeRanges);
addListLineDecorations(ranges, state, indentSelectedLines);
addListLineDecorations(ranges, state, indentSelectedLines, frontmatter);
for (const section of collapsedHeadingSections) {
addLineClass(ranges, state, section.lineFrom, section.lineTo, collapsedHeadingLineDeco);
addRange(ranges, section.collapseFrom, section.collapseTo, collapsedHeadingBodyDeco);
@@ -702,14 +720,31 @@ function buildDecorations(state) {
return result;
}
function safeBuildDecorations(state, fallback, context, extra = {}) {
try {
return buildDecorations(state);
} catch (error) {
console.error('[MEO liveMode] decoration build failed', {
context,
docLength: state.doc.length,
...extra,
error
});
return fallback;
}
}
const liveDecorationField = StateField.define({
create(state) {
return buildDecorations(state);
return safeBuildDecorations(state, Decoration.none, 'create');
},
update(decorations, transaction) {
// Recompute on every transaction so live mode stays in sync with parser updates
// that may arrive without direct doc/selection changes.
const next = buildDecorations(transaction.state);
const next = safeBuildDecorations(transaction.state, decorations, 'update', {
docChanged: transaction.docChanged,
selection: transaction.selection
});
// Guard against transient empty parse results on selection-only transactions.
if (!transaction.docChanged && isEmptyDecorationSet(next) && !isEmptyDecorationSet(decorations)) {
+22
View File
@@ -1555,3 +1555,25 @@ body {
.cm-editor.meo-mode-source .cm-line.meo-md-frontmatter-content {
color: var(--meo-color-base07) !important;
}
.cm-editor.meo-mode-live .cm-line.meo-md-frontmatter-content *,
.cm-editor.meo-mode-source .cm-line.meo-md-frontmatter-content * {
color: inherit !important;
}
.cm-editor.meo-mode-live .cm-line.meo-md-frontmatter-content .meo-md-list-marker,
.cm-editor.meo-mode-source .cm-line.meo-md-frontmatter-content .meo-md-list-marker,
.cm-editor.meo-mode-live .cm-line.meo-md-frontmatter-content .meo-md-list-prefix,
.cm-editor.meo-mode-source .cm-line.meo-md-frontmatter-content .meo-md-list-prefix {
color: var(--meo-color-base02) !important;
}
.cm-editor.meo-mode-live .cm-line.meo-md-frontmatter-content .meo-md-frontmatter-key,
.cm-editor.meo-mode-source .cm-line.meo-md-frontmatter-content .meo-md-frontmatter-key {
color: var(--meo-color-base07) !important;
}
.cm-editor.meo-mode-live .cm-line.meo-md-frontmatter-content .meo-md-frontmatter-value,
.cm-editor.meo-mode-source .cm-line.meo-md-frontmatter-content .meo-md-frontmatter-value {
color: var(--vscode-editor-foreground) !important;
}