@coldsmirk/inkstone-core 0.20.1 → 0.22.0

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.
package/README.md CHANGED
@@ -1,13 +1,14 @@
1
1
  # @coldsmirk/inkstone-core
2
2
 
3
- The shared [Shiki](https://shiki.style/) highlighter service behind inkstone: one fine-grained, lazily-created singleton (catppuccin latte / macchiato, JS regex engine) that serves the editors, static code rendering, and markdown surfaces alike — one instance, consistent colors everywhere.
3
+ The shared [Shiki](https://shiki.style/) highlighter service behind inkstone: one fine-grained, lazily-created singleton (catppuccin latte / macchiato, the JS regex engine by default or Oniguruma on request) that serves the editors, static code rendering, and markdown surfaces alike — one instance, consistent colors everywhere.
4
4
 
5
5
  Part of [inkstone](https://github.com/coldsmirk/inkstone). The editor layers ([`@coldsmirk/inkstone-monaco`](https://www.npmjs.com/package/@coldsmirk/inkstone-monaco), [`@coldsmirk/inkstone-codemirror`](https://www.npmjs.com/package/@coldsmirk/inkstone-codemirror)) and the React components ([`@coldsmirk/inkstone-react`](https://www.npmjs.com/package/@coldsmirk/inkstone-react)) consume this package; use it directly when a non-editor surface needs the same highlighting.
6
6
 
7
7
  ## What you get
8
8
 
9
9
  - **`getHighlighter()`** — the process-wide `HighlighterCore` promise. JavaScript / TypeScript / JSON / SQL grammars and the catppuccin theme pair load by default.
10
- - **`configureHighlighter(config)`** — extend or replace the default grammar / theme set, and choose the regex engine (`engine`: the strict JavaScript engine by default; `createJavaScriptRegexEngine({ forgiving: true })` for grammars the strict one refuses, or the Oniguruma WASM engine), once, before any editor mounts. `DEFAULT_HIGHLIGHTER_LANGS` is exported so extension is additive.
10
+ - **`configureHighlighter(config)`** — extend or replace the default grammar / theme set, and choose the regex engine, once, before any editor mounts. `DEFAULT_HIGHLIGHTER_LANGS` is exported so extension is additive. `engine` takes the engine itself, a promise of one, or a factory called once when the highlighter is first built — configuration stays synchronous while the engine may be async to make: the strict JavaScript engine by default, `createJavaScriptRegexEngine({ forgiving: true })` for grammars the strict one refuses, or `onigurumaEngine`.
11
+ - **`onigurumaEngine`** — the Oniguruma engine on its WASM, inlined into a chunk of your own bundle (about 600 KB, nothing fetched from anywhere else) and instantiated once, in about 20 ms. Which engine: the JavaScript one translates each grammar's patterns into JavaScript at the first tokenization, on the main thread, and pays for it on whole files — a TypeScript file's first sixty lines cost it about 170 ms, against Oniguruma's 20. Colouring fenced snippets, keep the default; reading whole files in an editor (`@coldsmirk/inkstone-monaco`'s Shiki bridge, `<MonacoEditor>`), pass `onigurumaEngine` as the factory. `onigurumaEngine(wasm)` takes the WASM from elsewhere in any form Shiki's `createOnigurumaEngine` accepts, such as a `fetch("/onig.wasm")`.
11
12
  - **`shikiThemeId(dark)`** plus the `INKSTONE_LIGHT_THEME` / `INKSTONE_DARK_THEME` constants — the theme names to pass wherever a Shiki theme id is expected.
12
13
  - **`configureEditorSurface(surfaces)`** — re-light the editors' own surfaces in your design language, once, before any editor mounts: per-scheme CSS color literals for `background` (content and gutter), `lineHighlight`, `lineNumber`, `widget` (completion, hover, parameter hints, the find widget and search panels), `widgetBorder`, and `widgetSelection`. The catppuccin pair keeps its syntax palette and gets these baked into its theme colors — Monaco, static rendering, and CodeMirror's chrome all read the same values — so an editor sits inside the app instead of bringing a second dark. A role or scheme left out keeps the flavor's own color, a later call replaces the schemes it names, and values must be hex colors (`#rrggbb`, `#rrggbbaa`) — Monaco parses theme colors as hex and paints red for anything else, so a `var()` reference or an `rgb(…)` is refused up front. Keep `lineHighlight` translucent: CodeMirror draws selections behind the content, so an opaque active line would hide them. `getEditorSurface(dark)` reads what was configured.
13
14
  - **`CODE_FONT_FAMILY`** — the shared code font stack both editor engines render with: the page's `--inkstone-font-family-code` CSS token when defined, else the platform's native monospace.
@@ -24,11 +25,12 @@ pnpm add @coldsmirk/inkstone-core
24
25
  ## Quick start
25
26
 
26
27
  ```ts
27
- import { configureEditorSurface, configureHighlighter, DEFAULT_HIGHLIGHTER_LANGS, getHighlighter, shikiThemeId } from "@coldsmirk/inkstone-core";
28
+ import { configureEditorSurface, configureHighlighter, DEFAULT_HIGHLIGHTER_LANGS, getHighlighter, onigurumaEngine, shikiThemeId } from "@coldsmirk/inkstone-core";
28
29
  import yaml from "@shikijs/langs/yaml";
29
30
 
30
- // Optional: add grammars/themes beyond the defaults — once, before any editor mounts.
31
- configureHighlighter({ langs: [...DEFAULT_HIGHLIGHTER_LANGS, yaml] });
31
+ // Optional: add grammars/themes beyond the defaults — once, before any editor mounts — and,
32
+ // for an app that reads whole files in an editor, the Oniguruma engine (see above).
33
+ configureHighlighter({ langs: [...DEFAULT_HIGHLIGHTER_LANGS, yaml], engine: onigurumaEngine });
32
34
 
33
35
  // Optional: paint the editors' surfaces in your own tokens (syntax colors stay catppuccin's).
34
36
  configureEditorSurface({
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { HighlighterCore, HighlighterCore as HighlighterCore$1, LanguageInput, RegexEngine, ThemeInput, ThemeRegistration } from "shiki/core";
1
+ import { Awaitable, HighlighterCore, HighlighterCore as HighlighterCore$1, LanguageInput, LoadWasmOptions, RegexEngine, ThemeInput, ThemeRegistration } from "shiki/core";
2
2
  //#region src/code-font.d.ts
3
3
  /**
4
4
  * The code font stack every inkstone editor host renders with: the page's
@@ -111,12 +111,36 @@ interface HighlighterConfig {
111
111
  themes?: ThemeInput[];
112
112
  /**
113
113
  * The regex engine the highlighter tokenizes with, replacing the default JavaScript engine
114
- * in its strict form — for an app that loads grammars the strict engine refuses
115
- * (`createJavaScriptRegexEngine({ forgiving: true })`), or one that ships the Oniguruma
116
- * WASM and wants every grammar exact.
114
+ * in its strict form: the engine itself, a promise of one, or a factory called once when the
115
+ * highlighter is first built — so configuration stays synchronous (it must precede the first
116
+ * {@link getHighlighter}) while the engine may be async to make, as the Oniguruma one is.
117
+ *
118
+ * The JavaScript engine translates each grammar's patterns into JavaScript at the first
119
+ * tokenization, on the main thread, and pays for it on whole files: a TypeScript file's
120
+ * first sixty lines cost it about 170 ms, against Oniguruma's 20. An app that colors fenced
121
+ * snippets keeps the default; one that reads whole files in an editor configures
122
+ * {@link onigurumaEngine}; one whose grammars the strict engine refuses configures
123
+ * `createJavaScriptRegexEngine({ forgiving: true })`.
117
124
  */
118
- engine?: RegexEngine;
125
+ engine?: Awaitable<RegexEngine> | (() => Awaitable<RegexEngine>);
119
126
  }
127
+ /**
128
+ * The Oniguruma engine — the one every TextMate grammar was written against, so none is
129
+ * refused and each compiles in a few milliseconds — on its WASM, inlined by `shiki/wasm` into
130
+ * a chunk of the app's own bundle (about 600 KB; nothing is fetched from anywhere else), so
131
+ * it suits an offline or embedded deployment as the JavaScript engine does. Instantiated once,
132
+ * in about 20 ms. Pass the function itself as the engine factory, so the chunk is fetched and
133
+ * the WASM instantiated only when the highlighter is first built:
134
+ *
135
+ * ```ts
136
+ * configureHighlighter({ engine: onigurumaEngine });
137
+ * ```
138
+ *
139
+ * `wasm` takes the WASM from elsewhere in any form `createOnigurumaEngine` accepts — a
140
+ * `fetch("/onig.wasm")` for a deployment that would rather stream-compile the binary than
141
+ * decode it out of a script.
142
+ */
143
+ declare function onigurumaEngine(wasm?: LoadWasmOptions): Promise<RegexEngine>;
120
144
  /**
121
145
  * Configure the shared highlighter before its first use. The highlighter is a process-wide
122
146
  * singleton (editors, static rendering, and markdown surfaces all share it for consistent
@@ -147,8 +171,9 @@ declare function getEditorSurface(dark: boolean): EditorSurface | undefined;
147
171
  *
148
172
  * Fine-grained build: only the configured grammars and the two catppuccin themes are bundled,
149
173
  * whereas the convenient `createHighlighter` generates a lazy chunk for *every* Shiki theme and
150
- * language. The JS regex engine avoids the Oniguruma WASM — smaller, no extra network request,
151
- * ideal for offline deployments (Tauri webviews, rust-embed consoles).
174
+ * language. The JavaScript regex engine is the default — nothing to instantiate, no WASM in the
175
+ * bundle — and right for fenced snippets; an app reading whole files in an editor configures
176
+ * {@link onigurumaEngine} instead (see {@link HighlighterConfig.engine}).
152
177
  *
153
178
  * A failed build is not cached: the slot resets so a later call retries (and
154
179
  * {@link configureHighlighter} becomes callable again), instead of replaying one transient
@@ -161,4 +186,4 @@ declare function getHighlighter(): Promise<HighlighterCore$1>;
161
186
  */
162
187
  declare function shikiThemeId(dark: boolean): string;
163
188
  //#endregion
164
- export { CODE_FONT_FAMILY, DEFAULT_HIGHLIGHTER_LANGS, type EditorSurface, type EditorSurfaces, type HighlighterConfig, type HighlighterCore, INKSTONE_DARK_THEME, INKSTONE_LIGHT_THEME, type RadiusSize, type ShadowSize, configureEditorSurface, configureHighlighter, getEditorSurface, getHighlighter, inkstoneRadius, inkstoneShadow, shikiThemeId, surfacedTheme };
189
+ export { CODE_FONT_FAMILY, DEFAULT_HIGHLIGHTER_LANGS, type EditorSurface, type EditorSurfaces, type HighlighterConfig, type HighlighterCore, INKSTONE_DARK_THEME, INKSTONE_LIGHT_THEME, type RadiusSize, type ShadowSize, configureEditorSurface, configureHighlighter, getEditorSurface, getHighlighter, inkstoneRadius, inkstoneShadow, onigurumaEngine, shikiThemeId, surfacedTheme };
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import catppuccinLatte from "@shikijs/themes/catppuccin-latte";
6
6
  import catppuccinMacchiato from "@shikijs/themes/catppuccin-macchiato";
7
7
  import { createHighlighterCore } from "shiki/core";
8
8
  import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
9
+ import { createOnigurumaEngine } from "shiki/engine/oniguruma";
9
10
  //#region src/code-font.ts
10
11
  const CODE_FONT_FAMILY = "var(--inkstone-font-family-code, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace)";
11
12
  //#endregion
@@ -75,6 +76,14 @@ const DEFAULT_HIGHLIGHTER_LANGS = [
75
76
  langJson,
76
77
  langSql
77
78
  ];
79
+ function onigurumaEngine(wasm) {
80
+ return createOnigurumaEngine(wasm ?? import("shiki/wasm"));
81
+ }
82
+ function engineOf(config) {
83
+ const { engine } = config;
84
+ if (typeof engine === "function") return Promise.try(() => engine());
85
+ return engine ?? createJavaScriptRegexEngine();
86
+ }
78
87
  const HIGHLIGHTER_REGISTRY_KEY = Symbol.for("coldsmirk.inkstone.shiki.registry");
79
88
  function getHighlighterRegistry() {
80
89
  const host = globalThis;
@@ -129,7 +138,7 @@ function getHighlighter() {
129
138
  ...registry.config.themes ?? []
130
139
  ],
131
140
  langs: registry.config.langs ?? [...DEFAULT_HIGHLIGHTER_LANGS],
132
- engine: registry.config.engine ?? createJavaScriptRegexEngine()
141
+ engine: engineOf(registry.config)
133
142
  });
134
143
  registry.promise = attempt;
135
144
  attempt.catch(() => {
@@ -141,4 +150,4 @@ function shikiThemeId(dark) {
141
150
  return dark ? INKSTONE_DARK_THEME : INKSTONE_LIGHT_THEME;
142
151
  }
143
152
  //#endregion
144
- export { CODE_FONT_FAMILY, DEFAULT_HIGHLIGHTER_LANGS, INKSTONE_DARK_THEME, INKSTONE_LIGHT_THEME, configureEditorSurface, configureHighlighter, getEditorSurface, getHighlighter, inkstoneRadius, inkstoneShadow, shikiThemeId, surfacedTheme };
153
+ export { CODE_FONT_FAMILY, DEFAULT_HIGHLIGHTER_LANGS, INKSTONE_DARK_THEME, INKSTONE_LIGHT_THEME, configureEditorSurface, configureHighlighter, getEditorSurface, getHighlighter, inkstoneRadius, inkstoneShadow, onigurumaEngine, shikiThemeId, surfacedTheme };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@coldsmirk/inkstone-core",
3
- "version": "0.20.1",
4
- "description": "Shared Shiki highlighter service for the inkstone editor toolkit: one fine-grained singleton (catppuccin themes, JS regex engine) reused by Monaco, static rendering, and markdown surfaces.",
3
+ "version": "0.22.0",
4
+ "description": "Shared Shiki highlighter service for the inkstone editor toolkit: one fine-grained singleton (catppuccin themes, the JS regex engine by default or Oniguruma on request) reused by Monaco, static rendering, and markdown surfaces.",
5
5
  "keywords": [
6
6
  "shiki",
7
7
  "syntax-highlighting",