1
0

Make frontmatter foldable

This commit is contained in:
Zef Hemel 2023-12-21 19:04:54 +01:00
parent 3c3b648b79
commit 90659c9c7e
3 changed files with 31 additions and 44 deletions

View File

@ -468,6 +468,11 @@ export default function buildMarkdown(mdExtensions: MDExt[]): Language {
from: state.doc.lineAt(tree.from).to,
to: tree.to,
}),
// Fold frontmatter
FrontMatter: (tree) => ({
from: tree.from,
to: tree.to,
}),
}),
styleTags({

View File

@ -1,4 +1,4 @@
import { Decoration, EditorState, syntaxTree } from "../deps.ts";
import { Decoration, EditorState, foldedRanges, syntaxTree } from "../deps.ts";
import {
decoratorStateField,
HtmlWidget,
@ -8,6 +8,7 @@ import {
function hideNodes(state: EditorState) {
const widgets: any[] = [];
const foldRanges = foldedRanges(state);
syntaxTree(state).iterate({
enter(node) {
if (
@ -33,23 +34,36 @@ function hideNodes(state: EditorState) {
node.name === "FrontMatterMarker"
) {
const parent = node.node.parent!;
const folded = foldRanges.iter();
let shouldShowFrontmatterBanner = false;
while (folded.value) {
// Check if cursor is in the folded range
if (isCursorInRange(state, [folded.from, folded.to])) {
// console.log("Cursor is in folded area, ");
shouldShowFrontmatterBanner = true;
break;
}
folded.next();
}
if (!isCursorInRange(state, [parent.from, parent.to])) {
widgets.push(
Decoration.line({
class: "sb-line-frontmatter-outside",
}).range(node.from),
);
if (parent.from === node.from) {
// Only put this on the first line of the frontmatter
widgets.push(
Decoration.widget({
widget: new HtmlWidget(
`frontmatter`,
"sb-frontmatter-marker",
),
}).range(node.from),
);
}
shouldShowFrontmatterBanner = true;
}
if (shouldShowFrontmatterBanner && parent.from === node.from) {
// Only put this on the first line of the frontmatter
widgets.push(
Decoration.widget({
widget: new HtmlWidget(
`frontmatter`,
"sb-frontmatter-marker",
),
}).range(node.from),
);
}
}
},

View File

@ -6,7 +6,6 @@ import {
DecorationSet,
EditorState,
EditorView,
foldedRanges,
StateField,
Transaction,
WidgetType,
@ -146,34 +145,3 @@ export function isCursorInRange(state: EditorState, range: [number, number]) {
* Decoration to simply hide anything.
*/
export const invisibleDecoration = Decoration.replace({});
/**
* Returns the lines of the editor that are in the given range and not folded.
* This function is of use when you need to get the lines of a particular
* block node and add line decorations to each line of it.
*
* @param view - Editor view
* @param from - Start of the range
* @param to - End of the range
* @returns A list of line blocks that are in the range
*/
export function editorLines(view: EditorView, from: number, to: number) {
let lines = view.viewportLineBlocks.filter((block) =>
// Keep lines that are in the range
checkRangeOverlap([block.from, block.to], [from, to])
);
const folded = foldedRanges(view.state).iter();
while (folded.value) {
lines = lines.filter(
(line) =>
!checkRangeOverlap(
[folded.from, folded.to],
[line.from, line.to],
),
);
folded.next();
}
return lines;
}