@citisen/litearea 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/grammar.ts","../src/core/format.ts","../src/core/vocabulary.ts","../src/grammars/dshFont.ts","../src/core/text.ts","../src/grammars/dshSentry.ts"],"names":["faces","key"],"mappings":"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","file":"grammars.js","sourcesContent":["// ─── grammar: the two identity functions authors actually want ──────────────\n//\n// Neither does anything at runtime, and that is not a joke at the reader's\n// expense: `defineGrammar` exists so `State` is inferred from `analyze` and then\n// enforced everywhere else. Written as a bare object literal, a grammar whose\n// `analyze` returns `{ entries: Entry[] }` would have every hook's `context.state`\n// typed as `unknown`, and the author would spend the afternoon casting.\n//\n// const grammar = defineGrammar({\n// id: 'my-language',\n// rules: [...],\n// analyze: (text) => ({ lines: text.split('\\n') }), // State is inferred\n// compose: [{\n// id: 'values',\n// range: (context) => ({ from: 0, to: context.caret }),\n// items: (context) => context.state.lines.map(...), // typed, not cast\n// }],\n// })\n\nimport type { CompletionSource, Grammar } from './types.js'\n\n/**\n * Declare a grammar, inferring its state type from `analyze`.\n * @param grammar - the grammar.\n * @returns the same grammar, typed.\n */\nexport function defineGrammar<State = unknown>(grammar: Grammar<State>): Grammar<State> {\n return grammar\n}\n\n/**\n * Declare a completion source, inferring the state type from its context.\n * @param source - the source.\n * @returns the same source, typed.\n */\nexport function defineCompletion<State = unknown>(\n source: CompletionSource<State>,\n): CompletionSource<State> {\n return source\n}\n","// ─── format: the small string helpers the messages share ────────────────────\n//\n// Kept apart from the vocabulary so that a grammar can raise its own diagnostics\n// with the same phrasing the built-in ones use, and so that a translated host can\n// reuse the substitution instead of writing a second one.\n\n/** The most members a message will name before it stops counting. */\nconst DEFAULT_LIST_LIMIT = 12\n\n/**\n * Substitute `{name}` placeholders in a template.\n *\n * A placeholder with no matching key is left exactly as it was rather than\n * blanked: a visible `{allowed}` in a message is a bug report, and an empty gap\n * is a mystery.\n * @param template - the template, with `{name}` placeholders.\n * @param values - the substitutions.\n * @returns the filled text.\n */\nexport function fillTemplate(template: string, values: Readonly<Record<string, string>>): string {\n return String(template).replace(/\\{(\\w+)\\}/g, (match, key: string) =>\n Object.hasOwn(values, key) ? String(values[key]) : match,\n )\n}\n\n/**\n * A readable list: `a`, `a or b`, `a, b, or c`.\n *\n * The conjunction is a parameter because the same list reads differently as\n * \"expected one of X, Y, or Z\" and as \"X, Y, and Z are installed\".\n * @param items - the members.\n * @param options - `conjunction` (`'or'` by default) and `limit`, the most\n * members to name before summarising the rest as `… and N more`.\n * @returns the phrase.\n */\nexport function listPhrase(\n items: readonly string[],\n options?: { conjunction?: string; limit?: number },\n): string {\n const conjunction = options?.conjunction ?? 'or'\n const limit = options?.limit ?? DEFAULT_LIST_LIMIT\n const shown = items.slice(0, limit)\n const rest = items.length - shown.length\n if (shown.length === 0) return ''\n if (shown.length === 1) {\n return rest > 0 ? `${String(shown[0])} and ${String(rest)} more` : String(shown[0])\n }\n // Two members take no comma before the conjunction. \"circle, or square\" is not how\n // anyone writes it, and every diagnostic that lists a two-member vocabulary would\n // have said it that way.\n if (shown.length === 2) {\n const pair = `${String(shown[0])} ${conjunction} ${String(shown[1])}`\n return rest > 0 ? `${pair}, and ${String(rest)} more` : pair\n }\n const head = shown.slice(0, -1).join(', ')\n const tail = shown[shown.length - 1]\n const phrase = `${head}, ${conjunction} ${String(tail)}`\n return rest > 0 ? `${phrase}, and ${String(rest)} more` : phrase\n}\n\n/**\n * Collapse the whitespace in a snippet of user text so it can be quoted inside a\n * one-line message.\n * @param text - the text.\n * @param limit - the longest result, ellipsised beyond it.\n * @returns the excerpt.\n */\nexport function excerpt(text: string, limit = 24): string {\n const flat = text.replace(/\\s+/g, ' ').trim()\n return flat.length <= limit ? flat : `${flat.slice(0, limit - 1)}…`\n}\n","// ─── vocabulary: the four facts that must agree ─────────────────────────────\n//\n// A closed set of words appears four times in a language-aware editor: as the\n// syntax that accepts it, as the colour it is painted in, as the message a typo\n// earns, and as the documentation a hover shows. Written out four times they\n// drift — a word added to the parser and forgotten by the highlighter is the\n// ordinary way a grammar rots — and the drift is invisible until someone types\n// the new word and watches the editor get it wrong.\n//\n// So they are declared once. `defineVocabulary` returns an object the engine\n// already knows how to consume: hand it to a `words` rule and it paints, accepts,\n// rejects, and documents without being mentioned again.\n//\n// const SHAPES = defineVocabulary({\n// id: 'shape',\n// words: ['circle', 'rounded', 'square', 'none'],\n// unknownMessage: '\"{word}\" is not a shape — expected one of {allowed}.',\n// docs: { circle: 'A full disc, the background for a busy state.' },\n// })\n//\n// { kind: 'words', words: SHAPES }\n\nimport type {\n ResolvedVocabulary,\n Scope,\n Severity,\n VocabularyContext,\n VocabularyEntry,\n WordsSource,\n} from './types.js'\nimport { fillTemplate, listPhrase } from './format.js'\n\n/** What a vocabulary is told about the document it is being resolved for. */\nexport interface VocabularySpec<State = unknown> {\n /** A stable id, used in the diagnostic code and for debugging. */\n id: string\n /**\n * The members.\n *\n * A function is how a set that lives outside the document reaches the grammar\n * without the grammar holding mutable state: the installed fonts, the states\n * the host actually has. It is called once per scan.\n */\n words: readonly string[] | ((context: VocabularyContext<State>) => readonly string[])\n /** The scope a member is painted with. Defaults to `vocabulary:<id>`. */\n scope?: Scope | ((word: string) => Scope)\n /** The scope a rejected word is painted with. Defaults to `'invalid'`. */\n unknownScope?: Scope\n /**\n * The message a rejected word earns.\n *\n * Present, a word-shaped token outside the set is reported; absent, it is\n * reported by nobody and the grammar is the poorer for it. `{word}` and\n * `{allowed}` are substituted, the latter as a readable list.\n */\n unknownMessage?: string | ((word: string, allowed: readonly string[]) => string)\n /** How loudly a rejected word complains. Default `'error'`. */\n unknownSeverity?: Severity\n /** A stable code for the rejection. Defaults to `vocabulary:<id>`. */\n unknownCode?: string\n /**\n * What each member explains about itself, for hover. A bare string is taken as\n * the body.\n */\n docs?: Readonly<Record<string, string | VocabularyEntry>>\n /** A dimmed line shown beside a member in the completion list. */\n detail?: (word: string) => string | undefined\n /** Whether membership is case-sensitive. Default `false`. */\n caseSensitive?: boolean\n /**\n * How a member is written into the document when it is accepted.\n *\n * Separate from the word itself because a member is not always insertable as\n * typed: a font family containing a space has to be quoted, even though the\n * vocabulary calls it `IBM Plex Mono`.\n */\n format?: (word: string) => string\n}\n\n/**\n * Build a vocabulary: the set, its colour, its rejection, and its documentation.\n * @param spec - the declaration.\n * @returns a resolved vocabulary, ready for a `words` rule.\n */\nexport function defineVocabulary<State = unknown>(\n spec: VocabularySpec<State>,\n): ResolvedVocabulary<State> {\n const caseSensitive = spec.caseSensitive === true\n const unknownScope = spec.unknownScope ?? 'invalid'\n const defaultScope = `vocabulary:${spec.id}`\n const unknownCode = spec.unknownCode ?? `vocabulary:${spec.id}`\n const unknownSeverity = spec.unknownSeverity ?? 'error'\n /** Fold a word for lookup, honouring the vocabulary's case rule. */\n const fold = (word: string): string => (caseSensitive ? word : word.toLowerCase())\n /** Find the member a word names, preserving the declared spelling. */\n const memberOf = (word: string, allowed: readonly string[]): string | undefined => {\n const needle = fold(word)\n return allowed.find((candidate) => fold(candidate) === needle)\n }\n /** The declaration for one member, whichever of the two shapes it took. */\n const docOf = (word: string): VocabularyEntry | undefined => {\n if (spec.docs === undefined) return undefined\n for (const [key, value] of Object.entries(spec.docs)) {\n if (fold(key) !== fold(word)) continue\n return typeof value === 'string' ? { body: value } : value\n }\n return undefined\n }\n\n return {\n id: spec.id,\n caseSensitive,\n resolve: (context) => {\n const words = typeof spec.words === 'function' ? spec.words(context) : spec.words\n return Array.isArray(words) ? words : []\n },\n has: (word, context) => {\n const words = typeof spec.words === 'function' ? spec.words(context) : spec.words\n return memberOf(word, Array.isArray(words) ? words : []) !== undefined\n },\n scopeFor: (word) => {\n if (typeof spec.scope === 'function') return spec.scope(memberOf(word, [word]) ?? word)\n return spec.scope ?? defaultScope\n },\n unknownScope,\n reject: (word, context) => {\n if (spec.unknownMessage === undefined) return undefined\n const allowed = typeof spec.words === 'function' ? spec.words(context) : spec.words\n const members = Array.isArray(allowed) ? allowed : []\n const message =\n typeof spec.unknownMessage === 'function'\n ? spec.unknownMessage(word, members)\n : fillTemplate(spec.unknownMessage, {\n word,\n allowed: listPhrase(members, { conjunction: 'or' }),\n })\n return { message, severity: unknownSeverity, code: unknownCode }\n },\n entryFor: (word) => docOf(word),\n format: (word) => (spec.format === undefined ? word : spec.format(word)),\n }\n}\n\n/**\n * The members of a vocabulary, resolved for a document.\n *\n * A helper for the common case of a caller that has a vocabulary and wants its\n * words, without reaching through to `resolve` and re-supplying the context.\n * @param vocabulary - a resolved vocabulary.\n * @param context - the document it is being resolved for.\n * @returns the members, in declaration order.\n */\nexport function vocabularyWords<State>(\n vocabulary: ResolvedVocabulary<State>,\n context: VocabularyContext<State>,\n): readonly string[] {\n return vocabulary.resolve(context)\n}\n\n/**\n * Recognize a vocabulary among the shapes a `WordsSource` may take.\n *\n * The test is structural rather than `instanceof`, so a grammar may hand over its\n * own object as long as it carries the four facts — which is what lets a host\n * wrap a vocabulary in logging, caching, or a translation layer without the\n * engine needing to know.\n * @param source - a words source.\n * @returns the vocabulary, or undefined when the source is a bare list or function.\n */\nexport function asResolvedVocabulary<State>(\n source: WordsSource<State>,\n): ResolvedVocabulary<State> | undefined {\n if (typeof source !== 'object' || source === null || Array.isArray(source)) return undefined\n const candidate = source as { resolve?: unknown }\n return typeof candidate.resolve === 'function' ? (source as ResolvedVocabulary<State>) : undefined\n}\n\n/**\n * The members any words source stands for, whichever shape it took.\n * @param source - a bare list, a vocabulary, or a function.\n * @param context - the document it is being resolved for.\n * @returns the members, or an empty list when the source resolved to nothing.\n */\nexport function resolveWordsSource<State>(\n source: WordsSource<State>,\n context: VocabularyContext<State>,\n): readonly string[] {\n const vocabulary = asResolvedVocabulary(source)\n const raw =\n vocabulary !== undefined\n ? vocabulary.resolve(context)\n : typeof source === 'function'\n ? source(context)\n : source\n return Array.isArray(raw) ? raw.filter((word) => word !== '') : []\n}\n","// ─── dsh-font's font query, as a litearea grammar ───────────────────────────\n//\n// The language is a CSS font-family list plus the one thing the list cannot carry:\n//\n// Geist Mono medium, \"Zhuque Fangsong (technical preview)\", monospace\n// └─────┬────┘ └──┬─┘\n// family weight\n//\n// `font-family: \"Geist Mono\" 500, monospace` is an invalid declaration that drops\n// the whole stack, so the weight has to be its own `font-weight` — but it can\n// still be WRITTEN next to the family it belongs to, which is what lets one field\n// describe both. A weight is chosen for a family; having to change them in two\n// places is exactly the problem this language exists to remove.\n//\n// query := entry (\",\" entry)*\n// entry := family | weight\n// family := '\"' … '\"' | \"'\" … \"'\" | word (space word)*\n// weight := a word from WEIGHT_WORDS\n//\n// Only the LAST word of an unquoted entry may be a weight, and only when the whole\n// entry is not itself a catalogued family: `Book Antiqua` and `Franklin Gothic\n// Medium` are real families, and stripping either would silently retarget the stack\n// at a font nobody picked. Quoting always means \"this is the family name,\n// verbatim\", so a quoted entry never splits.\n//\n// The parser is forgiving on purpose. This text is typed by hand into a small box,\n// not generated, so anything it cannot place is kept as written and reported as a\n// diagnostic instead of being silently dropped. This grammar keeps that behaviour\n// AND adds the one thing the original editor could not do: it tells you at the\n// moment you type, rather than after you press a key.\n//\n// This is a REFERENCE grammar, not a built-in one. Nothing in `src/core/` knows\n// this language exists.\n//\n// Semantic colouring, and why it is not a token rule's business\n// ------------------------------------------------------------\n// Two of the original's token classes are not lexical at all. `weightMissing` — a\n// weight the chosen family does not have — depends on the machine's installed\n// faces, and `unknown` depends on whether the catalogue is authoritative. Both are\n// still painted here, from a `scope` FUNCTION that reads the analysis, because a\n// rule may look at `match.state`. That is this library's answer to VSCode's split\n// between a TextMate grammar and semantic tokens: one rule set, two sources of\n// truth about a span, and the semantic one is allowed to override.\n\nimport type {\n Decoration,\n Grammar,\n Scope,\n Severity,\n SuggestionItem,\n} from '../core/types.js'\nimport { defineGrammar } from '../core/grammar.js'\nimport { defineVocabulary } from '../core/vocabulary.js'\n\n/** Every weight word the language accepts, mapped to its CSS number. */\nexport const FONT_WEIGHT_WORDS: Readonly<Record<string, number>> = {\n thin: 100,\n hairline: 100,\n extralight: 200,\n ultralight: 200,\n light: 300,\n book: 400,\n normal: 400,\n regular: 400,\n roman: 400,\n medium: 500,\n demibold: 600,\n semibold: 600,\n bold: 700,\n extrabold: 800,\n ultrabold: 800,\n black: 900,\n heavy: 900,\n extrablack: 900,\n ultrablack: 900,\n}\n\n/** The CSS weight scale, in the order a picker shows it. */\nexport const FONT_WEIGHT_SCALE: readonly number[] = [100, 200, 300, 400, 500, 600, 700, 800, 900]\n\n/** The canonical word per weight — `500` is `medium`. */\nexport const FONT_WEIGHT_LABELS: Readonly<Record<number, string>> = {\n 100: 'thin',\n 200: 'extralight',\n 300: 'light',\n 400: 'regular',\n 500: 'medium',\n 600: 'semibold',\n 700: 'bold',\n 800: 'extrabold',\n 900: 'black',\n}\n\n/**\n * Generic CSS families. Valid anywhere in a list, and only useful at the end,\n * which is why they are coloured apart from an installed family: picking one is a\n * different intent from picking a font.\n */\nexport const FONT_GENERIC_FAMILIES: readonly string[] = [\n 'system-ui',\n 'sans-serif',\n 'serif',\n 'monospace',\n 'cursive',\n 'fantasy',\n 'math',\n 'emoji',\n 'fangsong',\n 'ui-sans-serif',\n 'ui-serif',\n 'ui-monospace',\n 'ui-rounded',\n]\n\n/**\n * Popular families offered as suggestions even when not detected.\n *\n * Detection cannot see every font and a family may be installed later, so the\n * picker must not present itself as the complete truth. A host that has read the\n * real catalogue passes it in; this list is what a host with no permission to read\n * one can still offer.\n */\nexport const FONT_COMMON_FAMILIES: readonly string[] = [\n 'Inter',\n 'IBM Plex Sans',\n 'IBM Plex Mono',\n 'Noto Sans',\n 'Noto Sans SC',\n 'Noto Serif',\n 'Source Han Sans SC',\n 'Source Han Serif SC',\n 'JetBrains Mono',\n 'Fira Code',\n 'Fira Sans',\n 'Cascadia Code',\n 'Cascadia Mono',\n 'Maple Mono',\n 'Roboto',\n 'Roboto Mono',\n 'Open Sans',\n 'Lato',\n 'Montserrat',\n 'Poppins',\n 'Ubuntu',\n 'Ubuntu Mono',\n 'DejaVu Sans',\n 'DejaVu Sans Mono',\n 'Hack',\n 'Inconsolata',\n 'Iosevka',\n 'Comic Sans MS',\n 'PingFang SC',\n 'Hiragino Sans GB',\n 'Microsoft YaHei',\n 'Microsoft YaHei UI',\n 'Microsoft JhengHei',\n 'SimSun',\n 'SimHei',\n 'KaiTi',\n 'Segoe UI',\n 'Segoe UI Variable',\n 'Helvetica Neue',\n 'Arial',\n 'Consolas',\n 'Menlo',\n 'Monaco',\n 'SF Mono',\n 'Courier New',\n 'Times New Roman',\n 'Georgia',\n]\n\n/** The scope names this grammar paints with. */\nconst SCOPE = {\n family: 'family',\n generic: 'family.generic',\n unknown: 'family.unknown',\n unclosed: 'family.unclosed',\n weight: 'weight',\n weightMissing: 'weight.missing',\n separator: 'separator',\n} as const\n\n/** One entry of the query, as it was found in the source. */\nexport interface DshFontEntry {\n /** The whole entry, whitespace included. */\n from: number\n to: number\n /** The trimmed core, and its range. */\n coreFrom: number\n coreTo: number\n core: string\n /** Whether the core opens with a quote. */\n quoted: boolean\n /** The family name, with the quotes and any weight word taken out. */\n name: string\n nameFrom: number\n nameTo: number\n /** The weight word the entry carries, if any. */\n word: string | undefined\n wordFrom: number\n wordTo: number\n /** What the reader made of the entry. */\n kind: 'empty' | 'family' | 'generic' | 'unknown' | 'weight'\n}\n\n/** A problem the structural pass found. */\nexport interface DshFontProblem {\n from: number\n to: number\n message: string\n code: string\n severity: Severity\n}\n\n/** What one pass over the query produced. */\nexport interface DshFontState {\n entries: DshFontEntry[]\n /** The family names the entries name, in order. */\n families: string[]\n /** Which of them the browser will actually paint with; -1 when none will. */\n effective: number\n /** The numeric weight the query states, if it states one. */\n weight: number | undefined\n weightWord: string | undefined\n problems: DshFontProblem[]\n}\n\n/** What a host supplies to describe the machine the query will run on. */\nexport interface DshFontQueryOptions {\n /** The family names the machine has. */\n catalogue?: readonly string[]\n /**\n * Whether that catalogue was READ from the machine.\n *\n * It changes what an unrecognized name means. With a read catalogue the browser\n * will fall through to a later family, which is worth warning about; without one\n * the catalogue is only a suggestion list, and the parser has no business\n * second-guessing a name the user typed.\n */\n enumerated?: boolean\n /** The face style names of each family, as the Local Font Access API reports them. */\n styles?: Readonly<Record<string, readonly string[]>>\n /** The weight the axis ships with, offered as a row that takes the word away. */\n shippedWeight?: number\n /** Families offered even when not detected. */\n commonFamilies?: readonly string[]\n /** The generic CSS families. */\n genericFamilies?: readonly string[]\n /** How many words one unquoted family name may span when matching the catalogue. */\n phraseWords?: number\n}\n\n/**\n * The word a numeric weight is spelled with: `500` becomes `medium`.\n * @param weight - a numeric weight.\n * @returns the canonical word, or the number as text when it is off the scale.\n */\nexport function fontWeightWord(weight: number): string {\n return FONT_WEIGHT_LABELS[weight] ?? String(weight)\n}\n\n/**\n * The weights one family actually has, read off its faces' style names.\n *\n * The Local Font Access API reports a face's `style` (`Regular`, `SemiBold`,\n * `Bold Italic`) rather than a number, and is not obliged to spell a two-word\n * style with a hyphen, so `Semi Bold` has to be folded back into one word before\n * the lookup.\n *\n * An empty result means \"unknown\", never \"none\": enumerating faces is\n * permission-gated, and a family may report styles this vocabulary cannot read.\n * @param styles - the face style names of one family.\n * @returns the distinct weights, ascending.\n */\nexport function fontFaceWeights(styles: readonly string[] | undefined): number[] {\n if (styles === undefined) return []\n const found = new Set<number>()\n for (const style of styles) {\n const text = String(style)\n .toLowerCase()\n .replace(/\\b(semi|demi)\\s+(?=[a-z])/g, 'semi')\n .replace(/\\b(extra|ultra)\\s+(?=[a-z])/g, 'extra')\n for (const word of text.split(/[^a-z]+/)) {\n const weight = FONT_WEIGHT_WORDS[word]\n if (weight !== undefined) found.add(weight)\n }\n }\n return [...found].sort((left, right) => left - right)\n}\n\n/**\n * Render a family name for a CSS list, quoting it only when CSS requires it.\n *\n * A generic family or a CSS-wide keyword must NOT be quoted, because `\"sans-serif\"`\n * names a literal font instead of the generic family. A single leading hyphen is\n * part of an identifier (`-apple-system`), so it survives unquoted too.\n * @param family - a bare family name.\n * @returns the CSS token for it.\n */\nexport function quoteFontFamily(family: string): string {\n const name = family.trim()\n if (name === '') return ''\n if (/^-?[A-Za-z][\\w-]*$/.test(name)) return name\n return `\"${name.replaceAll('\"', '')}\"`\n}\n\n/** Whether a lowercase name is a generic CSS family. */\nfunction isGenericName(name: string, generics: readonly string[]): boolean {\n return generics.includes(name)\n}\n\n/**\n * Find the entries of a query, keeping every raw slice.\n *\n * Commas inside quotes are not separators, and an unclosed quote swallows the rest\n * of the document — the same reading the original takes, which is what makes the\n * unclosed-quote diagnostic worth having.\n * @param source - the query.\n * @returns one range per entry, in order. A blank query yields one empty entry.\n */\nfunction splitEntries(source: string): Array<{ from: number; to: number }> {\n const bounds: Array<{ from: number; to: number }> = []\n let start = 0\n let quote = ''\n for (let index = 0; index < source.length; index += 1) {\n const char = source.charAt(index)\n if (quote !== '') {\n if (char === quote) quote = ''\n continue\n }\n if (char === '\"' || char === \"'\") {\n quote = char\n continue\n }\n if (char === ',') {\n bounds.push({ from: start, to: index })\n start = index + 1\n }\n }\n bounds.push({ from: start, to: source.length })\n return bounds\n}\n\n/**\n * Build the grammar for dsh-font's font query.\n * @param options - the machine's catalogue, its faces, and the shipped weight.\n * @returns a grammar that paints, completes, diagnoses, and explains the language.\n */\nexport function dshFontQueryGrammar(options: DshFontQueryOptions = {}): Grammar<DshFontState> {\n const CATALOGUE = options.catalogue ?? []\n const COMMON = options.commonFamilies ?? FONT_COMMON_FAMILIES\n const GENERICS = options.genericFamilies ?? FONT_GENERIC_FAMILIES\n const STYLES = options.styles ?? {}\n const ENUMERATED = options.enumerated === true\n const SHIPPED_WEIGHT = options.shippedWeight\n const PHRASE_WORDS = options.phraseWords ?? 4\n\n /** The lowercase catalogue, which is what every lookup folds against. */\n const KNOWN = new Set(CATALOGUE.map((family) => family.toLowerCase()))\n /** The suggestion space: the catalogue when there is one, plus the curated list. */\n const SUGGESTION_SPACE = [...new Set([...CATALOGUE, ...COMMON, ...GENERICS])]\n /** Every weight word, as a literal alternation, for the lexical weight rule. */\n const WEIGHT_ALTERNATION = Object.keys(FONT_WEIGHT_WORDS).join('|')\n\n /** The families that explain themselves through hover. */\n const FAMILY_VOCAB = defineVocabulary<DshFontState>({\n id: 'family',\n words: SUGGESTION_SPACE,\n scope: SCOPE.family,\n format: quoteFontFamily,\n })\n\n const GENERIC_VOCAB = defineVocabulary<DshFontState>({\n id: 'generic',\n words: GENERICS,\n scope: SCOPE.generic,\n docs: Object.fromEntries(\n GENERICS.map((name) => [\n name,\n {\n detail: 'a generic CSS family',\n body: 'Always valid, and only useful at the end of the list: it is what the browser falls back to when nothing before it resolves.',\n },\n ]),\n ),\n })\n\n const WEIGHT_VOCAB = defineVocabulary<DshFontState>({\n id: 'weight',\n words: Object.keys(FONT_WEIGHT_WORDS),\n scope: SCOPE.weight,\n unknownScope: SCOPE.weight,\n docs: Object.fromEntries(\n Object.entries(FONT_WEIGHT_WORDS).map(([word, weight]) => [\n word,\n { title: word, detail: `font-weight ${String(weight)}` },\n ]),\n ),\n })\n\n /**\n * Read one entry range into the family it names and the weight it carries.\n *\n * The two shapes a weight can take are both here: a bare entry whose last word\n * is a weight (`Geist Mono medium`), and a quoted family followed by one\n * (`\"Geist Mono\" medium`). Only the last word of an UNQUOTED entry may be a\n * weight, and only when the whole entry is not itself a catalogued family.\n * @param source - the query.\n * @param bounds - the entry's range.\n * @returns the entry, and any complaint about it.\n */\n const readEntry = (\n source: string,\n bounds: { from: number; to: number },\n ): { entry: DshFontEntry; problems: DshFontProblem[] } => {\n const raw = source.slice(bounds.from, bounds.to)\n const trimmed = raw.trim()\n const lead = trimmed === '' ? raw.length : raw.indexOf(trimmed)\n const coreFrom = bounds.from + lead\n const core = trimmed\n const coreTo = coreFrom + core.length\n const problems: DshFontProblem[] = []\n\n const entry: DshFontEntry = {\n from: bounds.from,\n to: bounds.to,\n coreFrom,\n coreTo,\n core,\n quoted: false,\n name: '',\n nameFrom: coreFrom,\n nameTo: coreTo,\n word: undefined,\n wordFrom: coreTo,\n wordTo: coreTo,\n kind: 'empty',\n }\n if (core === '') return { entry, problems }\n\n const quoteChar = core.charAt(0)\n const quote = quoteChar === '\"' || quoteChar === \"'\" ? quoteChar : ''\n const lower = core.toLowerCase()\n /**\n * Whether the entry is still worth looking up.\n *\n * A quote that never closes, or text after a closing one that is neither a weight\n * nor part of the name, means the entry is already reported — and the name the\n * reader salvaged from it is a consequence of that mistake, not a separate fact\n * about the machine. Warning that this consequence is \"not in the font list\" would\n * bury the cause under its symptom.\n */\n let lookUp = true\n\n if (quote !== '') {\n entry.quoted = true\n const close = core.indexOf(quote, 1)\n if (close < 0) {\n // An unclosed quote runs to the end of the document, which is why it is\n // reported rather than repaired: everything after it became one name.\n entry.name = core.slice(1).trim()\n entry.nameFrom = coreFrom + 1\n entry.kind = 'family'\n problems.push({\n from: coreFrom,\n to: coreTo,\n message: 'This quote is never closed, so everything after it is read as part of one family name.',\n code: 'unclosed-quote',\n severity: 'error',\n })\n return { entry, problems }\n }\n entry.name = core.slice(1, close)\n entry.nameFrom = coreFrom + 1\n entry.nameTo = coreFrom + close\n const rest = core.slice(close + 1).trim()\n if (rest !== '') {\n const restFrom = coreTo - rest.length\n if (Object.hasOwn(FONT_WEIGHT_WORDS, rest.toLowerCase())) {\n entry.word = rest.toLowerCase()\n entry.wordFrom = restFrom\n entry.wordTo = coreTo\n } else {\n problems.push({\n from: restFrom,\n to: coreTo,\n message: `\"${rest}\" follows a quoted family name but is neither a weight nor part of it, so it is ignored.`,\n code: 'trailing-text',\n severity: 'error',\n })\n lookUp = false\n }\n }\n entry.kind = 'family'\n } else if (isGenericName(lower, GENERICS) || KNOWN.has(lower)) {\n // The whole entry is one family: there is nothing to strip off it.\n entry.name = core\n entry.kind = isGenericName(lower, GENERICS) ? 'generic' : 'family'\n } else if (Object.hasOwn(FONT_WEIGHT_WORDS, lower)) {\n // A bare weight word stands on its own, without a family.\n entry.kind = 'weight'\n entry.word = lower\n entry.wordFrom = coreFrom\n entry.wordTo = coreTo\n } else {\n const cut = lower.lastIndexOf(' ')\n const tail = cut > 0 ? lower.slice(cut + 1) : ''\n if (cut > 0 && Object.hasOwn(FONT_WEIGHT_WORDS, tail)) {\n entry.word = tail\n entry.wordFrom = coreFrom + cut + 1\n entry.wordTo = coreTo\n entry.name = core.slice(0, cut).trim()\n entry.nameTo = entry.nameFrom + entry.name.length\n } else {\n entry.name = core\n }\n entry.kind = 'family'\n }\n\n const nameLower = entry.name.trim().toLowerCase()\n const generic = nameLower !== '' && isGenericName(nameLower, GENERICS)\n const catalogued = nameLower !== '' && KNOWN.has(nameLower)\n if (lookUp && nameLower !== '' && !generic && !catalogued && ENUMERATED) {\n entry.kind = 'unknown'\n problems.push({\n from: entry.nameFrom,\n to: entry.nameFrom + entry.name.length,\n message: `\"${entry.name}\" is not in this machine's font list. It is still written, and the browser will fall back to whatever comes after it.`,\n code: 'unknown-family',\n severity: 'warning',\n })\n } else if (generic) {\n entry.kind = 'generic'\n }\n return { entry, problems }\n }\n\n return defineGrammar<DshFontState>({\n id: 'dsh-font-query',\n name: 'dsh-font font query',\n\n // A hyphen belongs to a name (`-apple-system`, `Helvetica Neue` has spaces and\n // is reached by the phrase rule instead), and `.` deliberately does not: no\n // family name in this vocabulary contains one, and leaving it out keeps a\n // stray `Inter.` from being read as a single unknown name.\n wordChars: /[\\p{L}\\p{N}_-]/u,\n\n rules: [\n // ── quoted names, before anything can split them ───────────────────\n {\n kind: 'match',\n pattern: /\"[^\"\\n]*\"|'[^'\\n]*'/,\n // The scope is decided by what is INSIDE the quotes: a quoted generic is\n // still a generic, and a quoted name the machine does not have is still\n // worth painting as unknown.\n scope: (match) => quotedScope(match.text, KNOWN, GENERICS, ENUMERATED),\n },\n {\n kind: 'match',\n pattern: /[\"'][^\\n]*/,\n scope: SCOPE.unclosed,\n },\n\n { kind: 'match', scope: SCOPE.separator, pattern: /,/ },\n\n // ── a weight word, but only where a weight may stand ──────────────\n // A weight is the LAST word of an entry, so the rule looks ahead for a comma\n // or the end of a line. Without that lookahead `Book` in `Book Antiqua`\n // would be painted as a weight. `prevNot` stops it matching the tail of a\n // longer word.\n //\n // The scope is decided from the ANALYSIS rather than from the characters,\n // which is the one place this grammar needs that: `weight` and\n // `weightMissing` are the same word, and only the machine knows which one it\n // is. A rule may look at `match.state` precisely so that a semantic\n // judgement does not have to become a second highlighter.\n {\n kind: 'match',\n pattern: new RegExp(`(?:${WEIGHT_ALTERNATION})(?=\\\\s*(?:,|$))`, 'im'),\n when: { prevNot: '\\\\w' },\n scope: (match) => {\n const state = match.state\n if (state.weight === undefined || state.effective < 0) return SCOPE.weight\n const family = state.families[state.effective] ?? ''\n const faces = fontFaceWeights(lookupStyles(STYLES, family))\n // An unread face list means \"unknown\", never \"absent\".\n if (faces.length === 0 || faces.includes(state.weight)) return SCOPE.weight\n return SCOPE.weightMissing\n },\n },\n\n // ── the catalogue, longest phrase first ──────────────────────────\n // The generics come first because they are ALSO in the suggestion space,\n // and a generic painted as an installed family would say the wrong thing\n // about a word whose whole point is that it names no particular font.\n { kind: 'words', words: GENERIC_VOCAB },\n {\n kind: 'words',\n words: FAMILY_VOCAB,\n phrase: { max: PHRASE_WORDS },\n },\n\n // ── anything else is a name the reader has not seen ──────────────\n // `unknown` when the catalogue is authoritative, because then the browser\n // really will fall through; plain `family` when it is only a suggestion\n // list, because the parser has no business doubting the user.\n {\n kind: 'match',\n pattern: /[^\\s,]+/,\n scope: ENUMERATED ? SCOPE.unknown : SCOPE.family,\n },\n ],\n\n fallbackScope: 'text',\n\n // ── what the query means ──────────────────────────────────────────────\n analyze: (text) => {\n const entries: DshFontEntry[] = []\n const problems: DshFontProblem[] = []\n for (const bounds of splitEntries(text)) {\n const read = readEntry(text, bounds)\n entries.push(read.entry)\n problems.push(...read.problems)\n }\n\n const families: string[] = []\n let weight: number | undefined\n let weightWord: string | undefined\n let sawWeight = false\n for (const entry of entries) {\n if (entry.name.trim() !== '') families.push(entry.name.trim())\n if (entry.word !== undefined) {\n if (!sawWeight) {\n sawWeight = true\n weight = FONT_WEIGHT_WORDS[entry.word]\n weightWord = entry.word\n } else {\n problems.push({\n from: entry.wordFrom,\n to: entry.wordTo,\n message: `The weight is stated more than once. The first one is used and this \"${entry.word}\" is ignored.`,\n code: 'duplicate-weight',\n severity: 'warning',\n })\n }\n }\n }\n\n // ── the family that is actually in effect ───────────────────────────\n // With a catalogue read from the machine the first INSTALLED family wins,\n // because that is the one the browser will paint with. Without one the\n // catalogue is only a suggestion list, so the first entry stands.\n let effective = -1\n if (families.length > 0) {\n if (!ENUMERATED) {\n effective = 0\n } else {\n for (let index = 0; index < families.length; index += 1) {\n const lower = (families[index] ?? '').toLowerCase()\n if (isGenericName(lower, GENERICS) || KNOWN.has(lower)) {\n effective = index\n break\n }\n }\n }\n }\n\n // ── a weight the effective family does not have ──────────────────────\n // Only reported when that family's faces are actually known: an empty face\n // list means \"not read\", never \"not installed\".\n if (weight !== undefined && effective >= 0) {\n const family = families[effective] ?? ''\n const faces = fontFaceWeights(lookupStyles(STYLES, family))\n if (faces.length > 0 && !faces.includes(weight)) {\n const entry = entries.find((candidate) => candidate.word !== undefined)\n if (entry !== undefined) {\n problems.push({\n from: entry.wordFrom,\n to: entry.wordTo,\n message: `\"${family}\" has no ${String(weight)} face, so the browser will synthesise one. It does have ${faces.join(', ')}.`,\n code: 'missing-weight',\n severity: 'warning',\n })\n }\n }\n }\n\n // Only the unenumerated, non-generic case needs the old generic warning: a list\n // with no generic tail is a list with nothing to fall back to.\n if (\n families.length > 0 &&\n !families.some((family) => isGenericName(family.toLowerCase(), GENERICS))\n ) {\n // A note about the document as a whole belongs to no character, so its range is\n // empty and sits at the end. Underlining an entry to say the LIST is incomplete\n // would put a squiggle on text that is perfectly correct — and, because a\n // diagnostic outranks a description in a tooltip, it would also hide what that\n // entry has to say about itself.\n problems.push({\n from: text.length,\n to: text.length,\n message:\n 'No generic family at the end, so a name that fails to resolve has nothing to fall back to. Adding one, such as `sans-serif`, is free.',\n code: 'no-generic-fallback',\n severity: 'info',\n })\n }\n\n return { entries, families, effective, weight, weightWord, problems }\n },\n\n validate: (context) => {\n for (const problem of context.state.problems) {\n context.report({\n from: problem.from,\n to: problem.to,\n message: problem.message,\n code: problem.code,\n severity: problem.severity,\n })\n }\n },\n\n // ── the family in effect, marked rather than recoloured ───────────────\n // It is a decoration and not a scope because it depends on the machine, not on\n // the characters: the same text means something else on a computer with\n // different fonts, and re-lexing the document whenever the catalogue changed\n // would be the wrong shape of work.\n decorate: (_text, state) => {\n const decorations: Decoration[] = []\n if (state.effective < 0) return decorations\n const family = state.families[state.effective] ?? ''\n const target = state.entries.find((candidate) => candidate.name.trim() === family)\n if (target !== undefined) {\n decorations.push({\n from: target.nameFrom,\n to: target.nameFrom + target.name.length,\n kind: 'effective',\n title: `in effect: ${family}`,\n })\n }\n return decorations\n },\n\n // ── what can come next ────────────────────────────────────────────────\n compose: [\n {\n id: 'family',\n // The whole query is entries, so this source is always eligible; the\n // entry under the caret decides what it replaces.\n when: () => true,\n range: (context) => entryRange(context.state, context.caret),\n items: (context) => {\n const entry = entryAt(context.state.entries, context.caret)\n const core = entry?.core ?? ''\n const quoted = entry?.quoted === true\n // The needle is the FAMILY part of the entry: a weight word the entry\n // already carries would otherwise make `\"Geist Mono\" medium` match no\n // family at all.\n const inner = unquote(core)\n const carried = entry?.word\n const needle = carried === undefined ? inner.trim() : inner.slice(0, -(carried.length)).trim()\n const exact = findExact(SUGGESTION_SPACE, needle)\n // What the caret has already spelled, with any weight word still to come\n // left out. This is what makes `Geist Mono b` offer Geist Mono's weights:\n // the entry as a whole is not a family name, but the part before the word\n // being typed is. Without this fallback a weight becomes unreachable the\n // moment the first letter of it is typed.\n const headFrom = entry?.coreFrom ?? context.word.from\n const head = unquote(context.text.slice(headFrom, Math.max(context.word.from, headFrom))).trim()\n // Where the caret sits decides whether a pick replaces the entry or is\n // inserted ahead of it. A caret at the very start of a COMPLETE entry is\n // a boundary, not an edit: the user put it there to place another family\n // in front, which is how a fallback stays a fallback.\n const atBoundary = entry !== undefined && context.caret <= entry.coreFrom && exact !== undefined\n\n const familyInEntry = exact ?? findExact(SUGGESTION_SPACE, head)\n // Where the caret sits decides what leads. Past the family name the user\n // is reaching for a weight (`Geist Mono b` → Bold); inside the name they\n // are still spelling it out, so the family list leads and the list never\n // fills with weights while a name is half-written.\n const atFamilyEnd = entry === undefined || context.caret >= entry.wordFrom\n\n // A weight is only offered once the entry names a family.\n const weightRows: SuggestionItem[] = []\n if (familyInEntry !== undefined && !atBoundary && atFamilyEnd) {\n const detected = fontFaceWeights(lookupStyles(STYLES, familyInEntry))\n const pool = detected.length > 0 ? detected : [...FONT_WEIGHT_SCALE]\n const typedWord = context.word.prefix.toLowerCase()\n for (const value of pool) {\n const word = fontWeightWord(value)\n if (typedWord !== '' && !word.startsWith(typedWord)) continue\n weightRows.push({\n label: `${familyInEntry} ${word}`,\n insert: quoteFontFamily(familyInEntry) + (value === SHIPPED_WEIGHT ? '' : ` ${word}`),\n kind: 'weight',\n detail: `font-weight ${String(value)}`,\n documentation:\n value === SHIPPED_WEIGHT\n ? 'The weight this axis already uses, so picking it takes the word away rather than spelling out a value nobody chose.'\n : undefined,\n // A weight's position is decided by the SCALE and not by the length of\n // its label, which is what the zero-padded key is for: without it the\n // shortest word would lead, so `bold` would sit above the shipped\n // `regular` and the list would look shuffled. The weight the entry\n // already states outranks all of them, so an Enter that accepts the top\n // row re-applies what is written.\n sortText:\n word === carried ? '0' : `1${String(value).padStart(3, '0')}`,\n })\n }\n }\n\n const familyRows: SuggestionItem[] = []\n for (const name of SUGGESTION_SPACE) {\n const generic = isGenericName(name.toLowerCase(), GENERICS)\n familyRows.push({\n label: name,\n // A completion never drops a weight the entry already states: the\n // word travels with the pick, so swapping the family does not quietly\n // reset the weight.\n insert: quoteFontFamily(name) + (carried === undefined ? '' : ` ${carried}`),\n mode: atBoundary ? 'before' : 'replace',\n // A comma invites the next fallback. Only after a family, never after\n // a weight, which completes the entry instead of starting one.\n append: atBoundary || lastEntry(context.state, context.caret) ? ', ' : '',\n kind: generic ? 'generic' : 'family',\n detail: generic\n ? 'generic family'\n : KNOWN.has(name.toLowerCase())\n ? 'installed'\n : 'suggested',\n // After the weights when weights lead, which is the whole reason a\n // grammar gets to name the group: `2` sorts above `1xxx` and below `0`.\n sortText: weightRows.length > 0 ? '2' : '0',\n })\n }\n\n const rows = weightRows.length > 0 ? [...weightRows, ...familyRows] : familyRows\n // The entry exactly as typed, so a name nobody catalogued can still be\n // completed to itself rather than being impossible to accept.\n if (needle !== '' && exact === undefined && !isGenericName(needle.toLowerCase(), GENERICS)) {\n rows.push({\n label: inner,\n insert: inner,\n kind: 'custom',\n detail: 'as typed',\n documentation:\n 'Written exactly as it stands. A name the browser does not have is still a valid declaration: it is what lets a stack work on a machine this one cannot see.',\n sortText: '3',\n })\n }\n return rows\n },\n },\n ],\n\n // ── what a thing is ───────────────────────────────────────────────────\n describe: (context) => {\n const token = context.token\n if (token === undefined) return undefined\n const state = context.state\n const entry = entryAt(state.entries, context.offset)\n\n if (token.scope === SCOPE.separator) return undefined\n\n if (token.scope === SCOPE.weight || token.scope === SCOPE.weightMissing) {\n const word = token.text.toLowerCase()\n const value = FONT_WEIGHT_WORDS[word]\n const family = state.effective >= 0 ? state.families[state.effective] : undefined\n if (value === undefined) return { title: token.text }\n const faces = family === undefined ? [] : fontFaceWeights(lookupStyles(STYLES, family))\n return {\n title: `${word} — font-weight ${String(value)}`,\n detail: entry?.name === '' ? 'applies to the whole axis' : `applies to ${family ?? 'the first family'}`,\n body:\n faces.length === 0\n ? `${family ?? 'This family'} was not read, so whether it has a ${String(value)} face is unknown.`\n : faces.includes(value)\n ? `${family ?? 'This family'} has this face.`\n : `${family ?? 'This family'} has no ${String(value)} face, so the browser will synthesise one.`,\n }\n }\n\n if (token.scope === SCOPE.generic) {\n return {\n title: token.text,\n detail: 'a generic CSS family',\n body: 'Always valid, and only useful at the end of the list: it is what the browser falls back to when nothing before it resolves.',\n }\n }\n\n if (token.scope === SCOPE.unclosed) {\n return {\n title: token.text,\n detail: 'unclosed quote',\n body: 'The closing quote is missing, so this and everything after it are read as one family name. A font family containing a quote character has to be written with the other quote style, because backslash escapes are deliberately not interpreted.',\n }\n }\n\n if (entry !== undefined && entry.kind === 'unknown') {\n return {\n title: entry.name,\n detail: 'not installed here',\n body: 'Still a valid declaration: it is written to the setting, and the browser falls through to the next family in the list when it cannot resolve. Reordering it to the end of the list is what the fallbacks are for.',\n }\n }\n\n const entryDoc = FAMILY_VOCAB.entryFor(token.text)\n const installed = KNOWN.has(token.text.toLowerCase())\n const faces = fontFaceWeights(lookupStyles(STYLES, token.text))\n return {\n title: token.text,\n detail: installed ? 'installed' : 'not read on this machine',\n body:\n entryDoc?.body ??\n (faces.length > 0\n ? `Faces read from this machine: ${faces.join(', ')}.`\n : 'This family has no faces recorded, so its weights are unknown rather than absent.'),\n }\n },\n })\n}\n\n/** The scope a closed quoted entry is painted with. */\nfunction quotedScope(\n text: string,\n known: ReadonlySet<string>,\n generics: readonly string[],\n enumerated: boolean,\n): Scope {\n const quote = text.charAt(0)\n const inner = text.length >= 2 && text.endsWith(quote) ? text.slice(1, -1) : text.slice(1)\n const lower = inner.trim().toLowerCase()\n if (lower === '') return SCOPE.family\n if (generics.includes(lower)) return SCOPE.generic\n if (known.has(lower)) return SCOPE.family\n return enumerated ? SCOPE.unknown : SCOPE.family\n}\n\n/** Take one matching pair of surrounding quotes off a name. */\nfunction unquote(name: string): string {\n const text = String(name)\n const quote = text.charAt(0)\n if ((quote === '\"' || quote === \"'\") && text.length >= 2 && text.endsWith(quote)) {\n return text.slice(1, -1)\n }\n return text\n}\n\n/** The entry an offset falls in, when it falls in one. */\nfunction entryAt(entries: readonly DshFontEntry[], offset: number): DshFontEntry | undefined {\n for (const entry of entries) {\n if (offset >= entry.from && offset <= entry.to) return entry\n }\n return entries[entries.length - 1]\n}\n\n/**\n * The range a completion over the caret replaces: the CORE of the entry it sits\n * in, without the whitespace around it.\n *\n * The whitespace is left out on purpose, and it matters twice. It keeps the\n * replacement from swallowing the separator that belongs to the comma before it,\n * and it keeps the needle honest — the text between the range's start and the\n * caret is what the list is filtered by, and a leading space in it would match\n * nothing while looking like it should match everything.\n * @param state - the analysis.\n * @param caret - the caret offset.\n * @returns the range to replace.\n */\nfunction entryRange(state: DshFontState, caret: number): { from: number; to: number } {\n const entry = entryAt(state.entries, caret)\n return entry === undefined ? { from: caret, to: caret } : { from: entry.coreFrom, to: entry.coreTo }\n}\n\n/** Whether the caret's entry is the last one in the document. */\nfunction lastEntry(state: DshFontState, caret: number): boolean {\n const entry = entryAt(state.entries, caret)\n return entry === undefined || entry === state.entries[state.entries.length - 1]\n}\n\n/** Case-insensitive exact lookup in a suggestion space. */\nfunction findExact(names: readonly string[], needle: string): string | undefined {\n const lower = needle.toLowerCase()\n return names.find((name) => name.toLowerCase() === lower)\n}\n\n/** The face style names of a family, matched without regard to case. */\nfunction lookupStyles(\n styles: Readonly<Record<string, readonly string[]>>,\n family: string,\n): readonly string[] | undefined {\n if (Object.hasOwn(styles, family)) return styles[family]\n const lower = family.toLowerCase()\n for (const [name, faces] of Object.entries(styles)) {\n if (name.toLowerCase() === lower) return faces\n }\n return undefined\n}\n\n/** A diagnostic the grammar rates as informational rather than as a mistake. */\nexport const DSH_FONT_INFO_CODES: readonly string[] = ['no-generic-fallback']\n","// ─── text: offsets, lines, and words ────────────────────────────────────────\n//\n// The engine counts in character offsets and nothing else. Not rows, not\n// columns, not pixels: every position that crosses a module boundary in litearea\n// is an offset into the document string, so there is exactly one coordinate\n// system to get wrong instead of three that must be kept in step.\n//\n// Pixels enter only in `src/dom/`, only to place the popup, and never travel\n// back inward. That boundary is the fix for a whole family of bugs in the\n// editors this library replaces, where a caret was tracked as a character index\n// in one place and read back as a screen position in another.\n\nimport type { LineInfo, Range, Token, WordInfo } from './types.js'\n\n/** Keeps a number inside a range, which every caller here needs and none should repeat. */\nexport function clamp(value: number, low: number, high: number): number {\n return value < low ? low : value > high ? high : value\n}\n\n/** Whether a value is a usable offset: a finite, non-negative integer. */\nexport function isOffset(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 0\n}\n\n/**\n * The offset each line starts at, in order. The first entry is always `0`.\n *\n * `\\r\\n`, `\\n`, and a lone `\\r` all end a line, because this text is typed by\n * hand into a textarea and a paste from a Windows editor must not read as one\n * long line. The terminator itself belongs to no line: a line's text excludes it\n * so that column arithmetic never has to reason about a stray carriage return.\n * @param source - the document.\n * @returns one offset per line, ascending.\n */\nexport function lineStarts(source: string): number[] {\n const starts = [0]\n for (let index = 0; index < source.length; index += 1) {\n const code = source.charCodeAt(index)\n if (code === 10) {\n starts.push(index + 1)\n } else if (code === 13) {\n if (source.charCodeAt(index + 1) === 10) index += 1\n starts.push(index + 1)\n }\n }\n return starts\n}\n\n/**\n * The index of the line an offset falls on.\n * @param starts - the result of {@link lineStarts}.\n * @param offset - a character offset.\n * @returns a zero-based line index.\n */\nexport function lineIndexAt(starts: readonly number[], offset: number): number {\n let low = 0\n let high = starts.length - 1\n while (low < high) {\n const middle = Math.ceil((low + high) / 2)\n if ((starts[middle] ?? 0) <= offset) low = middle\n else high = middle - 1\n }\n return low\n}\n\n/**\n * The line an offset falls on, with the offset expressed inside it.\n *\n * `before` and `after` are the line's own text split at the caret, which is what\n * completion and the indentation rules actually want; handing them out here\n * means neither has to re-derive the split and get it subtly different.\n * @param source - the document.\n * @param offset - a character offset; clamped into the document.\n * @param starts - the result of {@link lineStarts}, when the caller already has it.\n * @returns the line, its bounds, and the caret's place in it.\n */\nexport function lineAt(source: string, offset: number, starts?: readonly number[]): LineInfo {\n const position = clamp(offset, 0, source.length)\n const boundaries = starts ?? lineStarts(source)\n const index = lineIndexAt(boundaries, position)\n const from = boundaries[index] ?? 0\n const rawTo = boundaries[index + 1] ?? source.length\n // The next line's start sits after the terminator, so the last character of\n // the raw slice is the terminator itself — one character, or two for `\\r\\n`.\n let to = rawTo\n while (to > from) {\n const code = source.charCodeAt(to - 1)\n if (code === 10 || code === 13) to -= 1\n else break\n }\n const text = source.slice(from, to)\n const column = clamp(position - from, 0, text.length)\n return {\n from,\n to,\n text,\n number: index,\n column,\n before: text.slice(0, column),\n after: text.slice(column),\n }\n}\n\n/**\n * Whether a character is part of a word.\n *\n * The predicate is supplied by the grammar because it decides three things at\n * once — what a completion replaces, what a diagnostic underlines, and where a\n * double click puts the selection — and a language whose names contain a hyphen\n * must say so or every completion will replace one segment of a name instead of\n * the name.\n * @param char - one character, or the empty string at the end of the document.\n * @param wordChars - a single-character test.\n * @returns whether the character continues a word.\n */\nexport function isWordChar(char: string, wordChars: RegExp): boolean {\n return char !== '' && wordChars.test(char)\n}\n\n/**\n * The word at an offset.\n *\n * The word is found by expanding in BOTH directions from the offset rather than\n * by requiring the offset to be strictly inside a word. Completion needs the\n * second reading: a caret sitting at `Geist|` is at the end of the word, and the\n * word it is completing is still `Geist` — a lookup that insisted the offset be\n * interior would find nothing at exactly the moment the user wants a list.\n * @param source - the document.\n * @param offset - a character offset; clamped into the document.\n * @param wordChars - a single-character test.\n * @returns the word, its range, and the text either side of the caret.\n */\nexport function wordInfoAt(source: string, offset: number, wordChars: RegExp): WordInfo {\n const position = clamp(offset, 0, source.length)\n let from = position\n let to = position\n while (from > 0 && isWordChar(source.charAt(from - 1), wordChars)) from -= 1\n while (to < source.length && isWordChar(source.charAt(to), wordChars)) to += 1\n const text = source.slice(from, to)\n const column = position - from\n return {\n from,\n to,\n text,\n prefix: text.slice(0, column),\n suffix: text.slice(column),\n }\n}\n\n/** Whether a range is empty. */\nexport function isEmptyRange(range: Range): boolean {\n return range.to <= range.from\n}\n\n/** Whether an offset lies inside a range, with `to` exclusive. */\nexport function containsOffset(range: Range, offset: number): boolean {\n return offset >= range.from && offset < range.to\n}\n\n// ─── reading the token stream ───────────────────────────────────────────────\n\n/**\n * The token covering an offset.\n *\n * Zero-length tokens are skipped, so a caret at a boundary resolves to the token\n * it is *inside* rather than to an empty marker sitting on the seam.\n * @param tokens - the scanned tokens, ascending.\n * @param offset - a character offset.\n * @returns the covering token, or undefined in whitespace.\n */\nexport function tokenAt(tokens: readonly Token[], offset: number): Token | undefined {\n for (const token of tokens) {\n if (token.from <= offset && offset < token.to) return token\n if (token.from > offset) break\n }\n return undefined\n}\n\n/**\n * The scope painted at an offset, when there is one.\n * @param tokens - the scanned tokens, ascending.\n * @param offset - a character offset.\n * @returns the scope, or undefined in whitespace.\n */\nexport function scopeAt(tokens: readonly Token[], offset: number): string | undefined {\n return tokenAt(tokens, offset)?.scope\n}\n\n/**\n * The nearest token that ends at or before an offset, skipping whitespace.\n *\n * Whitespace is skipped because every caller is asking a question about\n * structure — \"which slot is this word in?\" — and a space is never an answer.\n * @param tokens - the scanned tokens, ascending.\n * @param offset - a character offset.\n * @returns the token, or undefined at the start of the document.\n */\nexport function tokenBefore(tokens: readonly Token[], offset: number): Token | undefined {\n let found\n for (const token of tokens) {\n if (token.to > offset) break\n if (token.text.trim() !== '') found = token\n }\n return found\n}\n\n/**\n * The nearest token that starts at or after an offset, skipping whitespace.\n * @param tokens - the scanned tokens, ascending.\n * @param offset - a character offset.\n * @returns the token, or undefined at the end of the document.\n */\nexport function tokenAfter(tokens: readonly Token[], offset: number): Token | undefined {\n for (const token of tokens) {\n if (token.to <= offset) continue\n if (token.text.trim() !== '') return token\n }\n return undefined\n}\n\n/**\n * The non-whitespace tokens on one line, in order.\n *\n * Completion and diagnostics both ask \"what is on this line so far\", and both\n * must ignore the indentation and the gaps between words. Returning the tokens\n * rather than the words means a grammar can ask what they *were* (their scopes)\n * and not only what they said.\n * @param tokens - the scanned tokens, ascending.\n * @param line - a line number, or a line record.\n * @returns the tokens on that line.\n */\nexport function tokensOnLine(\n tokens: readonly Token[],\n line: number | LineInfo,\n): Token[] {\n const number = typeof line === 'number' ? line : line.number\n return tokens.filter((token) => token.line === number && token.text.trim() !== '')\n}\n","// ─── dsh-sentry's style document, as a litearea grammar ─────────────────────\n//\n// The language is line-oriented: a line names one of the plugin's states and then\n// says what that state looks like, either as bare words or as `key=value` pairs.\n//\n// # comments and blank lines are ignored\n// running circle blue turn 3\n// waiting rounded amber blink 1.1\n// approval rounded amber blink 1.9\n// done circle green flush 1.6\n//\n// running shape=none color=gray motion=still speed=1\n//\n// A bare word goes into the first positional slot the line has not filled, in the\n// order shape, colour, pattern, motion, speed — except that the value sets are\n// disjoint, so in practice the *word itself* says where it goes and the slot order\n// only decides what a word that fits nothing is measured against. That is the\n// plugin's own reading of the language and this grammar reproduces it.\n//\n// This is a REFERENCE grammar, not a built-in one. litearea ships no syntax of its\n// own and nothing in `src/core/` knows this language exists; the file is here to\n// prove that a fully custom rule set can express a real DSL, to be the worked\n// example the documentation points at, and to be copied or imported by a host.\n//\n// Why the lexical layer cannot validate an option's value\n// ------------------------------------------------------\n// It is worth stating, because it is the first thing a grammar author tries. The\n// obvious rule is \"a word after `=` must be one of the shape words\", and it is\n// wrong: the rule can see the `=` but not the KEY, so it cannot tell `shape=blue`\n// from `color=blue`. Written that way, `color=blue` earns a complaint that blue is\n// not a shape. The key is structural information, so option values are validated by\n// the structural pass below and only the line-leading state word is validated\n// lexically, where nothing shares its position and there is nothing to confuse it\n// with.\n//\n// Deliberately stricter than the host parser\n// ------------------------------------------\n// `parseStyle` in the plugin does no value checking for a known option: it writes\n// `shape=bogus` into the rule and lets `resolveLook` quietly substitute the shipped\n// default later. Nothing tells the user, and a typo shows up as an icon that simply\n// never changed. This grammar reports it, as a warning rather than an error, since\n// the document still works — it just does not mean what it says.\n//\n// It also does NOT accept `fallback`. The plugin's module comment shows a\n// `fallback none` line, but `STYLE_STATES` holds only the four states and any other\n// leading word is reported as an unknown state; `fallback` is derived internally\n// from `STYLE_FALLBACK_LOOK` and has never been parseable. The comment is stale,\n// and copying it here would have made the editor disagree with the parser it edits\n// for.\n\nimport type {\n Grammar,\n ResolvedVocabulary,\n Scope,\n Severity,\n SuggestionItem,\n} from '../core/types.js'\nimport { defineGrammar } from '../core/grammar.js'\nimport { defineVocabulary, type VocabularySpec } from '../core/vocabulary.js'\nimport { lineStarts } from '../core/text.js'\n\n/** One positional slot of a state line, in the order a bare word fills them. */\nexport type DshSentrySlot = 'shape' | 'color' | 'pattern' | 'motion' | 'speed'\n\n/** The four facts one state's appearance is made of. */\nexport interface DshSentryLook {\n shape: string\n color: string\n pattern: string\n motion: string\n speed: number\n}\n\n/** One word of the document, with the range it occupies. */\nexport interface DshSentryWord {\n text: string\n from: number\n to: number\n}\n\n/** A problem the structural walk found, ready to be reported. */\nexport interface DshSentryProblem {\n from: number\n to: number\n message: string\n code: string\n severity: Severity\n}\n\n/** One line, read. */\nexport interface DshSentryLine {\n /** Zero-based line number, so a completion can find the line the caret is on. */\n number: number\n /** The state the line opens, as written. */\n state: string | undefined\n /** Whether that state is one this document understands. */\n known: boolean\n /** The words on the line, comments removed. */\n words: DshSentryWord[]\n /** The value each positional slot ended up with, whatever syntax put it there. */\n slots: Partial<Record<DshSentrySlot, string>>\n /** The option keys the line named, in order, whether or not they are known. */\n keys: string[]\n /** The option key whose value the line has not written yet, as `speed=`. */\n pendingKey: string | undefined\n}\n\n/** What one pass over the document produced. */\nexport interface DshSentryState {\n lines: DshSentryLine[]\n /** What the structural walk found. `validate` reports these verbatim. */\n problems: DshSentryProblem[]\n}\n\n/** The vocabularies and shipped defaults a host may override. */\nexport interface DshSentryStyleOptions {\n /** The states a document may address, in the order the list shows them. */\n states?: readonly string[]\n /** The background shapes a rule may name. */\n shapes?: readonly string[]\n /** The motions a rule may apply. */\n motions?: readonly string[]\n /** The patterns still accepted as `pattern=<name>`. */\n patterns?: readonly string[]\n /** The named palette. Presets on purpose: a free colour can be illegible. */\n colors?: Readonly<Record<string, string>>\n /** The option keys a rule may write. */\n options?: readonly string[]\n /** The shipped look per state, used to rank and to document. */\n defaults?: Readonly<Record<string, DshSentryLook>>\n}\n\n// ─── the shipped vocabulary ─────────────────────────────────────────────────\n//\n// Every word below is verbatim from the plugin, including the palette, whose eight\n// members exist because the two contrast failures that plugin has already shipped\n// were both free colour choices. A preset cannot be illegible, so the set is closed\n// and the editor must not offer anything else.\n\nconst DEFAULT_STATES = ['running', 'waiting', 'approval', 'done']\nconst DEFAULT_SHAPES = ['circle', 'rounded', 'square', 'none']\nconst DEFAULT_MOTIONS = ['still', 'turn', 'blink', 'flush']\nconst DEFAULT_PATTERNS: readonly string[] = []\nconst DEFAULT_COLORS: Readonly<Record<string, string>> = {\n blue: '#4d6bfe',\n amber: '#f59e0b',\n green: '#22c55e',\n red: '#ef4444',\n purple: '#8b5cf6',\n gray: '#8b8f97',\n dark: '#23262c',\n light: '#eef0f3',\n}\nconst DEFAULT_OPTIONS = ['shape', 'color', 'pattern', 'motion', 'speed', 'bg']\nconst DEFAULT_SLOTS: readonly DshSentrySlot[] = ['shape', 'color', 'pattern', 'motion', 'speed']\nconst DEFAULT_LOOK: Readonly<Record<string, DshSentryLook>> = {\n running: { shape: 'circle', color: 'blue', pattern: 'none', motion: 'turn', speed: 3 },\n waiting: { shape: 'rounded', color: 'amber', pattern: 'none', motion: 'blink', speed: 1.1 },\n approval: { shape: 'rounded', color: 'amber', pattern: 'none', motion: 'blink', speed: 1.9 },\n done: { shape: 'circle', color: 'green', pattern: 'none', motion: 'flush', speed: 1.6 },\n}\n\n/** The scope each slot's values are painted under. */\nconst SLOT_SCOPE: Record<DshSentrySlot, Scope> = {\n shape: 'value.shape',\n color: 'value.color',\n pattern: 'value.pattern',\n motion: 'value.motion',\n speed: 'value.number',\n}\n\n/** Which positional slot an option key writes. `bg` is an alias for `color`. */\nconst KEY_SLOT: Record<string, DshSentrySlot | undefined> = {\n shape: 'shape',\n color: 'color',\n bg: 'color',\n pattern: 'pattern',\n motion: 'motion',\n speed: 'speed',\n}\n\n/** The nine colours, so a message can list them without resolving a vocabulary. */\nconst COLOR_NAMES_OF = (colors: Readonly<Record<string, string>>): string[] => Object.keys(colors)\n\n/**\n * A vocabulary, with the one setting this grammar always wants.\n *\n * `caseSensitive` is on for every word here because the host parser compares with\n * `includes` on the literal: a suggestion list that accepted `Circle` would be\n * teaching a spelling the plugin then rejects.\n * @param spec - the declaration, minus the repeated setting.\n * @returns the resolved vocabulary.\n */\nfunction closed<State>(spec: VocabularySpec<State>): ResolvedVocabulary<State> {\n return defineVocabulary<State>({ ...spec, caseSensitive: true })\n}\n\n/**\n * Build the grammar for dsh-sentry's style document.\n * @param options - the vocabularies and shipped defaults, defaulting to the plugin's.\n * @returns a grammar that paints, completes, diagnoses, and explains the language.\n */\nexport function dshSentryStyleGrammar(\n options: DshSentryStyleOptions = {},\n): Grammar<DshSentryState> {\n const STATES = options.states ?? DEFAULT_STATES\n const SHAPES = options.shapes ?? DEFAULT_SHAPES\n const MOTIONS = options.motions ?? DEFAULT_MOTIONS\n const PATTERNS = options.patterns ?? DEFAULT_PATTERNS\n const COLORS = options.colors ?? DEFAULT_COLORS\n const COLOR_NAMES = COLOR_NAMES_OF(COLORS)\n const OPTIONS = options.options ?? DEFAULT_OPTIONS\n const LOOK = options.defaults ?? DEFAULT_LOOK\n const SLOTS = DEFAULT_SLOTS\n /** The patterns a bare word may name. Empty in this build, and that is the shipped truth. */\n const PATTERN_WORDS = PATTERNS.length > 0 ? PATTERNS : ['none']\n\n // ── vocabularies ────────────────────────────────────────────────────────\n // Declared once each so the word set, the paint, the hover text, and the\n // completion list cannot disagree. Nothing here carries `unknownMessage` except\n // the state vocabulary, because nothing else can be validated from a token: see\n // the header note about the key a lexical rule cannot see.\n\n const STATE_VOCAB = closed({\n id: 'state',\n words: STATES,\n scope: 'state',\n unknownMessage: 'Unknown state \"{word}\" — this document understands {allowed}.',\n docs: {\n running: { detail: 'a turn is in progress', body: 'The agent is working and does not need anyone.' },\n waiting: { detail: 'a question is waiting', body: 'The agent asked something, and the turn is blocked until it is answered.' },\n approval: { detail: 'a permission is waiting', body: 'The agent requested an escalation or a plan review, and the turn is blocked on it.' },\n done: { detail: 'the turn finished', body: 'The agent stopped and left the tab alone.' },\n },\n })\n\n const SHAPE_VOCAB = closed({\n id: 'shape',\n words: SHAPES,\n scope: SLOT_SCOPE.shape,\n docs: {\n circle: { detail: 'a full disc' },\n rounded: { detail: 'a rounded square' },\n square: { detail: 'a square with sharp corners' },\n none: {\n detail: 'no background',\n body: 'The fish alone, on whatever the tab gives it. A bare `none` is a SHAPE and never a pattern: one word cannot mean two things.',\n },\n },\n })\n\n const COLOR_VOCAB = closed({\n id: 'color',\n words: COLOR_NAMES,\n scope: SLOT_SCOPE.color,\n docs: Object.fromEntries(Object.entries(COLORS).map(([name, hex]) => [name, { detail: hex }])),\n })\n\n const MOTION_VOCAB = closed({\n id: 'motion',\n words: MOTIONS,\n scope: SLOT_SCOPE.motion,\n docs: {\n still: { detail: 'nothing moves' },\n turn: { detail: 'rotates', body: 'speed is seconds per revolution.' },\n blink: { detail: 'alternates', body: 'speed is seconds per cycle.' },\n flush: { detail: 'pulses', body: 'speed is seconds per cycle.' },\n },\n })\n\n const PATTERN_VOCAB = closed({\n id: 'pattern',\n words: PATTERN_WORDS,\n scope: SLOT_SCOPE.pattern,\n docs: {\n none: {\n detail: 'carve nothing',\n body: 'Every dial-like pattern was tried on a real 16px favicon and read as noise, so `none` is the only pattern left. It is written as `pattern=none` and never as a bare word, because `none` is also a shape.',\n },\n },\n })\n\n /** What each option key explains about itself. */\n const KEY_DOCS: Record<string, { detail: string; body: string }> = {\n shape: { detail: 'background shape', body: `One of ${SHAPES.join(', ')}.` },\n color: { detail: 'disc colour', body: `${COLOR_NAMES.join(', ')} — all presets, chosen so the fish stays legible.` },\n pattern: { detail: 'carved pattern', body: 'Only `none` remains; write it as `pattern=none`.' },\n motion: { detail: 'what moves', body: `One of ${MOTIONS.join(', ')}.` },\n speed: { detail: 'seconds per cycle', body: 'A number: seconds per revolution for `turn`, seconds per cycle otherwise.' },\n bg: { detail: 'an alias for color', body: 'Kept so a document written against an earlier release still says what it means.' },\n }\n\n /** Every vocabulary, by the scope its words are painted under, for hover. */\n const BY_SCOPE = new Map<Scope, ResolvedVocabulary<DshSentryState>>([\n ['state', STATE_VOCAB],\n [SLOT_SCOPE.shape, SHAPE_VOCAB],\n [SLOT_SCOPE.color, COLOR_VOCAB],\n [SLOT_SCOPE.pattern, PATTERN_VOCAB],\n [SLOT_SCOPE.motion, MOTION_VOCAB],\n ])\n\n /** The vocabulary that decides a value written for an option key. */\n const VOCAB_FOR_KEY: Record<string, ResolvedVocabulary<DshSentryState>> = {\n shape: SHAPE_VOCAB,\n color: COLOR_VOCAB,\n bg: COLOR_VOCAB,\n pattern: PATTERN_VOCAB,\n motion: MOTION_VOCAB,\n }\n\n /** The words a slot accepts, for both a message and a completion list. */\n const wordsForSlot = (slot: string): readonly string[] => {\n if (slot === 'shape') return SHAPES\n if (slot === 'color' || slot === 'bg') return COLOR_NAMES\n if (slot === 'motion') return MOTIONS\n if (slot === 'pattern') return PATTERN_WORDS\n return []\n }\n\n /**\n * What a slot expects, in words, for a diagnostic message.\n * @param slot - a positional slot name, or an option key such as `bg`.\n * @returns a readable list.\n */\n const expectedList = (slot: string): string => {\n if (slot === 'speed') return 'a number of seconds, such as 3 or 1.1'\n const words = wordsForSlot(slot)\n if (words.length === 0) return `pattern=<name>`\n return words.join(', ')\n }\n\n /**\n * Whether a value written for an option key is acceptable.\n * @param key - the option key.\n * @param value - the value as written.\n * @returns a complaint, or undefined when the value is fine.\n */\n const valueProblem = (key: string, value: string): string | undefined => {\n if (key === 'speed') {\n return Number.isFinite(Number.parseFloat(value))\n ? undefined\n : `\"${value}\" is not a speed — write a number of seconds, such as 3 or 1.1. The shipped rate is used instead.`\n }\n if (VOCAB_FOR_KEY[key] === undefined) return undefined\n const words = wordsForSlot(key)\n if (words.includes(value)) return undefined\n const noun = key === 'bg' ? 'preset colour' : key\n return `\"${value}\" is not a ${noun} — expected ${words.join(', ')}. The shipped default is used instead.`\n }\n\n return defineGrammar<DshSentryState>({\n id: 'dsh-sentry-style',\n name: 'dsh-sentry style document',\n\n // A decimal speed is one token because the number RULE says so, not because `.`\n // is a word character. Leaving `.` out of the predicate stops a stray\n // `circle.` from being read as one word, matching no shape, and earning a\n // diagnostic about a word the user never typed.\n wordChars: /[\\p{L}\\p{N}_]/u,\n\n rules: [\n { kind: 'match', scope: 'comment', pattern: /#[^\\n]*/ },\n\n // The first word on a line is a state or it is a mistake. `unknown: {}` asks\n // for the vocabulary's own rejection, and this is the one place in the\n // language where the lexical layer can be that sure: nothing else may stand\n // at the head of a line, so there is no later rule to wait for.\n {\n kind: 'words',\n words: STATE_VOCAB,\n when: { firstOnLine: true },\n unknown: {},\n },\n\n // `shape=` — the key, seen from the `=` so it cannot also swallow a value.\n { kind: 'match', scope: 'property', pattern: /[A-Za-z][\\w-]*(?==)/ },\n { kind: 'match', scope: 'operator', pattern: /=/ },\n { kind: 'match', scope: 'separator', pattern: /,/ },\n\n // Values. The sets are disjoint, so membership alone places a bare word, and\n // none of these rules rejects: a rule that did would claim a word belonging\n // to the next vocabulary down the list.\n { kind: 'words', words: SHAPE_VOCAB },\n { kind: 'words', words: COLOR_VOCAB },\n { kind: 'words', words: MOTION_VOCAB },\n { kind: 'match', scope: SLOT_SCOPE.speed, pattern: /\\d+(?:\\.\\d+)?/ },\n\n // Anything left is a word this language does not know. Painting it as invalid\n // rather than as plain text makes a typo visible before the structural pass\n // has even run, and that pass supplies the precise message.\n { kind: 'match', scope: 'invalid', pattern: /\\S+/ },\n ],\n\n fallbackScope: 'text',\n\n // ── what the document means ───────────────────────────────────────────\n //\n // This walk decides the slot filling AND records what went wrong, rather than\n // leaving the second job to a second walk. They are the same decision: the only\n // reason to know which slot is free is to say what a word that fits nothing\n // should have been, and splitting them would mean two implementations of one\n // rule — which is exactly how the editors this library replaces came to\n // disagree with themselves.\n analyze: (text) => {\n const starts = lineStarts(text)\n const lines: DshSentryLine[] = []\n const problems: DshSentryProblem[] = []\n\n for (let number = 0; number < starts.length; number += 1) {\n const from = starts[number] ?? 0\n const rawTo = starts[number + 1] ?? text.length\n let to = rawTo\n while (to > from && (text.charAt(to - 1) === '\\n' || text.charAt(to - 1) === '\\r')) to -= 1\n const raw = text.slice(from, to)\n // The host parser splits the comment off at the first `#` anywhere on the\n // line, so a `#` inside a value begins a comment there too.\n const comment = raw.indexOf('#')\n const body = comment === -1 ? raw : raw.slice(0, comment)\n\n const words: DshSentryWord[] = []\n const wordPattern = /[^\\s,]+/g\n let match: RegExpExecArray | null\n while ((match = wordPattern.exec(body)) !== null) {\n words.push({\n text: match[0],\n from: from + match.index,\n to: from + match.index + match[0].length,\n })\n }\n\n const line: DshSentryLine = {\n number,\n state: undefined,\n known: true,\n words,\n slots: {},\n keys: [],\n pendingKey: undefined,\n }\n lines.push(line)\n\n const first = words[0]\n if (first === undefined) continue\n line.state = first.text\n line.known = STATES.includes(first.text)\n // An unknown state is a dead end for the parser: it discards the rest of\n // the line, so complaining about the values on it would be inventing\n // problems the document does not have.\n if (!line.known) continue\n\n const claim = (slot: DshSentrySlot, value: string): void => {\n line.slots[slot] = value\n }\n\n for (let index = 1; index < words.length; index += 1) {\n const word = words[index]\n if (word === undefined) continue\n const equals = word.text.indexOf('=')\n const key = equals === -1 ? undefined : word.text.slice(0, equals)\n const value = equals === -1 ? undefined : word.text.slice(equals + 1)\n\n if (key !== undefined) {\n line.keys.push(key)\n // `key` exists only because the word held an `=`, so there is always a\n // right-hand side; an empty one means the value is still being typed.\n const written = value ?? ''\n if (written === '') {\n line.pendingKey = key\n continue\n }\n const complaint = valueProblem(key, written)\n if (complaint !== undefined) {\n problems.push({\n from: word.from,\n to: word.to,\n message: complaint,\n code: 'bad-option-value',\n severity: 'warning',\n })\n continue\n }\n const slot = KEY_SLOT[key]\n if (slot !== undefined) claim(slot, written)\n continue\n }\n\n // A bare word is placed by what it IS. The sets are disjoint, which is\n // what lets the position be inferred without the slot order mattering.\n if (MOTIONS.includes(word.text)) {\n claim('motion', word.text)\n continue\n }\n if (SHAPES.includes(word.text)) {\n claim('shape', word.text)\n continue\n }\n if (COLOR_NAMES.includes(word.text)) {\n claim('color', word.text)\n continue\n }\n if (PATTERNS.includes(word.text)) {\n claim('pattern', word.text)\n continue\n }\n if (Number.isFinite(Number.parseFloat(word.text))) {\n claim('speed', word.text)\n continue\n }\n\n // It fits nothing, so the host parser measures it against the first slot\n // the line has not filled — and since every value set has been ruled out\n // above, the answer can only be \"not valid for that slot\" or \"there is no\n // slot left\".\n const free = SLOTS.find((slot) => line.slots[slot] === undefined)\n if (free === undefined) {\n problems.push({\n from: word.from,\n to: word.to,\n message: `\"${word.text}\" has nowhere to go — this line already names a shape, colour, pattern, motion, and speed.`,\n code: 'unexpected-value',\n severity: 'error',\n })\n } else {\n problems.push({\n from: word.from,\n to: word.to,\n message: `\"${word.text}\" is not a valid ${free} — expected ${expectedList(free)}.`,\n code: 'bad-value',\n severity: 'error',\n })\n }\n }\n }\n\n return { lines, problems }\n },\n\n // ── what the tokens must be ───────────────────────────────────────────\n // One declarative check, because \"a key must be one it knows\" is exactly the\n // shape a check is for: a scope, an allowed set, and a message.\n checks: [\n {\n code: 'unknown-option',\n scopes: ['property'],\n allow: closed({ id: 'option', words: [...OPTIONS, ...PATTERNS] }),\n severity: 'error',\n message: 'Unknown option \"{word}\" — this document understands {allowed}.',\n },\n ],\n\n validate: (context) => {\n for (const problem of context.state.problems) {\n context.report({\n from: problem.from,\n to: problem.to,\n message: problem.message,\n code: problem.code,\n severity: problem.severity,\n })\n }\n },\n\n // ── what can come next ────────────────────────────────────────────────\n compose: [\n {\n id: 'state',\n // A state opens a line, so its list belongs at the head of one — and it has to\n // stay offered while the state is being spelled, which is why this asks\n // `firstWord` rather than `firstOnLine`. Asking the stricter question makes the\n // list vanish after the first letter, which is precisely the \"the completion\n // feels unnatural\" complaint this grammar exists to answer.\n when: (context) => context.firstWord,\n range: (context) => context.word,\n items: () =>\n STATES.map((state) => ({\n label: state,\n insert: state,\n // A space is what the next word on the line needs. The engine will not\n // add a second one if the document already has whitespace there.\n append: ' ',\n kind: 'state',\n detail: STATE_VOCAB.entryFor(state)?.detail,\n documentation: STATE_VOCAB.entryFor(state)?.body,\n sortText: '0',\n })),\n },\n {\n id: 'value',\n when: (context) => {\n const line = context.state.lines[context.line.number]\n // Values belong to a line that has opened a state, and to the part of it\n // after the state word.\n if (line === undefined || line.state === undefined || !line.known) return false\n const stateWord = line.words[0]\n return stateWord !== undefined && context.caret > stateWord.to\n },\n range: (context) => context.word,\n items: (context) => {\n const line = context.state.lines[context.line.number]\n // Inside `key=`, the key names the slot, so the list is exactly that slot's\n // vocabulary.\n const key = optionAtCaret(context.line.before)\n if (key !== undefined && key !== '') {\n return valueItems(key, line)\n }\n const free = SLOTS.find((slot) => line?.slots[slot] === undefined)\n const items: SuggestionItem[] = free === undefined ? [] : valueItems(free, line)\n // The keys follow the values: a line names values far more often than it\n // switches to the `key=value` spelling, so the values lead.\n for (const key of OPTIONS) {\n if (line?.keys.includes(key) === true) continue\n const doc = KEY_DOCS[key]\n items.push({\n label: `${key}=`,\n insert: `${key}=`,\n kind: 'property',\n detail: doc?.detail,\n documentation: doc?.body,\n sortText: '1',\n })\n }\n return items\n },\n },\n ],\n\n // ── what a thing is ───────────────────────────────────────────────────\n describe: (context) => {\n const token = context.token\n if (token === undefined) return undefined\n if (token.scope === 'comment') {\n return { title: 'comment', body: 'Ignored by the parser. A `#` anywhere on a line starts one.' }\n }\n if (token.scope === 'property') {\n const doc = KEY_DOCS[token.text]\n return doc === undefined ? undefined : { title: token.text, detail: doc.detail, body: doc.body }\n }\n if (token.scope === 'operator' || token.scope === 'separator') return undefined\n if (token.scope === 'invalid') {\n return {\n title: token.text,\n detail: 'not part of this language',\n body: 'Nothing here accepts this word: it is not a state, not one of the option keys, and not a value any slot recognises.',\n }\n }\n if (token.scope === SLOT_SCOPE.speed) {\n return {\n title: token.text,\n detail: 'seconds per cycle',\n body: 'Seconds per revolution for `turn`, seconds per cycle otherwise.',\n }\n }\n const entry = BY_SCOPE.get(token.scope)?.entryFor(token.text)\n // Nothing documented means nothing to say. Falling back to the scope name would put an\n // internal identifier in front of the user — resting the pointer on a gap in the\n // document once produced a tooltip whose only content was the word `text`.\n return entry === undefined\n ? undefined\n : { title: token.text, detail: entry.detail, body: entry.body }\n },\n })\n\n /**\n * The completion rows for one slot or option key.\n *\n * A slot already filled by the line still gets a list, because replacing a value\n * is as common as writing the first one — but its own value leads, so accepting\n * the top row changes nothing by accident.\n * @param slot - a positional slot name, or an option key such as `bg`.\n * @param line - the line the caret is on, when there is one.\n * @returns the rows, ready to rank.\n */\n function valueItems(slot: string, line: DshSentryLine | undefined): SuggestionItem[] {\n if (slot === 'speed') {\n // A speed is a free number, so the list offers the shipped rates rather than\n // pretending to be exhaustive. The state's own rate leads.\n const current = line?.state === undefined ? undefined : LOOK[line.state]?.speed\n const rates = [...new Set([...Object.values(LOOK).map((look) => look.speed), 1, 2, 3])].sort(\n (left, right) => left - right,\n )\n return rates.map((rate) => ({\n label: String(rate),\n insert: String(rate),\n kind: 'number',\n detail: current === rate ? 'the shipped rate for this state' : 'seconds per cycle',\n sortText: current === rate ? '0' : '1',\n }))\n }\n const words = wordsForSlot(slot)\n if (words.length === 0) return []\n const scope = slot === 'bg' ? SLOT_SCOPE.color : SLOT_SCOPE[slot as DshSentrySlot]\n const vocabulary = BY_SCOPE.get(scope)\n const filled = line?.slots[KEY_SLOT[slot] ?? 'shape']\n const noun = slot === 'bg' ? 'color' : slot\n return words.map((word) => {\n const entry = vocabulary?.entryFor(word)\n return {\n label: word,\n insert: word,\n kind: 'value',\n detail: word === filled ? `the current ${noun}` : entry?.detail,\n documentation: entry?.body,\n sortText: word === filled ? '0' : '1',\n }\n })\n }\n}\n\n/**\n * The option a value is being written for, when the caret is inside one.\n *\n * Read from the text before the caret on the caret's own line. The parse reads whole\n * lines, and part-way through `shape=ci` the line is not a finished rule yet — the local\n * reading is correct in the middle of the edit, which is the only moment a completion is\n * ever asked.\n *\n * The value has to be the word the caret is IN, which is why the pattern allows no\n * whitespace between the `=` and the caret. Without that, any earlier `key=` on the line\n * would claim the list: a line that already said `pattern=none` would go on offering\n * patterns instead of moving on to the slot that is still empty.\n * @param before - the caret's line, up to the caret.\n * @returns the key, or undefined when the caret is not in a value.\n */\nfunction optionAtCaret(before: string): string | undefined {\n const match = /([A-Za-z][\\w-]*)\\s*=([^\\s=]*)$/.exec(before)\n return match?.[1]\n}\n\n/** The four states this grammar understands, for a host that wants to list them. */\nexport const DSH_SENTRY_STATES: readonly string[] = DEFAULT_STATES\n\n/** The palette it documents, for a host that wants to draw a swatch. */\nexport const DSH_SENTRY_COLORS: Readonly<Record<string, string>> = DEFAULT_COLORS\n\n/** The value sets it accepts, for a host that wants to validate a stored document. */\nexport const DSH_SENTRY_VOCABULARY = {\n states: DEFAULT_STATES,\n shapes: DEFAULT_SHAPES,\n motions: DEFAULT_MOTIONS,\n colors: DEFAULT_COLORS,\n options: DEFAULT_OPTIONS,\n} as const\n"]}
@@ -1,127 +0,0 @@
1
- import type { Grammar, Severity } from '../core/types.js';
2
- /** Every weight word the language accepts, mapped to its CSS number. */
3
- export declare const FONT_WEIGHT_WORDS: Readonly<Record<string, number>>;
4
- /** The CSS weight scale, in the order a picker shows it. */
5
- export declare const FONT_WEIGHT_SCALE: readonly number[];
6
- /** The canonical word per weight — `500` is `medium`. */
7
- export declare const FONT_WEIGHT_LABELS: Readonly<Record<number, string>>;
8
- /**
9
- * Generic CSS families. Valid anywhere in a list, and only useful at the end,
10
- * which is why they are coloured apart from an installed family: picking one is a
11
- * different intent from picking a font.
12
- */
13
- export declare const FONT_GENERIC_FAMILIES: readonly string[];
14
- /**
15
- * Popular families offered as suggestions even when not detected.
16
- *
17
- * Detection cannot see every font and a family may be installed later, so the
18
- * picker must not present itself as the complete truth. A host that has read the
19
- * real catalogue passes it in; this list is what a host with no permission to read
20
- * one can still offer.
21
- */
22
- export declare const FONT_COMMON_FAMILIES: readonly string[];
23
- /** One entry of the query, as it was found in the source. */
24
- export interface DshFontEntry {
25
- /** The whole entry, whitespace included. */
26
- from: number;
27
- to: number;
28
- /** The trimmed core, and its range. */
29
- coreFrom: number;
30
- coreTo: number;
31
- core: string;
32
- /** Whether the core opens with a quote. */
33
- quoted: boolean;
34
- /** The family name, with the quotes and any weight word taken out. */
35
- name: string;
36
- nameFrom: number;
37
- nameTo: number;
38
- /** The weight word the entry carries, if any. */
39
- word: string | undefined;
40
- wordFrom: number;
41
- wordTo: number;
42
- /** What the reader made of the entry. */
43
- kind: 'empty' | 'family' | 'generic' | 'unknown' | 'weight';
44
- }
45
- /** A problem the structural pass found. */
46
- export interface DshFontProblem {
47
- from: number;
48
- to: number;
49
- message: string;
50
- code: string;
51
- severity: Severity;
52
- }
53
- /** What one pass over the query produced. */
54
- export interface DshFontState {
55
- entries: DshFontEntry[];
56
- /** The family names the entries name, in order. */
57
- families: string[];
58
- /** Which of them the browser will actually paint with; -1 when none will. */
59
- effective: number;
60
- /** The numeric weight the query states, if it states one. */
61
- weight: number | undefined;
62
- weightWord: string | undefined;
63
- problems: DshFontProblem[];
64
- }
65
- /** What a host supplies to describe the machine the query will run on. */
66
- export interface DshFontQueryOptions {
67
- /** The family names the machine has. */
68
- catalogue?: readonly string[];
69
- /**
70
- * Whether that catalogue was READ from the machine.
71
- *
72
- * It changes what an unrecognized name means. With a read catalogue the browser
73
- * will fall through to a later family, which is worth warning about; without one
74
- * the catalogue is only a suggestion list, and the parser has no business
75
- * second-guessing a name the user typed.
76
- */
77
- enumerated?: boolean;
78
- /** The face style names of each family, as the Local Font Access API reports them. */
79
- styles?: Readonly<Record<string, readonly string[]>>;
80
- /** The weight the axis ships with, offered as a row that takes the word away. */
81
- shippedWeight?: number;
82
- /** Families offered even when not detected. */
83
- commonFamilies?: readonly string[];
84
- /** The generic CSS families. */
85
- genericFamilies?: readonly string[];
86
- /** How many words one unquoted family name may span when matching the catalogue. */
87
- phraseWords?: number;
88
- }
89
- /**
90
- * The word a numeric weight is spelled with: `500` becomes `medium`.
91
- * @param weight - a numeric weight.
92
- * @returns the canonical word, or the number as text when it is off the scale.
93
- */
94
- export declare function fontWeightWord(weight: number): string;
95
- /**
96
- * The weights one family actually has, read off its faces' style names.
97
- *
98
- * The Local Font Access API reports a face's `style` (`Regular`, `SemiBold`,
99
- * `Bold Italic`) rather than a number, and is not obliged to spell a two-word
100
- * style with a hyphen, so `Semi Bold` has to be folded back into one word before
101
- * the lookup.
102
- *
103
- * An empty result means "unknown", never "none": enumerating faces is
104
- * permission-gated, and a family may report styles this vocabulary cannot read.
105
- * @param styles - the face style names of one family.
106
- * @returns the distinct weights, ascending.
107
- */
108
- export declare function fontFaceWeights(styles: readonly string[] | undefined): number[];
109
- /**
110
- * Render a family name for a CSS list, quoting it only when CSS requires it.
111
- *
112
- * A generic family or a CSS-wide keyword must NOT be quoted, because `"sans-serif"`
113
- * names a literal font instead of the generic family. A single leading hyphen is
114
- * part of an identifier (`-apple-system`), so it survives unquoted too.
115
- * @param family - a bare family name.
116
- * @returns the CSS token for it.
117
- */
118
- export declare function quoteFontFamily(family: string): string;
119
- /**
120
- * Build the grammar for dsh-font's font query.
121
- * @param options - the machine's catalogue, its faces, and the shipped weight.
122
- * @returns a grammar that paints, completes, diagnoses, and explains the language.
123
- */
124
- export declare function dshFontQueryGrammar(options?: DshFontQueryOptions): Grammar<DshFontState>;
125
- /** A diagnostic the grammar rates as informational rather than as a mistake. */
126
- export declare const DSH_FONT_INFO_CODES: readonly string[];
127
- //# sourceMappingURL=dshFont.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dshFont.d.ts","sourceRoot":"","sources":["../../../src/grammars/dshFont.ts"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAEV,OAAO,EAEP,QAAQ,EAET,MAAM,kBAAkB,CAAA;AAIzB,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAoB9D,CAAA;AAED,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAAkD,CAAA;AAEjG,yDAAyD;AACzD,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAU/D,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAclD,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAgDjD,CAAA;AAaD,6DAA6D;AAC7D,MAAM,WAAW,YAAY;IAC3B,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,uCAAuC;IACvC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,2CAA2C;IAC3C,MAAM,EAAE,OAAO,CAAA;IACf,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,iDAAiD;IACjD,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,yCAAyC;IACzC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;CAC5D;AAED,2CAA2C;AAC3C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,QAAQ,CAAA;CACnB;AAED,6CAA6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,6EAA6E;IAC7E,SAAS,EAAE,MAAM,CAAA;IACjB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,QAAQ,EAAE,cAAc,EAAE,CAAA;CAC3B;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,wCAAwC;IACxC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC7B;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,sFAAsF;IACtF,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAA;IACpD,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,gCAAgC;IAChC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,CAc/E;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKtD;AAuCD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,YAAY,CAAC,CA8jB5F;AA+ED,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAA4B,CAAA"}
@@ -1,84 +0,0 @@
1
- import type { Grammar, Severity } from '../core/types.js';
2
- /** One positional slot of a state line, in the order a bare word fills them. */
3
- export type DshSentrySlot = 'shape' | 'color' | 'pattern' | 'motion' | 'speed';
4
- /** The four facts one state's appearance is made of. */
5
- export interface DshSentryLook {
6
- shape: string;
7
- color: string;
8
- pattern: string;
9
- motion: string;
10
- speed: number;
11
- }
12
- /** One word of the document, with the range it occupies. */
13
- export interface DshSentryWord {
14
- text: string;
15
- from: number;
16
- to: number;
17
- }
18
- /** A problem the structural walk found, ready to be reported. */
19
- export interface DshSentryProblem {
20
- from: number;
21
- to: number;
22
- message: string;
23
- code: string;
24
- severity: Severity;
25
- }
26
- /** One line, read. */
27
- export interface DshSentryLine {
28
- /** Zero-based line number, so a completion can find the line the caret is on. */
29
- number: number;
30
- /** The state the line opens, as written. */
31
- state: string | undefined;
32
- /** Whether that state is one this document understands. */
33
- known: boolean;
34
- /** The words on the line, comments removed. */
35
- words: DshSentryWord[];
36
- /** The value each positional slot ended up with, whatever syntax put it there. */
37
- slots: Partial<Record<DshSentrySlot, string>>;
38
- /** The option keys the line named, in order, whether or not they are known. */
39
- keys: string[];
40
- /** The option key whose value the line has not written yet, as `speed=`. */
41
- pendingKey: string | undefined;
42
- }
43
- /** What one pass over the document produced. */
44
- export interface DshSentryState {
45
- lines: DshSentryLine[];
46
- /** What the structural walk found. `validate` reports these verbatim. */
47
- problems: DshSentryProblem[];
48
- }
49
- /** The vocabularies and shipped defaults a host may override. */
50
- export interface DshSentryStyleOptions {
51
- /** The states a document may address, in the order the list shows them. */
52
- states?: readonly string[];
53
- /** The background shapes a rule may name. */
54
- shapes?: readonly string[];
55
- /** The motions a rule may apply. */
56
- motions?: readonly string[];
57
- /** The patterns still accepted as `pattern=<name>`. */
58
- patterns?: readonly string[];
59
- /** The named palette. Presets on purpose: a free colour can be illegible. */
60
- colors?: Readonly<Record<string, string>>;
61
- /** The option keys a rule may write. */
62
- options?: readonly string[];
63
- /** The shipped look per state, used to rank and to document. */
64
- defaults?: Readonly<Record<string, DshSentryLook>>;
65
- }
66
- /**
67
- * Build the grammar for dsh-sentry's style document.
68
- * @param options - the vocabularies and shipped defaults, defaulting to the plugin's.
69
- * @returns a grammar that paints, completes, diagnoses, and explains the language.
70
- */
71
- export declare function dshSentryStyleGrammar(options?: DshSentryStyleOptions): Grammar<DshSentryState>;
72
- /** The four states this grammar understands, for a host that wants to list them. */
73
- export declare const DSH_SENTRY_STATES: readonly string[];
74
- /** The palette it documents, for a host that wants to draw a swatch. */
75
- export declare const DSH_SENTRY_COLORS: Readonly<Record<string, string>>;
76
- /** The value sets it accepts, for a host that wants to validate a stored document. */
77
- export declare const DSH_SENTRY_VOCABULARY: {
78
- readonly states: string[];
79
- readonly shapes: string[];
80
- readonly motions: string[];
81
- readonly colors: Readonly<Record<string, string>>;
82
- readonly options: string[];
83
- };
84
- //# sourceMappingURL=dshSentry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dshSentry.d.ts","sourceRoot":"","sources":["../../../src/grammars/dshSentry.ts"],"names":[],"mappings":"AAkDA,OAAO,KAAK,EACV,OAAO,EAGP,QAAQ,EAET,MAAM,kBAAkB,CAAA;AAKzB,gFAAgF;AAChF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAA;AAE9E,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACd;AAED,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;CACX;AAED,iEAAiE;AACjE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,QAAQ,CAAA;CACnB;AAED,sBAAsB;AACtB,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,2DAA2D;IAC3D,KAAK,EAAE,OAAO,CAAA;IACd,+CAA+C;IAC/C,KAAK,EAAE,aAAa,EAAE,CAAA;IACtB,kFAAkF;IAClF,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAA;IAC7C,+EAA+E;IAC/E,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,4EAA4E;IAC5E,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;CAC/B;AAED,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,aAAa,EAAE,CAAA;IACtB,yEAAyE;IACzE,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC7B;AAED,iEAAiE;AACjE,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B,6CAA6C;IAC7C,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B,oCAAoC;IACpC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC3B,uDAAuD;IACvD,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC5B,6EAA6E;IAC7E,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACzC,wCAAwC;IACxC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAA;CACnD;AAmED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,cAAc,CAAC,CAsfzB;AAsBD,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAAmB,CAAA;AAElE,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAkB,CAAA;AAEjF,sFAAsF;AACtF,eAAO,MAAM,qBAAqB;aAChC,MAAM;aACN,MAAM;aACN,OAAO;aACP,MAAM;aACN,OAAO;CACC,CAAA"}
@@ -1,3 +0,0 @@
1
- export { DSH_FONT_INFO_CODES, FONT_COMMON_FAMILIES, FONT_GENERIC_FAMILIES, FONT_WEIGHT_LABELS, FONT_WEIGHT_SCALE, FONT_WEIGHT_WORDS, dshFontQueryGrammar, fontFaceWeights, fontWeightWord, quoteFontFamily, type DshFontEntry, type DshFontProblem, type DshFontQueryOptions, type DshFontState, } from './dshFont.js';
2
- export { DSH_SENTRY_COLORS, DSH_SENTRY_STATES, DSH_SENTRY_VOCABULARY, dshSentryStyleGrammar, type DshSentryLine, type DshSentryLook, type DshSentryProblem, type DshSentrySlot, type DshSentryState, type DshSentryStyleOptions, type DshSentryWord, } from './dshSentry.js';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/grammars/index.ts"],"names":[],"mappings":"AA2BA,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,eAAe,EACf,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,YAAY,GAClB,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAA"}