Skip to content

Commit

Permalink
fix: re-apply windows hover preview image fix & improve hover preview…
Browse files Browse the repository at this point in the history
… performance (#2312)

* move hover preview rendering to engine

* Revert "Revert "fix(views): hover preview containing local images on Windows  (#2047)""

This reverts commit 7890c01.

* hover preview strips out frontmatter

VSCode markdown preview tries to show the frontmatter as a block of text, so just strip it out instead.

* fix performance issue & eliminate MDUtilsV4 from noteRefsV2

* Fix tests & re-add some V4/V5 compat

* remove debugger

* remove debugger

* fix type error

* fix bad snaps

* Revert "fix bad snaps"

This reverts commit 20cb523.

* use note fnames for links in tests by default

* fix snaps that change run-to-run

* remove debugger

* work around husky check

* fix test on Windows

* implement type changes
  • Loading branch information
Kaan Genç committed Feb 3, 2022
1 parent 0ad5126 commit 103655e
Show file tree
Hide file tree
Showing 33 changed files with 1,226 additions and 1,013 deletions.
26 changes: 26 additions & 0 deletions packages/common-all/src/dnode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,32 @@ export class NoteUtils {
body: opts.contents,
});
}

static FAKE_ID_PREFIX = "fake-";

static isFakeId(id: string) {
return id.startsWith(this.FAKE_ID_PREFIX);
}

/** Create a fake note object for something that is not actually a note in the workspace.
*
* For example when we need to render a piece of an actual note. If you need
* to create a fake note for an actual file, prefer
* {@link NoteUtils.createForFile} instead.
*/
static createForFake(opts: {
contents: string;
fname: string;
id: string;
vault: DVault;
}) {
return this.create({
fname: opts.fname,
id: `${this.FAKE_ID_PREFIX}${opts.id}`,
vault: opts.vault,
body: opts.contents,
});
}
}

