import { Annotation, type ChangeSpec, type Transaction } from '@codemirror/state' export type CoreInlineSpecName = 'bold' | 'italic' | 'strike' | 'inline-code' export type InlineSemanticSpecName = CoreInlineSpecName | (string & {}) export type InlineSemanticMarkOp = | { readonly kind: 'add-mark' readonly specName: InlineSemanticSpecName readonly range: { readonly start: number; readonly end: number } readonly attrs: unknown } | { readonly kind: 'unmark' readonly specName: InlineSemanticSpecName readonly range: { readonly start: number; readonly end: number } } | { readonly kind: 'synthesize-paste' readonly range: { readonly start: number; readonly end: number } } export interface InlineSemanticChange { readonly ops: ReadonlyArray } export interface InlineSemanticTextChange { readonly from: number readonly to: number readonly insert: string } const CORE_INLINE_SPEC_NAMES = { '**': 'bold', '__': 'bold', '*': 'italic', '_': 'italic', '~~': 'strike', '`': 'inline-code', '``': 'inline-code', '```': 'inline-code', } as const satisfies Record export function coreInlineSpecNameForDelimiter(delimiter: string): CoreInlineSpecName | undefined { return CORE_INLINE_SPEC_NAMES[delimiter as keyof typeof CORE_INLINE_SPEC_NAMES] } export const INLINE_SEMANTIC_CHANGE_ANNOTATION = Annotation.define() export const INLINE_SEMANTIC_TEXT_CHANGE_ANNOTATION = Annotation.define() export function readInlineSemanticChange( transaction: Transaction, ): InlineSemanticChange | undefined { return transaction.annotation(INLINE_SEMANTIC_CHANGE_ANNOTATION) } export function inlineSemanticTextChangeFromChangeSpec( change: ChangeSpec, ): InlineSemanticTextChange | undefined { if ( typeof change === 'object' && change !== null && !Array.isArray(change) && 'from' in change && 'to' in change && 'insert' in change && typeof (change as { insert: unknown }).insert === 'string' ) { return { from: (change as { from: number }).from, to: (change as { to: number }).to, insert: (change as { insert: string }).insert, } } return undefined } export function readInlineSemanticTextChange( transaction: Transaction, ): InlineSemanticTextChange | undefined { return transaction.annotation(INLINE_SEMANTIC_TEXT_CHANGE_ANNOTATION) }