1
0
silverbullet/web/cm_plugins/hide_mark.ts

107 lines
2.7 KiB
TypeScript

// Forked from https://codeberg.org/retronav/ixora
// Original author: Pranav Karawale
// License: Apache License 2.0.
import { Decoration, EditorState, syntaxTree } from "../deps.ts";
import {
checkRangeOverlap,
decoratorStateField,
invisibleDecoration,
isCursorInRange,
} from "./util.ts";
/**
* These types contain markers as child elements that can be hidden.
*/
const typesWithMarks = [
"Emphasis",
"StrongEmphasis",
"InlineCode",
"Highlight",
"Strikethrough",
];
/**
* The elements which are used as marks.
*/
const markTypes = [
"EmphasisMark",
"CodeMark",
"HighlightMark",
"StrikethroughMark",
];
/**
* Ixora hide marks plugin.
*
* This plugin allows to:
* - Hide marks when they are not in the editor selection.
*/
export function hideMarksPlugin() {
return decoratorStateField((state: EditorState) => {
const widgets: any[] = [];
let parentRange: [number, number];
syntaxTree(state).iterate({
enter: ({ type, from, to, node }) => {
if (typesWithMarks.includes(type.name)) {
// There can be a possibility that the current node is a
// child eg. a bold node in a emphasis node, so check
// for that or else save the node range
if (
parentRange &&
checkRangeOverlap([from, to], parentRange)
) {
return;
} else parentRange = [from, to];
if (isCursorInRange(state, [from, to])) return;
const innerTree = node.toTree();
innerTree.iterate({
enter({ type, from: markFrom, to: markTo }) {
// Check for mark types and push the replace
// decoration
if (!markTypes.includes(type.name)) return;
widgets.push(
invisibleDecoration.range(
from + markFrom,
from + markTo,
),
);
},
});
}
},
});
return Decoration.set(widgets, true);
});
}
// HEADINGS
export function hideHeaderMarkPlugin() {
return decoratorStateField((state) => {
const widgets: any[] = [];
syntaxTree(state).iterate({
enter: ({ type, from, to }) => {
if (!type.name.startsWith("ATXHeading")) {
return;
}
// Get the active line
const line = state.sliceDoc(from, to);
if (isCursorInRange(state, [from, to])) {
widgets.push(
Decoration.line({ class: "sb-header-inside" }).range(from),
);
return;
}
widgets.push(
invisibleDecoration.range(
from,
from + line.indexOf(" ") + 1,
),
);
},
});
return Decoration.set(widgets, true);
});
}