Keep one merge loop and one mark key: editor-normal compares normalized marks with identicalMark

This commit is contained in:
2026-10-03 14:17:22 +02:00
parent 0c507f981f
commit fdbf43398c
6 changed files with 34 additions and 53 deletions
+3 -3
View File
@@ -3,9 +3,9 @@ import type { LineContainer } from '../line-container.ts'
import type { MarkRun } from './line-escaping.ts'
import { blockNodeModel } from '../../adf/block-nodes.ts'
import { failure, success, type ConvertErrorPath, type Result } from '../../result.ts'
import { joinsNormally, sameMark } from '../../adf/editor-normal.ts'
import { largestNesting } from '../../nesting.ts'
import { mergeAdjacentText, sameMark } from '../../adf/editor-normal.ts'
import { nodeAttrs, nodeContent, nodeMarks } from '../../adf/document.ts'
import { mergeAdjacentText, nodeAttrs, nodeContent, nodeMarks } from '../../adf/document.ts'
import { plainLineFallback, type PlainLineFallback } from './inline-line.ts'
import { spellDestination, spellLinkTarget } from '../commonmark/link-syntax.ts'
@@ -193,7 +193,7 @@ function withMarks(leaf: AdfNode, marks: readonly AdfMark[]): AdfNode {
function trimmedEdges(leaves: readonly AdfNode[]): AdfNode[] {
for (let current = leaves; ; ) {
const merged = withoutEdgeBreaks(mergeAdjacentText(current))
const merged = withoutEdgeBreaks(mergeAdjacentText(current, joinsNormally))
let changed = false
const trimmed: AdfNode[] = []
for (const [index, leaf] of merged.entries()) {
+3 -16
View File
@@ -10,7 +10,7 @@ import { commonMarkLink, linkHref } from '../mark-spellings.ts'
import { delimiterFlags, matchEmphasis, runLength } from '../commonmark/emphasis-matching.ts'
import { failure, faulted, success, type ConvertErrorPath, type Result } from '../../result.ts'
import { highlightDelimiter, highlightFlanking } from '../plain-conventions.ts'
import { identicalMarks, nodeAttrs, nodeMarks } from '../../adf/document.ts'
import { identicalMarks, mergeAdjacentText, nodeAttrs, nodeMarks } from '../../adf/document.ts'
import { inlineNodeModel } from '../../adf/inline-nodes.ts'
import { noSpans, readInlineDirective } from '../directive-syntax.ts'
import { normalizeLabel, readInlineTarget, readLabel } from '../commonmark/link-syntax.ts'
@@ -475,20 +475,7 @@ function resolveNodes(pieces: readonly Piece[], scan: Scan, highlights: boolean)
writeUnpaired(nodes, runs, pairings)
if (!markPairings(pieces, nodes, pairings)) return failure('unsupported-node-shape', carriedInMark, scan.path)
markHighlights(pieces, nodes, highlights ? pairedHighlights(pieces, nodes) : [])
return success(mergeText(nodes.flat(), scan.carried))
}
function mergeText(nodes: readonly AdfNode[], carried: ReadonlySet<AdfNode>): AdfNode[] {
const merged: AdfNode[] = []
for (const node of nodes) {
const previous = merged[merged.length - 1]
if (previous !== undefined && !carried.has(previous) && !carried.has(node) && readsAsOne(previous, node)) {
merged[merged.length - 1] = { ...previous, text: `${previous.text ?? ''}${node.text ?? ''}` }
continue
}
merged.push(node)
}
return merged
return success(mergeAdjacentText(nodes.flat(), (previous, node) => !scan.carried.has(previous) && !scan.carried.has(node) && readsAsOne(previous, node)))
}
// Only `imageAlt` reaches the image arm: everywhere else an image amid other content is refused first.
@@ -579,7 +566,7 @@ function pairedHighlights(pieces: readonly Piece[], nodes: readonly AdfNode[][])
let candidate = found[closer]
while (candidate !== undefined && (!candidate.closes || candidate.position < earliest)) candidate = found[(closer += 1)]
if (candidate === undefined) break
if (candidate.line !== opener.line || !identicalMarks(opener.holder, candidate.holder)) continue
if (candidate.line !== opener.line || !identicalMarks(nodeMarks(opener.holder), nodeMarks(candidate.holder))) continue
paired.push({ closer: candidate.index, opener: opener.index })
resume = candidate.position + highlightDelimiter.length
}
+2 -2
View File
@@ -1,5 +1,5 @@
import type { AdfNode } from '../adf/document.ts'
import { identicalMarks } from '../adf/document.ts'
import { identicalMarks, nodeMarks } from '../adf/document.ts'
import { spellInlineLeafDirective } from './directive-syntax.ts'
export const textBreakName = 'textBreak'
@@ -8,7 +8,7 @@ export const textBreakSpelling = spellInlineLeafDirective(textBreakName, '')
// Whether CommonMark reads the pair back as one text node, where neither rides the carry (spec/flavour.md, Inline nodes).
export function readsAsOne(previous: AdfNode, node: AdfNode): boolean {
return spelledAsText(previous) && spelledAsText(node) && identicalMarks(previous, node)
return spelledAsText(previous) && spelledAsText(node) && identicalMarks(nodeMarks(previous), nodeMarks(node))
}
function spelledAsText(node: AdfNode): boolean {