type SchemaMatchResult = {
Expand Down
1 change: 1 addition & 0 deletions packages/common-all/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from "./intermediateConfigs";
export * from "./compat";
export * from "./editor";
export * from "./lookup";
export * from "./unified";

export type Stage = "dev" | "prod" | "test";
export type DEngineQuery = {
Expand Down
5 changes: 5 additions & 0 deletions packages/common-all/src/types/typesv2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { IntermediateDendronConfig } from "./intermediateConfigs";
import { VSRange } from "./compat";
import { Decoration, Diagnostic } from ".";
import type { NoteFNamesDict } from "../utils";
import { DendronASTDest, ProcFlavor } from "./unified";

export enum ResponseCode {
OK = 200,
Expand Down Expand Up @@ -334,6 +335,10 @@ export type RenderNoteOpts = {
id: string;
/** Optionally, an entire note can be provided to be rendered. If provided, the engine won't look up the note by id and will instead render this note. */
note?: NoteProps;
/** `HTML` by default. */
dest?: DendronASTDest;
/** `Preview` by default. */
flavor?: ProcFlavor;
};

export type RefreshNotesOpts = {
Expand Down
31 changes: 31 additions & 0 deletions packages/common-all/src/types/unified.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Contains types that help with Dendron's unifiedjs markdown processor.

/** The expected output from the processor, if the processor is used to process or stringify a tree. */
export enum DendronASTDest {
MD_ENHANCED_PREVIEW = "MD_ENHANCED_PREVIEW",
MD_REGULAR = "MD_REGULAR",
MD_DENDRON = "MD_DENDRON",
HTML = "HTML",
}

/**
* If processor should run in an alternative flavor
*/
export enum ProcFlavor {
/**
* No special processing
*/
REGULAR = "REGULAR",
/**
* Apply publishing rules
*/
PUBLISHING = "PUBLISHING",
/**
* Apply preview rules
*/
PREVIEW = "PREVIEW",
/**
* Apply hover preview rules (used for the preview when hovering over a link)
*/
HOVER_PREVIEW = "HOVER_PREVIEW",
}
50 changes: 39 additions & 11 deletions packages/engine-server/src/enginev2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
GetDecorationsOpts,
newRange,
GetDecorationsPayload,
DendronASTDest,
} from "@dendronhq/common-all";
import {
createLogger,
Expand Down Expand Up @@ -499,6 +500,8 @@ export class DendronEngineV2 implements DEngine {
async renderNote({
id,
note,
flavor,
dest,
}: RenderNoteOpts): Promise<RespV2<RenderNotePayload>> {
const ctx = "DendronEngineV2:renderNote";

Expand Down Expand Up @@ -543,7 +546,11 @@ export class DendronEngineV2 implements DEngine {
// Either we don't have have the cached preview or the version that is
// cached has gotten stale, hence we will re-render the note and cache
// the new value.
const data = await this._renderNote(note);
const data = await this._renderNote({
note,
flavor: flavor || ProcFlavor.PREVIEW,
dest: dest || DendronASTDest.HTML,
});

this.renderedCache.set(id, {
updated: note.updated,
Expand Down Expand Up @@ -582,16 +589,37 @@ export class DendronEngineV2 implements DEngine {
);
}

private async _renderNote(note: NoteProps): Promise<string> {
const proc = MDUtilsV5.procRehypeFull(
{
engine: this,
fname: note.fname,
vault: note.vault,
config: this.config,
},
{ flavor: ProcFlavor.PREVIEW }
);
private async _renderNote({
note,
flavor,
dest,
}: {
note: NoteProps;
flavor: ProcFlavor;
dest: DendronASTDest;
}): Promise<string> {
let proc: ReturnType<typeof MDUtilsV5["procRehypeFull"]>;
if (dest === DendronASTDest.HTML) {
proc = MDUtilsV5.procRehypeFull(
{
engine: this,
fname: note.fname,
vault: note.vault,
config: this.config,
},
{ flavor }
);
} else {
proc = MDUtilsV5.procRemarkFull(
{
engine: this,
fname: note.fname,
vault: note.vault,
dest,
},
{ flavor }
);
}
const payload = await proc.process(NoteUtils.serialize(note));
const renderedNote = payload.toString();
return renderedNote;
Expand Down
9 changes: 5 additions & 4 deletions packages/engine-server/src/markdown/remark/blockAnchors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { DendronError } from "@dendronhq/common-all";
import { Eat } from "remark-parse";
import Unified, { Plugin } from "unified";
import { BlockAnchor, DendronASTDest } from "../types";
import { MDUtilsV4 } from "../utils";
import { Element } from "hast";
import { html } from "mdast-builder";
import { MDUtilsV5 } from "..";

// Letters, digits, dashes, and underscores.
// The underscores are an extension over Obsidian.
Expand Down Expand Up @@ -71,19 +71,20 @@ function attachParser(proc: Unified.Processor) {
inlineMethods.splice(inlineMethods.indexOf("link"), 0, "blockAnchor");
}

function attachCompiler(proc: Unified.Processor, opts?: PluginOpts) {
function attachCompiler(proc: Unified.Processor, _opts?: PluginOpts) {
const Compiler = proc.Compiler;
const visitors = Compiler.prototype.visitors;

if (visitors) {
visitors.blockAnchor = function (node: BlockAnchor): string | Element {
const { dest } = MDUtilsV4.getDendronData(proc);
const { dest } = MDUtilsV5.getProcData(proc);
const fullId = node.id;
switch (dest) {
case DendronASTDest.MD_DENDRON:
return fullId;
case DendronASTDest.MD_REGULAR:
return opts?.hideBlockAnchors ? "" : fullId;
// Regular markdown has no concept of anchors, so best to strip it out
return "";
case DendronASTDest.MD_ENHANCED_PREVIEW:
return `<a aria-hidden="true" class="block-anchor anchor-heading" id="${fullId}" href="#${fullId}">^${fullId}</a>`;
default:
Expand Down
9 changes: 8 additions & 1 deletion packages/engine-server/src/markdown/remark/dendronPreview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,18 @@ export function dendronHoverPreview(
): Transformer {
const proc = this;
function transformer(tree: Node, _file: VFile) {
visit(tree, (node, _index, _parent) => {
visit(tree, (node, index, parent) => {
if (RemarkUtils.isImage(node) || RemarkUtils.isExtendedImage(node)) {
// Hover preview can't use API URL's because they are http not https, so we instead have to get the image from disk.
return handleImage({ proc, node, useFullPathUrl: true });
}
// Remove the frontmatter because it will break the output
if (RemarkUtils.isFrontmatter(node) && parent) {
// Remove this node
parent.children.splice(index, 1);
// Since we removed this node, the next node to process will be the same index
return index;
}
});
}
return transformer;
Expand Down
21 changes: 14 additions & 7 deletions packages/engine-server/src/markdown/remark/dendronPub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ function plugin(this: Unified.Processor, opts?: PluginOpts): Transformer {
node.type === DendronASTTypes.WIKI_LINK &&
dest !== DendronASTDest.MD_ENHANCED_PREVIEW
) {
// If the target is Dendron, no processing of links is needed
if (dest === DendronASTDest.MD_DENDRON) return;
const _node = node as WikiLinkNoteV4;
// @ts-ignore
let value = node.value as string;
Expand Down Expand Up @@ -275,7 +277,11 @@ function plugin(this: Unified.Processor, opts?: PluginOpts): Transformer {
}

let useId = copts?.useId;
if (MDUtilsV5.isV5Active(proc) && dest === DendronASTDest.HTML) {
if (
useId === undefined &&
MDUtilsV5.isV5Active(proc) &&
dest === DendronASTDest.HTML
) {
useId = true;
}

Expand Down Expand Up @@ -344,6 +350,8 @@ function plugin(this: Unified.Processor, opts?: PluginOpts): Transformer {
}
}
if (node.type === DendronASTTypes.REF_LINK_V2) {
// If the target is Dendron, no processing of refs is needed
if (dest === DendronASTDest.MD_DENDRON) return;
// we have custom compiler for markdown to handle note ref
const ndata = node.data as NoteRefDataV4;
const copts: NoteRefsOptsV2 = {
Expand All @@ -366,14 +374,13 @@ function plugin(this: Unified.Processor, opts?: PluginOpts): Transformer {
}
if (node.type === DendronASTTypes.BLOCK_ANCHOR) {
// no transform
if (dest === DendronASTDest.MD_ENHANCED_PREVIEW) {
if (
dest === DendronASTDest.MD_ENHANCED_PREVIEW ||
dest === DendronASTDest.MD_REGULAR
) {
return;
}
const procOpts = MDUtilsV4.getProcOpts(proc);
const anchorHTML = blockAnchor2html(
node as BlockAnchor,
procOpts.blockAnchorsOpts
);
const anchorHTML = blockAnchor2html(node as BlockAnchor);
let target: Node | undefined;
const grandParent = ancestors[ancestors.length - 2];
if (
Expand Down
12 changes: 8 additions & 4 deletions packages/engine-server/src/markdown/remark/hierarchies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,14 @@ function footnoteDef2html(definition: FootnoteDefinition) {
// eslint-disable-next-line func-names
const plugin: Plugin = function (this: Unified.Processor, opts?: PluginOpts) {
const proc = this;
const hierarchyDisplayTitle = opts?.hierarchyDisplayTitle || "Children";
let hierarchyDisplay = _.isUndefined(opts?.hierarchyDisplay)
? true
: opts?.hierarchyDisplay;
const { config } = MDUtilsV5.getProcData(this);
// MDUtilsV4 explicitly passes these options in, while MDUtilsV5 relies on the config. We need to check both here for now.
const hierarchyDisplayTitle =
opts?.hierarchyDisplayTitle || config?.hierarchyDisplayTitle || "Children";
let hierarchyDisplay: undefined | boolean = opts?.hierarchyDisplay;
if (hierarchyDisplay === undefined)
hierarchyDisplay = config?.hierarchyDisplay;
if (hierarchyDisplay === undefined) hierarchyDisplay = true;

function transformer(tree: Node): void {
const root = tree as Root;
Expand Down

0 comments on commit 103655e

Please sign in to comment.