Automerge backed Markdown editor for the Atmosphere
Something went wrong. Try again.
1.8 kB · 61 lines
TypeScript
at main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162/** * Code fence semantic ops. * * Fence: * * ```lang * ...body... * ``` * * Mark shape: * { name: 'code-fence', value: '{"lang":"js"}', * start: <first char of body>, end: <last char of body+1> } * * Body = content between opening and closing fence lines, exclusive. * * Key spec property: body is treated as LITERAL TEXT. No other marks * should cross or live inside a code fence. The reconciler enforces this. */import * as A from '@automerge/automerge'import type { Doc } from './ops.js'
function lineBounds(text: string, pos: number) { let lineStart = pos while (lineStart > 0 && text[lineStart - 1] !== '\n') lineStart-- let lineEnd = pos while (lineEnd < text.length && text[lineEnd] !== '\n') lineEnd++ return { lineStart, lineEnd }}
/** * Insert a code fence at position `pos` with the given lang and body. * Inserts as a new fence block. Returns mark covering the body. */export function insertCodeFence( doc: A.Doc<Doc>, pos: number, lang: string, body: string,): A.Doc<Doc> { return A.change(doc, (d) => { const { lineStart } = lineBounds(d.content, pos) const fenceText = '```' + lang + '\n' + body + '\n```' A.splice(d, ['content'], lineStart, 0, fenceText) // Body range = after `\`\`\`lang\n` to before `\n\`\`\`` const openingLen = ('```' + lang + '\n').length const bodyStart = lineStart + openingLen const bodyEnd = bodyStart + body.length A.mark( d, ['content'], { start: bodyStart, end: bodyEnd, expand: 'both' }, 'code-fence', JSON.stringify({ lang }), ) })}
/** Read code-fence marks. */export function readCodeFences(doc: A.Doc<Doc>) { return A.marks(doc, ['content']).filter((m) => m.name === 'code-fence')}