|
@@ -218,6 +218,7 @@ function buildDecorationsFromCache(
|
|
|
contentCaches: Map<string, BlockTokenCache>,
|
|
contentCaches: Map<string, BlockTokenCache>,
|
|
|
isFocused: boolean,
|
|
isFocused: boolean,
|
|
|
markerMode: MarkerVisibilityMode,
|
|
markerMode: MarkerVisibilityMode,
|
|
|
|
|
+ resolvedRefs: Set<string>,
|
|
|
): DecorationSet {
|
|
): DecorationSet {
|
|
|
const decorationSpecs: Decoration[] = []
|
|
const decorationSpecs: Decoration[] = []
|
|
|
|
|
|
|
@@ -283,6 +284,7 @@ function buildDecorationsFromCache(
|
|
|
decorationSpecs,
|
|
decorationSpecs,
|
|
|
isFocused,
|
|
isFocused,
|
|
|
markerMode,
|
|
markerMode,
|
|
|
|
|
+ resolvedRefs,
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -501,6 +503,7 @@ function applyInlineDecorations(
|
|
|
decorationSpecs: Decoration[],
|
|
decorationSpecs: Decoration[],
|
|
|
isFocused: boolean,
|
|
isFocused: boolean,
|
|
|
markerMode: MarkerVisibilityMode,
|
|
markerMode: MarkerVisibilityMode,
|
|
|
|
|
+ resolvedRefs: Set<string>,
|
|
|
) {
|
|
) {
|
|
|
const ranges = token.decorationRanges
|
|
const ranges = token.decorationRanges
|
|
|
if (ranges.length === 0) return
|
|
if (ranges.length === 0) return
|
|
@@ -592,10 +595,30 @@ function applyInlineDecorations(
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ let extraAttrs: Record<string, string> = {}
|
|
|
|
|
+
|
|
|
|
|
+ // Unresolved reference detection: if a page-ref or block-ref
|
|
|
|
|
+ // chip's target is absent from resolvedRefs, style it with a
|
|
|
|
|
+ // dashed underline and title tooltip.
|
|
|
|
|
+ if (
|
|
|
|
|
+ (token.type === "page-ref" || token.type === "block-ref") &&
|
|
|
|
|
+ !isHiddenDecorator
|
|
|
|
|
+ ) {
|
|
|
|
|
+ const refName =
|
|
|
|
|
+ token.type === "page-ref"
|
|
|
|
|
+ ? token.wrapperAttrs?.["data-page-name"]
|
|
|
|
|
+ : token.wrapperAttrs?.["data-block-id"]
|
|
|
|
|
+ if (refName && !resolvedRefs.has(refName)) {
|
|
|
|
|
+ rangeClass = `${rangeClass} md-ref-unresolved`
|
|
|
|
|
+ extraAttrs = { title: "Unresolved reference" }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
decorationSpecs.push(
|
|
decorationSpecs.push(
|
|
|
Decoration.inline(spec.from, spec.to, {
|
|
Decoration.inline(spec.from, spec.to, {
|
|
|
nodeName: "span",
|
|
nodeName: "span",
|
|
|
class: rangeClass,
|
|
class: rangeClass,
|
|
|
|
|
+ ...extraAttrs,
|
|
|
...(token.wrapperAttrs ?? {}),
|
|
...(token.wrapperAttrs ?? {}),
|
|
|
}),
|
|
}),
|
|
|
)
|
|
)
|
|
@@ -858,6 +881,8 @@ interface DecorationState {
|
|
|
hasFocus: boolean
|
|
hasFocus: boolean
|
|
|
markerMode: MarkerVisibilityMode
|
|
markerMode: MarkerVisibilityMode
|
|
|
decorationVersion: number
|
|
decorationVersion: number
|
|
|
|
|
+ resolvedRefs: Set<string>
|
|
|
|
|
+ resolvedRefsVersion: number
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const markdownDecorationsKey = new PluginKey<DecorationState>(
|
|
const markdownDecorationsKey = new PluginKey<DecorationState>(
|
|
@@ -914,8 +939,6 @@ export function createMarkdownDecorationsPlugin(
|
|
|
) {
|
|
) {
|
|
|
let cachedSet: DecorationSet | null = null
|
|
let cachedSet: DecorationSet | null = null
|
|
|
let cachedVersion = -1
|
|
let cachedVersion = -1
|
|
|
- let cachedFocus = false
|
|
|
|
|
- let cachedMode = initialMarkerMode
|
|
|
|
|
|
|
|
|
|
const plugin = new Plugin<DecorationState>({
|
|
const plugin = new Plugin<DecorationState>({
|
|
|
key: markdownDecorationsKey,
|
|
key: markdownDecorationsKey,
|
|
@@ -941,6 +964,8 @@ export function createMarkdownDecorationsPlugin(
|
|
|
hasFocus: false,
|
|
hasFocus: false,
|
|
|
markerMode: initialMarkerMode,
|
|
markerMode: initialMarkerMode,
|
|
|
decorationVersion: 0,
|
|
decorationVersion: 0,
|
|
|
|
|
+ resolvedRefs: new Set<string>(),
|
|
|
|
|
+ resolvedRefsVersion: 0,
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
|
|
@@ -949,6 +974,8 @@ export function createMarkdownDecorationsPlugin(
|
|
|
let markerMode = prevState.markerMode
|
|
let markerMode = prevState.markerMode
|
|
|
let decorationVersion = prevState.decorationVersion
|
|
let decorationVersion = prevState.decorationVersion
|
|
|
let contentCaches = prevState.contentCaches
|
|
let contentCaches = prevState.contentCaches
|
|
|
|
|
+ let resolvedRefs = prevState.resolvedRefs
|
|
|
|
|
+ let resolvedRefsVersion = prevState.resolvedRefsVersion
|
|
|
let docChanged = false
|
|
let docChanged = false
|
|
|
|
|
|
|
|
const focusMeta = tr.getMeta("decorations:focus")
|
|
const focusMeta = tr.getMeta("decorations:focus")
|
|
@@ -963,6 +990,17 @@ export function createMarkdownDecorationsPlugin(
|
|
|
decorationVersion++
|
|
decorationVersion++
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ const refsMeta = tr.getMeta("decorations:resolvedRefs")
|
|
|
|
|
+ if (refsMeta !== undefined) {
|
|
|
|
|
+ const payload = refsMeta as {
|
|
|
|
|
+ refs: Set<string>
|
|
|
|
|
+ version: number
|
|
|
|
|
+ }
|
|
|
|
|
+ resolvedRefs = payload.refs
|
|
|
|
|
+ resolvedRefsVersion = payload.version
|
|
|
|
|
+ decorationVersion++
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (tr.docChanged) {
|
|
if (tr.docChanged) {
|
|
|
contentCaches = invalidateChangedCaches(
|
|
contentCaches = invalidateChangedCaches(
|
|
|
newState.doc,
|
|
newState.doc,
|
|
@@ -977,7 +1015,8 @@ export function createMarkdownDecorationsPlugin(
|
|
|
if (
|
|
if (
|
|
|
docChanged ||
|
|
docChanged ||
|
|
|
hasFocus !== prevState.hasFocus ||
|
|
hasFocus !== prevState.hasFocus ||
|
|
|
- markerMode !== prevState.markerMode
|
|
|
|
|
|
|
+ markerMode !== prevState.markerMode ||
|
|
|
|
|
+ decorationVersion !== prevState.decorationVersion
|
|
|
) {
|
|
) {
|
|
|
return {
|
|
return {
|
|
|
engine: prevState.engine,
|
|
engine: prevState.engine,
|
|
@@ -985,6 +1024,8 @@ export function createMarkdownDecorationsPlugin(
|
|
|
hasFocus,
|
|
hasFocus,
|
|
|
markerMode,
|
|
markerMode,
|
|
|
decorationVersion,
|
|
decorationVersion,
|
|
|
|
|
+ resolvedRefs,
|
|
|
|
|
+ resolvedRefsVersion,
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -999,9 +1040,7 @@ export function createMarkdownDecorationsPlugin(
|
|
|
|
|
|
|
|
if (
|
|
if (
|
|
|
cachedSet &&
|
|
cachedSet &&
|
|
|
- cachedVersion === pluginState.decorationVersion &&
|
|
|
|
|
- cachedFocus === pluginState.hasFocus &&
|
|
|
|
|
- cachedMode === pluginState.markerMode
|
|
|
|
|
|
|
+ cachedVersion === pluginState.decorationVersion
|
|
|
) {
|
|
) {
|
|
|
return cachedSet
|
|
return cachedSet
|
|
|
}
|
|
}
|
|
@@ -1011,10 +1050,9 @@ export function createMarkdownDecorationsPlugin(
|
|
|
pluginState.contentCaches,
|
|
pluginState.contentCaches,
|
|
|
pluginState.hasFocus,
|
|
pluginState.hasFocus,
|
|
|
pluginState.markerMode,
|
|
pluginState.markerMode,
|
|
|
|
|
+ pluginState.resolvedRefs,
|
|
|
)
|
|
)
|
|
|
cachedVersion = pluginState.decorationVersion
|
|
cachedVersion = pluginState.decorationVersion
|
|
|
- cachedFocus = pluginState.hasFocus
|
|
|
|
|
- cachedMode = pluginState.markerMode
|
|
|
|
|
|
|
|
|
|
return cachedSet
|
|
return cachedSet
|
|
|
},
|
|
},
|