@coldsmirk/inkstone-monaco 0.27.1 → 0.27.2

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
@@ -6,13 +6,13 @@ Part of [inkstone](https://github.com/coldsmirk/inkstone). For a drop-in React c
6
6
 
7
7
  ## What you get
8
8
 
9
- - **`ensureMonacoHost(options?)`** — the process-wide host: resolves the local `monaco-editor` module (never the CDN), routes **all** built-in language workers (base editor, TypeScript/JavaScript, JSON, CSS/scss/less, HTML/handlebars/razor) as bundler-emitted chunks so everything works offline, and applies `locale: "zh-cn"` via Monaco's official NLS catalog when asked. Idempotent — every caller gets the same module; a load failure is not cached, so a fresh call retries.
9
+ - **`ensureMonacoHost(options?)`** — the process-wide host: resolves the local `monaco-editor` module (never the CDN), routes **all** built-in language workers (base editor, TypeScript/JavaScript, JSON, CSS/scss/less, HTML/handlebars/razor) as bundler-emitted chunks so everything works offline, and applies `locale: "zh-cn"` via Monaco's official NLS catalog when asked — plus, on every editor created under that host, zh-CN descriptions for the six command-palette actions Monaco describes in English literals that no catalog can reach (Fold, Unfold, Find with Arguments, Refactor..., Source Action..., Paste As...), each held to the installed `monaco-editor` by an upgrade-tripwire test. Idempotent — every caller gets the same module; a load failure is not cached, so a fresh call retries.
10
10
  - **`getWorker` extension point** — plug third-party language workers (e.g. monaco-yaml) into the routing; return `undefined` to fall back to the built-in routes.
11
11
  - **`monacoLanguages`** — the sorted catalog of every built-in language id the installed Monaco registers (with the `MonacoBuiltInLanguage` union type behind it), held to the installed `monaco-editor` by an upgrade-tripwire test. These are *ids*, not display names (`proto`, `sol`, `aes`); an unknown id silently falls back to `plaintext`.
12
12
  - **`disabledKeybindings` / `installDisabledKeybindings`** — swallow the find/replace chords and the command palette's F1 for editors that opt in. Monaco's standalone keybinding service is page-global and its rules are permanent, so the install registers each chord once per monaco module's service (duplicate copies of this package share the ledger; independent monaco bundles register their own) and scopes it with a per-capability context key created on the opted-in editor; the chord table is held to the installed `monaco-editor` by an upgrade-tripwire test.
13
13
  - **`installJsxTagClosing`** — VS Code's auto-closing JSX tags: a typed `>` that completes an opening tag inserts the matching closing tag and keeps the caret between the pair. Parser-backed: the bundled TS worker subclasses monaco's stock worker to expose `getJsxClosingTagAtPosition` — a language-service call monaco never proxied (VS Code ships the feature in its TypeScript extension, outside the editor core) — so generics, comparisons, arrow functions, and already-closed elements never trigger. Only a *typed* `>` triggers: the gates require one bare single-character insertion into a **writable** TypeScript/JavaScript model whose path ends in `.tsx` / `.jsx`, and the reply lands only while the caret still sits right after that `>` — so `replaceInEditor` replacements, `StreamingEditorController` appends (the stream holds the editor read-only), and other programmatic writes never earn a closing tag, and the insert arrives as its own undo step (one undo removes just the closing tag). A `getWorker` override that routes the `typescript` label to a worker without the subclass is detected on its first lookup and the install disarms silently. Multi-cursor typing and the diff editor's panes are deliberately out of scope. `<MonacoEditor>` installs it automatically.
14
14
  - **`dropMonacoWorkerFallbacks()`** (from **`@coldsmirk/inkstone-monaco/vite`**) — a Vite plugin that removes monaco's built-in worker fallbacks at build time. Monaco's language workerManagers statically reference their workers as `new Worker(new URL(...))` fallbacks that never run under `ensureMonacoHost` (the environment check prefers `getWorker`), yet bundlers emit a chunk per reference — including a ~7MB TypeScript worker duplicate that is never fetched. The plugin rewrites the fallbacks into located throws so the duplicates are never emitted; if a monaco bump reshapes the pattern it warns and leaves the file untouched (the dead chunk returns, nothing breaks).
15
- - **Embedded-editor fix** — works around [microsoft/monaco-editor#5177](https://github.com/microsoft/monaco-editor/issues/5177) (find-widget button tooltips landing on top of the buttons they describe) with a `width: max-content` hover-layer style tagged `data-inkstone="monaco-hover-geometry"`; deleted the moment upstream fixes it. The tooltip layer positions against the editor's container — give that container `position: relative`.
15
+ - **Embedded-editor fixes** — works around [microsoft/monaco-editor#5177](https://github.com/microsoft/monaco-editor/issues/5177) (find-widget button tooltips landing on top of the buttons they describe) with a `width: max-content` hover-layer style tagged `data-inkstone="monaco-hover-geometry"`; deleted the moment upstream fixes it. The tooltip layer positions against the editor's container — give that container `position: relative`. The command palette's row tooltips have the same trouble inside the palette: 0.56 positions them against the palette's list, which sets no position of its own, so they landed above the row they describe (by the height of the filter box); a `position: relative` style on the list, tagged `data-inkstone="monaco-quick-input-geometry"`, puts them on their row until upstream does.
16
16
  - **`StreamingEditorController`** — stream generated text into an editor without routing every token through app state: `begin()` / `append(chunk)` / `end()` / `discard()`, `attach(editor)` / `detach(editor)` with buffered replay for late-mounting editors (and for a model swapped onto the attached editor mid-stream, including after the final chunk), and `isStreaming()` for the onChange guard. The stream locks every editor it touches read-only and `end()` / `discard()` restore each one's own setting — by handle, so an editor detached mid-stream is restored too; `discard()` puts every displaced document back into the model it came from, and `end()` does the same for every model except the one keeping the streamed text. Full-buffer writes and restorations preserve each model's UTF-8 BOM. Editors and models the app disposed mid-stream are skipped, never touched — teardown can race the stream without wedging it.
17
17
  - **`replaceInEditor(editor, old, new, all)`** — exact find-and-replace on an editor handle via `executeEdits`, preserving undo/cursor/folds; returns whether the edit landed (`false` = no editor / empty search / no match / a read-only editor refused it — e.g. one locked by a stream in progress), so a tool-call handler knows to fall back to a state write.
18
18
  - **`registerShikiHighlighting(monaco, highlighter)`** — wire `@coldsmirk/inkstone-core`'s shared Shiki highlighter onto a monaco module, once per distinct module: defines the highlighter's themes as Monaco themes, registers each loaded grammar's canonical name as a Monaco language where Monaco has none and installs a Shiki tokens provider for it, and patches `setTheme` so the Shiki theme ids route through the highlighter while non-Shiki ids (vs/vs-dark, caller-defined) keep Monaco's original path. Called again on a bridged module, it installs the grammars loaded since. A failed registration is restored and retried on the next call.
package/dist/index.d.ts CHANGED
@@ -13,7 +13,8 @@ interface MonacoHostOptions {
13
13
  * UI locale for Monaco's built-in chrome. A non-`"en"` locale is applied by evaluating the
14
14
  * official locale catalog before the monaco module itself — which is why the host owns the
15
15
  * monaco import: a static `import "monaco-editor"` elsewhere would evaluate first and lock
16
- * the UI to English.
16
+ * the UI to English. `"zh-cn"` also translates, on every editor created afterwards, the few
17
+ * command-palette descriptions monaco writes as English literals, which no catalog can reach.
17
18
  *
18
19
  * @default "en"
19
20
  */
package/dist/index.js CHANGED
@@ -143,6 +143,43 @@ function installDesignTokens() {
143
143
  document.head.append(style);
144
144
  }
145
145
  //#endregion
146
+ //#region src/action-descriptions.ts
147
+ const ZH_CN_ACTION_DESCRIPTIONS = {
148
+ "editor.action.pasteAs": {
149
+ original: "Paste as",
150
+ value: "粘贴为"
151
+ },
152
+ "editor.action.refactor": {
153
+ original: "Refactor...",
154
+ value: "重构..."
155
+ },
156
+ "editor.action.sourceAction": {
157
+ original: "Source Action...",
158
+ value: "源代码操作..."
159
+ },
160
+ "editor.actions.findWithArgs": {
161
+ original: "Open a new In-Editor Find Widget.",
162
+ value: "打开新的编辑器查找小组件。"
163
+ },
164
+ "editor.fold": {
165
+ original: "Fold the content in the editor",
166
+ value: "折叠编辑器中的内容"
167
+ },
168
+ "editor.unfold": {
169
+ original: "Unfold the content in the editor",
170
+ value: "展开编辑器中的内容"
171
+ }
172
+ };
173
+ function localizeActionDescriptions(editorInstance) {
174
+ for (const [id, description] of Object.entries(ZH_CN_ACTION_DESCRIPTIONS)) {
175
+ const action = editorInstance.getAction(id);
176
+ if (action?.metadata?.description === description.original) action.metadata = {
177
+ ...action.metadata,
178
+ description
179
+ };
180
+ }
181
+ }
182
+ //#endregion
146
183
  //#region src/geometry-fixes.ts
147
184
  const HOVER_GEOMETRY_STYLE_SELECTOR = "style[data-inkstone=\"monaco-hover-geometry\"]";
148
185
  function installHoverGeometryFix() {
@@ -160,6 +197,14 @@ function installSuggestGeometryFix() {
160
197
  style.textContent = ".monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .right > span.readMore.codicon.codicon-suggest-more-info::before { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }";
161
198
  document.head.append(style);
162
199
  }
200
+ const QUICK_INPUT_GEOMETRY_STYLE_SELECTOR = "style[data-inkstone=\"monaco-quick-input-geometry\"]";
201
+ function installQuickInputGeometryFix() {
202
+ if (document.querySelector(QUICK_INPUT_GEOMETRY_STYLE_SELECTOR)) return;
203
+ const style = document.createElement("style");
204
+ style.dataset.inkstone = "monaco-quick-input-geometry";
205
+ style.textContent = ".monaco-editor .quick-input-list { position: relative; }";
206
+ document.head.append(style);
207
+ }
163
208
  //#endregion
164
209
  //#region src/host.ts
165
210
  const HOST_PROMISE_KEY = Symbol.for("coldsmirk.inkstone.monaco.hostPromise");
@@ -230,8 +275,10 @@ function ensureMonacoHost(options = {}) {
230
275
  installDesignTokens();
231
276
  installHoverGeometryFix();
232
277
  installSuggestGeometryFix();
278
+ installQuickInputGeometryFix();
233
279
  const monaco = await import("monaco-editor");
234
280
  globalThis.MonacoEnvironment = { getWorker: (workerId, label) => getWorker?.(workerId, label) ?? builtinGetWorker(label) };
281
+ if (locale === "zh-cn") monaco.editor.onDidCreateEditor(localizeActionDescriptions);
235
282
  return monaco;
236
283
  } catch (error) {
237
284
  restoreNls?.();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coldsmirk/inkstone-monaco",
3
- "version": "0.27.1",
3
+ "version": "0.27.2",
4
4
  "description": "Framework-agnostic Monaco assembly: lazy offline host (all language workers bundled, no CDN), opt-in Simplified-Chinese UI via monaco's official NLS catalog, a streaming editor controller for AI-typed content, and the shared Shiki highlighting bridge.",
5
5
  "keywords": [
6
6
  "monaco",
@@ -40,7 +40,7 @@
40
40
  ],
41
41
  "dependencies": {
42
42
  "@shikijs/vscode-textmate": "^10.0.2",
43
- "@coldsmirk/inkstone-core": "^0.27.1"
43
+ "@coldsmirk/inkstone-core": "^0.27.2"
44
44
  },
45
45
  "devDependencies": {
46
46
  "monaco-editor": "^0.56.0",