ElyMark: tables compare by alignment and cell source, in quotes and lists too; rewritten cells stay raw (R2.13)
This commit is contained in:
5 files changed
+46
-7
No files matched your search
@@ -1,5 +1,6 @@
|
||||
// Blocks Milkdown cannot write back stay raw text (§14.3).
|
||||
import { editorViewCtx, parserCtx, remarkCtx, schemaCtx, serializerCtx } from '@milkdown/kit/core'
|
||||
import { editorViewCtx, remarkCtx, schemaCtx, serializerCtx } from '@milkdown/kit/core'
|
||||
import { canon } from './tables.js'
|
||||
import { Fragment } from '@milkdown/kit/prose/model'
|
||||
import { Selection } from '@milkdown/kit/prose/state'
|
||||
import { $nodeSchema } from '@milkdown/kit/utils'
|
||||
@@ -51,10 +52,11 @@ export function faithful(ctx, original) {
|
||||
const schema = ctx.get(schemaCtx)
|
||||
const serializer = ctx.get(serializerCtx)
|
||||
const written = (nodes) => serializer(schema.topNodeType.create(null, nodes)).replace(/\n+$/, '')
|
||||
const parser = ctx.get(parserCtx)
|
||||
// A table's spacing is free; its cells must match.
|
||||
const kept = (node, text) =>
|
||||
written([node]) === text || (node.type.name === 'table' && parser(text).firstChild?.eq(node))
|
||||
// Table spacing is free; every cell's source must match.
|
||||
const kept = (node, text) => {
|
||||
const own = written([node])
|
||||
return own === text || canon(own) === canon(text)
|
||||
}
|
||||
const rawOf = ([from, to]) => {
|
||||
const text = original.slice(from, to)
|
||||
return schema.nodes.ely_raw.create(null, text ? schema.text(text) : null)
|
||||
|
||||
@@ -36,7 +36,8 @@ export function style(text) {
|
||||
if (node.depth <= 2) vote('setext', head[0] !== '#')
|
||||
break
|
||||
case 'table': {
|
||||
const rows = text.slice(at, node.position.end.offset).split('\n').map((row) => row.trim())
|
||||
// Row nodes leave out quote and list prefixes.
|
||||
const rows = node.children.map((row) => text.slice(row.position.start.offset, row.position.end.offset).trim())
|
||||
const padded = /\| /.test(rows[0])
|
||||
const cells = rows.flatMap((row) => row.replace(/^\||\|$/g, '').split('|'))
|
||||
const inner = (cell) => (padded ? cell.replace(/^ | $/g, '') : cell)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Tables compare by alignment and cell source, not spacing.
|
||||
import { unified } from 'unified'
|
||||
import remarkParse from 'remark-parse'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import { SKIP, visit } from 'unist-util-visit'
|
||||
|
||||
const reader = unified().use(remarkParse).use(remarkGfm)
|
||||
|
||||
/** A cell's own source, without its padding. */
|
||||
function cell(text, node) {
|
||||
const kids = node.children
|
||||
return kids.length ? text.slice(kids[0].position.start.offset, kids.at(-1).position.end.offset) : ''
|
||||
}
|
||||
|
||||
/** `text` with each table's spacing made canonical. */
|
||||
export function canon(text) {
|
||||
const tables = []
|
||||
visit(reader.parse(text), 'table', (node) => {
|
||||
tables.push(node)
|
||||
return SKIP
|
||||
})
|
||||
let out = text
|
||||
// Later tables first, so earlier offsets hold.
|
||||
for (const table of tables.reverse()) {
|
||||
const rows = table.children.map((row) => row.children.map((node) => cell(text, node)).join('|'))
|
||||
const shape = [table.align.join(','), ...rows].join('\n')
|
||||
out = `${out.slice(0, table.position.start.offset)}\u0000${shape}\u0000${out.slice(table.position.end.offset)}`
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in new issue
Block a user