// 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; } const spacePos = line.indexOf(" "); if (spacePos === -1) { // Not complete header return; } widgets.push( invisibleDecoration.range( from, from + spacePos + 1, ), ); }, }); return Decoration.set(widgets, true); }); }