@coldsmirk/inkstone-codemirror 0.11.0 → 0.13.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 +7 -5
- package/dist/index.d.ts +76 -15
- package/dist/index.js +379 -27
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -12,7 +12,8 @@ Part of [inkstone](https://github.com/coldsmirk/inkstone). For a drop-in React c
|
|
|
12
12
|
- **`codeMirrorLanguages` / `loadLanguage(language)`** — the supported `CodeMirrorLanguage` names and their lazy loaders: one dynamic `import()` per grammar, so only the selected language is fetched, never the whole catalog. Two tiers back the ids: the official `@codemirror/lang-*` (Lezer) parsers where upstream ships one, plus the full [`@codemirror/legacy-modes`](https://github.com/codemirror/legacy-modes) catalog (stream-mode highlighting) for everything upstream never wrote a Lezer grammar for — `shell`, `dockerfile`, `ini` / `env` / `properties`, `toml`, `nginx`, `powershell`, `lua`, and a hundred more.
|
|
13
13
|
- **MiniJinja** — `language: "minijinja"` for standalone templates, or `minijinja-<host>` mixed variants (`minijinja-html`, `-xml`, `-json`, `-yaml`, `-css`, `-scss`, `-sass`, `-less`, `-markdown`; the SQL family — `-sql` plus every dialect id: `-mysql`, `-pgsql`, `-sqlite`, `-mssql`, `-mariadb`, `-plsql`, `-cassandra`, `-hive`, `-sparksql`, `-gql`, `-gpsql`, `-esper`; and the config/deploy hosts `-toml`, `-ini`, `-env`, `-shell`, `-dockerfile`, `-nginx`) that overlay MiniJinja tooling on the host grammar. A parser adapter supports MiniJinja whitespace control, dotted namespace assignments, and comma-separated `set` assignments beyond the upstream Jinja grammar; a linter flags non-MiniJinja tags, and autocomplete is restricted to MiniJinja's real tags / filters / tests / functions.
|
|
14
14
|
- **Context completion** — `normalizeContext({ schema })` (JSON Schema) or `normalizeContext({ sample })` (representative value) builds an `EditorContext`; dispatch it with `setMinijinjaContext` to make `{{ }}` / `{% if %}` / `{% for %}` complete the render context's variables and walk member access (`user.address.city`). `minijinjaContextField`, `resolveMembers`, and `typeAtPath` expose the underlying pieces.
|
|
15
|
-
- **SQL schema completion** — dispatch `setSqlSchema.of({ tables })` for dialect-aware table and column completion in the Lezer-backed `sql`, `mysql`, `pgsql`, `sqlite`, `mssql`, `mariadb`, `plsql`, and `cassandra` languages plus their `minijinja-*` variants. Legacy stream-mode SQL languages do not consume schemas.
|
|
15
|
+
- **SQL schema completion** — dispatch `setSqlSchema.of({ tables })` for dialect-aware table and column completion in the Lezer-backed `sql`, `mysql`, `pgsql`, `sqlite`, `mssql`, `mariadb`, `plsql`, and `cassandra` languages plus their `minijinja-*` variants. Legacy stream-mode SQL languages do not consume schemas. Install `sqlSchemaField` in your static extensions to dispatch the schema before the lazy grammar arrives.
|
|
16
|
+
- **Catppuccin theming** — `defaultThemeExtensions(dark, height?, width?, fontSize?, lineHeight?)`, the latte/macchiato flavor pair plus chrome polish (completion tooltip, icons, hover/lint tooltips, search panel) and sizing; `mergeTheme(dark)` / `installDiffChrome(root)` / `diffChromeColor(dark)` / `installDiffControlKeyboardSupport(container)` extend it to `@codemirror/merge`'s diff surfaces (see the `merge-chrome` module docs for the assembly). This is the identity `@coldsmirk/inkstone-react`'s components ship by default.
|
|
16
17
|
- **`searchPhrasesZhCn`** — an opt-in `EditorState.phrases` table localizing the search panel to Simplified Chinese.
|
|
17
18
|
|
|
18
19
|
## Install
|
|
@@ -72,10 +73,11 @@ import { loadLanguage, normalizeContext, setMinijinjaContext } from "@coldsmirk/
|
|
|
72
73
|
view.dispatch({ effects: setMinijinjaContext.of(normalizeContext({ schema })) });
|
|
73
74
|
```
|
|
74
75
|
|
|
75
|
-
The
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
The hosts are policy-free and pre-install no data fields: when you dispatch `setMinijinjaContext`
|
|
77
|
+
or `setSqlSchema`, install `minijinjaContextField` / `sqlSchemaField` in your static `extensions`
|
|
78
|
+
(as `@coldsmirk/inkstone-react`'s components do). The fields live independently of the lazy
|
|
79
|
+
grammars, so either effect may be dispatched immediately and the grammar loaded/reconfigured
|
|
80
|
+
later.
|
|
79
81
|
|
|
80
82
|
The completion is **structural** — it walks the declared shape (member access along a literal path), not types produced by filters or arithmetic. For a Rust backend the schema is nearly free: derive it from the same `serde` struct you render with via [`schemars`](https://docs.rs/schemars), and the completion can't drift from the real context.
|
|
81
83
|
|
package/dist/index.d.ts
CHANGED
|
@@ -62,9 +62,9 @@ type EditorContext = {
|
|
|
62
62
|
* Reactively set (or clear) the render-context schema an editor completes against. Dispatch this
|
|
63
63
|
* effect — `setMinijinjaContext.of(normalizeContext(...))`, or `.of(null)` to turn it off — to
|
|
64
64
|
* update completion without recreating the editor, matching the create-once discipline used
|
|
65
|
-
* throughout the toolkit.
|
|
66
|
-
*
|
|
67
|
-
*
|
|
65
|
+
* throughout the toolkit. The field lives independently of the lazy MiniJinja grammar, so an
|
|
66
|
+
* editor that installs {@link minijinjaContextField} in its static extensions (as
|
|
67
|
+
* `@coldsmirk/inkstone-react`'s components do) accepts this effect before the grammar resolves.
|
|
68
68
|
*/
|
|
69
69
|
declare const setMinijinjaContext: import("@codemirror/state").StateEffectType<IrSchema | null>;
|
|
70
70
|
/**
|
|
@@ -131,6 +131,11 @@ interface ControlledEditorOptions {
|
|
|
131
131
|
* Framework-agnostic: a React wrapper calls `setValue` from a value effect and `reconfigure`
|
|
132
132
|
* from a theme effect (see `@coldsmirk/inkstone-react`); any other framework does the same
|
|
133
133
|
* from its own reactivity.
|
|
134
|
+
*
|
|
135
|
+
* Policy-free plumbing — no inkstone language data fields are pre-installed. A host that
|
|
136
|
+
* dispatches `setMinijinjaContext` / `setSqlSchema` installs `minijinjaContextField` /
|
|
137
|
+
* `sqlSchemaField` in its static `extensions` (they accept a dispatch before the lazy grammar
|
|
138
|
+
* that reads them resolves).
|
|
134
139
|
*/
|
|
135
140
|
declare class ControlledEditorHost {
|
|
136
141
|
private readonly compartment;
|
|
@@ -156,12 +161,6 @@ declare class ControlledEditorHost {
|
|
|
156
161
|
}
|
|
157
162
|
//#endregion
|
|
158
163
|
//#region src/extensions.d.ts
|
|
159
|
-
/**
|
|
160
|
-
* Simplified-Chinese strings for the search / goto-line panels, as an opt-in extension —
|
|
161
|
-
* inkstone's defaults are English, so pass this through `extensions` to localize the panel
|
|
162
|
-
* (`search` must be on for the panel to exist at all).
|
|
163
|
-
*/
|
|
164
|
-
declare const searchPhrasesZhCn: Extension;
|
|
165
164
|
interface DocumentExtensionsOptions {
|
|
166
165
|
/**
|
|
167
166
|
* Placeholder text shown while the document is empty.
|
|
@@ -556,6 +555,56 @@ declare const codeMirrorLanguages: readonly CodeMirrorLanguage[];
|
|
|
556
555
|
*/
|
|
557
556
|
declare function loadLanguage(language: CodeMirrorLanguage): Promise<Extension>;
|
|
558
557
|
//#endregion
|
|
558
|
+
//#region src/locale.d.ts
|
|
559
|
+
/**
|
|
560
|
+
* Simplified-Chinese strings for the search / goto-line panels, as an opt-in extension —
|
|
561
|
+
* inkstone's defaults are English, so pass this through `extensions` to localize the panel
|
|
562
|
+
* (`search` must be on for the panel to exist at all).
|
|
563
|
+
*/
|
|
564
|
+
declare const searchPhrasesZhCn: Extension;
|
|
565
|
+
//#endregion
|
|
566
|
+
//#region src/merge-chrome.d.ts
|
|
567
|
+
/**
|
|
568
|
+
* Chrome for the surfaces `@codemirror/merge` owns, in catppuccin: deletions read red on the
|
|
569
|
+
* original side, insertions green on the modified side (the package scopes sides through the
|
|
570
|
+
* cm-merge-a / cm-merge-b classes it places on each editor root), and the collapsed-lines bar
|
|
571
|
+
* drops its hardcoded grays for flavor colors. Regular theme precedence — it beats the merge
|
|
572
|
+
* package's baseTheme by CodeMirror's theme-over-base contract, and a caller theme layered
|
|
573
|
+
* after it still overrides it.
|
|
574
|
+
*/
|
|
575
|
+
declare function mergeTheme(dark: boolean): Extension;
|
|
576
|
+
/**
|
|
577
|
+
* The foreground the injected diff chrome inherits: set it as the diff container's `color` so
|
|
578
|
+
* the revert buttons between the editors — which sit outside both editors' theme scopes —
|
|
579
|
+
* follow the flavor (and flip with `dark`). The editors paint their own flavor colors over it.
|
|
580
|
+
*/
|
|
581
|
+
declare function diffChromeColor(dark: boolean): string;
|
|
582
|
+
/**
|
|
583
|
+
* The two merge-view surfaces an editor theme cannot reach, styled through one injected rule
|
|
584
|
+
* set per document/shadow root (the same pattern as the monaco host's hover-geometry fix),
|
|
585
|
+
* scoped to containers carrying the `data-inkstone-diff` attribute:
|
|
586
|
+
*
|
|
587
|
+
* - `.cm-mergeView` is the shared scroll surface *around* both editors; giving it the
|
|
588
|
+
* container's full height is what makes a container height scroll the diff as one unit.
|
|
589
|
+
* - The revert buttons live between the editors, outside either theme scope. They inherit
|
|
590
|
+
* the container's `color` (set from {@link diffChromeColor}, so dark flips reach them) and
|
|
591
|
+
* get a hover tint mixed from that same currentColor — no per-flavor rules needed.
|
|
592
|
+
*/
|
|
593
|
+
declare function installDiffChrome(root: Document | ShadowRoot): void;
|
|
594
|
+
/**
|
|
595
|
+
* The document or shadow root a container mounts its editors into — what
|
|
596
|
+
* {@link installDiffChrome} takes, and what `ControlledMergeOptions.root` expects.
|
|
597
|
+
*/
|
|
598
|
+
declare function editorRoot(container: HTMLElement): Document | ShadowRoot;
|
|
599
|
+
/**
|
|
600
|
+
* Keyboard access for the merge view's mouse-only controls, wired on the diff container:
|
|
601
|
+
* collapsed-lines bars become focusable buttons, revert buttons get an explicit `type` and a
|
|
602
|
+
* keyboard/programmatic-click bridge to the mousedown `@codemirror/merge` listens for. A
|
|
603
|
+
* MutationObserver keeps late-rendered controls covered; the returned function tears
|
|
604
|
+
* everything down.
|
|
605
|
+
*/
|
|
606
|
+
declare function installDiffControlKeyboardSupport(container: HTMLElement): () => void;
|
|
607
|
+
//#endregion
|
|
559
608
|
//#region src/merge-host.d.ts
|
|
560
609
|
interface ControlledMergeOptions extends MergeConfig$1 {
|
|
561
610
|
/**
|
|
@@ -621,7 +670,10 @@ interface ControlledMergeOptions extends MergeConfig$1 {
|
|
|
621
670
|
* `collapseUnchanged` …) reconfigure through {@link MergeView.reconfigure} on {@link view}.
|
|
622
671
|
*
|
|
623
672
|
* Policy-free plumbing: neither side is read-only by default — wire that through
|
|
624
|
-
* `originalExtensions` / `modifiedExtensions` to match how the documents are controlled
|
|
673
|
+
* `originalExtensions` / `modifiedExtensions` to match how the documents are controlled —
|
|
674
|
+
* and no inkstone language data fields are pre-installed: a host that dispatches
|
|
675
|
+
* `setMinijinjaContext` / `setSqlSchema` installs `minijinjaContextField` / `sqlSchemaField`
|
|
676
|
+
* in the shared `extensions` (same rule as `ControlledEditorHost`).
|
|
625
677
|
* Framework-agnostic, same as `ControlledEditorHost`.
|
|
626
678
|
*/
|
|
627
679
|
declare class ControlledMergeHost {
|
|
@@ -675,11 +727,20 @@ interface SqlSchema {
|
|
|
675
727
|
*/
|
|
676
728
|
declare const setSqlSchema: import("@codemirror/state").StateEffectType<SqlSchema | null>;
|
|
677
729
|
/**
|
|
678
|
-
* Holds the schema that SQL table/column completion reads.
|
|
679
|
-
* eagerly; the `sql`-family language supports also include it for
|
|
680
|
-
* (the default) means no schema — keyword completion still works,
|
|
681
|
-
* off.
|
|
730
|
+
* Holds the schema that SQL table/column completion reads. `@coldsmirk/inkstone-react`'s
|
|
731
|
+
* components install it eagerly; the `sql`-family language supports also include it for
|
|
732
|
+
* hand-built editors. `null` (the default) means no schema — keyword completion still works,
|
|
733
|
+
* table/column completion stays off.
|
|
682
734
|
*/
|
|
683
735
|
declare const sqlSchemaField: StateField<SqlSchema | null>;
|
|
684
736
|
//#endregion
|
|
685
|
-
|
|
737
|
+
//#region src/theme.d.ts
|
|
738
|
+
declare function toCssSize(value: string | number | undefined): string | undefined;
|
|
739
|
+
/**
|
|
740
|
+
* inkstone's default dynamic theme layer: the catppuccin flavor picked by `dark`, plus
|
|
741
|
+
* optional height/width sizing. The catppuccin theme is injected at low precedence so a
|
|
742
|
+
* caller's own theme (layered after it, e.g. through a dynamic-extensions slot) overrides it.
|
|
743
|
+
*/
|
|
744
|
+
declare function defaultThemeExtensions(dark: boolean, height?: string | number, width?: string | number, fontSize?: number, lineHeight?: number): Extension[];
|
|
745
|
+
//#endregion
|
|
746
|
+
export { type CodeMirrorLanguage, ControlledEditorHost, type ControlledEditorOptions, ControlledMergeHost, type ControlledMergeOptions, type DocumentExtensionsOptions, type EditorContext, type IrField, type IrSchema, type IrType, type Member, type MergeConfig, type MergeView, type SqlSchema, codeMirrorLanguages, defaultThemeExtensions, diffChromeColor, documentExtensions, editorRoot, installDiffChrome, installDiffControlKeyboardSupport, loadLanguage, mergeTheme, minijinjaContextField, normalizeContext, resolveMembers, searchPhrasesZhCn, setMinijinjaContext, setSqlSchema, sqlSchemaField, toCssSize, typeAtPath };
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { a as setMinijinjaContext, i as resolveMembers, n as minijinjaContextField, o as typeAtPath, r as normalizeContext } from "./context-BJzyiP0A.js";
|
|
2
2
|
import { n as sqlSchemaField, t as setSqlSchema } from "./sql-schema-DiPx5-bu.js";
|
|
3
|
-
import { Compartment, EditorState, Transaction } from "@codemirror/state";
|
|
3
|
+
import { Compartment, EditorState, Prec, Transaction } from "@codemirror/state";
|
|
4
4
|
import { EditorView, drawSelection, highlightActiveLine, keymap, lineNumbers, placeholder } from "@codemirror/view";
|
|
5
5
|
import { autocompletion, closeBrackets, closeBracketsKeymap, completionKeymap } from "@codemirror/autocomplete";
|
|
6
6
|
import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
|
|
7
7
|
import { LanguageSupport, StreamLanguage, bracketMatching, codeFolding, foldGutter, foldKeymap, indentOnInput } from "@codemirror/language";
|
|
8
8
|
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
|
|
9
|
+
import { flavors } from "@catppuccin/palette";
|
|
10
|
+
import { catppuccinLatte, catppuccinMacchiato } from "@catppuccin/codemirror";
|
|
11
|
+
import { CODE_FONT_FAMILY } from "@coldsmirk/inkstone-core";
|
|
9
12
|
import { MergeView } from "@codemirror/merge";
|
|
10
13
|
//#region src/minimal-replace.ts
|
|
11
14
|
function minimalReplace(state, externalValue) {
|
|
@@ -83,8 +86,6 @@ var ControlledEditorHost = class {
|
|
|
83
86
|
state: EditorState.create({
|
|
84
87
|
doc,
|
|
85
88
|
extensions: [
|
|
86
|
-
minijinjaContextField,
|
|
87
|
-
sqlSchemaField,
|
|
88
89
|
...extensions,
|
|
89
90
|
this.compartment.of(dynamicExtensions),
|
|
90
91
|
EditorView.updateListener.of((update) => {
|
|
@@ -114,25 +115,8 @@ var ControlledEditorHost = class {
|
|
|
114
115
|
this.view.destroy();
|
|
115
116
|
}
|
|
116
117
|
};
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
Replace: "替换",
|
|
120
|
-
next: "下一个",
|
|
121
|
-
previous: "上一个",
|
|
122
|
-
all: "全部",
|
|
123
|
-
"match case": "区分大小写",
|
|
124
|
-
regexp: "正则表达式",
|
|
125
|
-
"by word": "全字匹配",
|
|
126
|
-
replace: "替换",
|
|
127
|
-
"replace all": "全部替换",
|
|
128
|
-
close: "关闭",
|
|
129
|
-
"current match": "当前匹配",
|
|
130
|
-
"on line": "所在行",
|
|
131
|
-
"replaced $ matches": "已替换 $ 处匹配",
|
|
132
|
-
"replaced match on line $": "已替换第 $ 行的匹配",
|
|
133
|
-
"Go to line": "跳转到行",
|
|
134
|
-
go: "跳转"
|
|
135
|
-
});
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region src/extensions.ts
|
|
136
120
|
function documentExtensions({ placeholder: placeholder$1, lineWrapping = false, showLineNumbers = false, folding = false, spellcheck = false, search = false } = {}) {
|
|
137
121
|
return [
|
|
138
122
|
...showLineNumbers ? [lineNumbers()] : [],
|
|
@@ -389,6 +373,378 @@ const codeMirrorLanguages = Object.keys(loaders).toSorted();
|
|
|
389
373
|
function loadLanguage(language) {
|
|
390
374
|
return loaders[language]();
|
|
391
375
|
}
|
|
376
|
+
const searchPhrasesZhCn = EditorState.phrases.of({
|
|
377
|
+
Find: "查找",
|
|
378
|
+
Replace: "替换",
|
|
379
|
+
next: "下一个",
|
|
380
|
+
previous: "上一个",
|
|
381
|
+
all: "全部",
|
|
382
|
+
"match case": "区分大小写",
|
|
383
|
+
regexp: "正则表达式",
|
|
384
|
+
"by word": "全字匹配",
|
|
385
|
+
replace: "替换",
|
|
386
|
+
"replace all": "全部替换",
|
|
387
|
+
close: "关闭",
|
|
388
|
+
"current match": "当前匹配",
|
|
389
|
+
"on line": "所在行",
|
|
390
|
+
"replaced $ matches": "已替换 $ 处匹配",
|
|
391
|
+
"replaced match on line $": "已替换第 $ 行的匹配",
|
|
392
|
+
"Go to line": "跳转到行",
|
|
393
|
+
go: "跳转"
|
|
394
|
+
});
|
|
395
|
+
//#endregion
|
|
396
|
+
//#region src/theme.ts
|
|
397
|
+
function toCssSize(value) {
|
|
398
|
+
if (value === void 0) return;
|
|
399
|
+
return typeof value === "number" ? `${value}px` : value;
|
|
400
|
+
}
|
|
401
|
+
function alphaOf(color, alphaValue) {
|
|
402
|
+
return `rgba(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b}, ${alphaValue})`;
|
|
403
|
+
}
|
|
404
|
+
function completionIconMask(body) {
|
|
405
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none" stroke="#000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">${body}</svg>`;
|
|
406
|
+
return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
|
|
407
|
+
}
|
|
408
|
+
const COMPLETION_ICON_FALLBACK = completionIconMask("<circle cx=\"8\" cy=\"8\" r=\"2.5\"/>");
|
|
409
|
+
const COMPLETION_ICONS = {
|
|
410
|
+
keyword: completionIconMask("<path d=\"M5.5 5 2.5 8l3 3\"/><path d=\"m10.5 5 3 3-3 3\"/>"),
|
|
411
|
+
function: completionIconMask("<path d=\"M10.8 3.4c-2-.4-2.9.7-3.2 2.5L6.4 12c-.3 1.7-1.2 2.2-2.6 1.8\"/><path d=\"M4.6 7.5h5\"/>"),
|
|
412
|
+
method: completionIconMask("<path d=\"M10.8 3.4c-2-.4-2.9.7-3.2 2.5L6.4 12c-.3 1.7-1.2 2.2-2.6 1.8\"/><path d=\"M4.6 7.5h5\"/>"),
|
|
413
|
+
variable: completionIconMask("<path d=\"M4 5c2.2 0 5.3 6 8 6\"/><path d=\"M12 5c-2.7 0-5.8 6-8 6\"/>"),
|
|
414
|
+
constant: completionIconMask("<path d=\"M3.5 5.2h9\"/><path d=\"M6.2 5.2v6.3\"/><path d=\"M10.2 5.2v4.4c0 1.3.6 1.9 1.7 1.9\"/>"),
|
|
415
|
+
property: completionIconMask("<circle cx=\"4.9\" cy=\"11.1\" r=\"1.8\"/><circle cx=\"11.1\" cy=\"4.9\" r=\"1.8\"/><path d=\"M6.4 9.6l3.2-3.2\"/>"),
|
|
416
|
+
class: completionIconMask("<rect x=\"3.5\" y=\"3.5\" width=\"9\" height=\"9\" rx=\"2.2\"/>"),
|
|
417
|
+
interface: completionIconMask("<circle cx=\"8\" cy=\"8\" r=\"4.5\"/>"),
|
|
418
|
+
type: completionIconMask("<path d=\"M4 4.5h8\"/><path d=\"M8 4.5V12\"/>"),
|
|
419
|
+
enum: completionIconMask("<path d=\"M6.5 4.5h6\"/><path d=\"M6.5 8h6\"/><path d=\"M6.5 11.5h6\"/><path d=\"M3.4 4.5h.01\"/><path d=\"M3.4 8h.01\"/><path d=\"M3.4 11.5h.01\"/>"),
|
|
420
|
+
namespace: completionIconMask("<path d=\"M6.2 3.5c-1.3 0-1.9.6-1.9 1.9v1.2c0 .9-.4 1.4-1.3 1.4.9 0 1.3.5 1.3 1.4v1.2c0 1.3.6 1.9 1.9 1.9\"/><path d=\"M9.8 3.5c1.3 0 1.9.6 1.9 1.9v1.2c0 .9.4 1.4 1.3 1.4-.9 0-1.3.5-1.3 1.4v1.2c0 1.3-.6 1.9-1.9 1.9\"/>"),
|
|
421
|
+
text: completionIconMask("<path d=\"M3.5 5h9\"/><path d=\"M3.5 8h9\"/><path d=\"M3.5 11h5.5\"/>")
|
|
422
|
+
};
|
|
423
|
+
function completionIconRules() {
|
|
424
|
+
const rules = {};
|
|
425
|
+
for (const [kind, mask] of Object.entries(COMPLETION_ICONS)) rules[`.cm-completionIcon-${kind}:after`] = {
|
|
426
|
+
maskImage: mask,
|
|
427
|
+
WebkitMaskImage: mask
|
|
428
|
+
};
|
|
429
|
+
return rules;
|
|
430
|
+
}
|
|
431
|
+
function chromeTheme(dark) {
|
|
432
|
+
const { colors } = dark ? flavors.macchiato : flavors.latte;
|
|
433
|
+
const hairline = `1px solid ${alphaOf(colors.overlay0, .35)}`;
|
|
434
|
+
const frame = {
|
|
435
|
+
border: hairline,
|
|
436
|
+
borderRadius: "8px",
|
|
437
|
+
boxShadow: dark ? "0 8px 24px rgba(0, 0, 0, 0.5)" : "0 8px 24px rgba(0, 0, 0, 0.12)",
|
|
438
|
+
color: colors.text.hex
|
|
439
|
+
};
|
|
440
|
+
return EditorView.theme({
|
|
441
|
+
"&": { colorScheme: dark ? "dark" : "light" },
|
|
442
|
+
".cm-scroller": { fontFamily: CODE_FONT_FAMILY },
|
|
443
|
+
".cm-tooltip": frame,
|
|
444
|
+
".cm-tooltip.cm-tooltip-autocomplete": {
|
|
445
|
+
...frame,
|
|
446
|
+
"& > ul": {
|
|
447
|
+
borderRadius: "7px",
|
|
448
|
+
padding: "4px",
|
|
449
|
+
maxHeight: "16em"
|
|
450
|
+
},
|
|
451
|
+
"& > ul > li": {
|
|
452
|
+
display: "flex",
|
|
453
|
+
alignItems: "center",
|
|
454
|
+
padding: "3px 8px",
|
|
455
|
+
borderRadius: "5px",
|
|
456
|
+
lineHeight: "1.45"
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
".cm-completionLabel": {
|
|
460
|
+
minWidth: "0",
|
|
461
|
+
overflow: "hidden",
|
|
462
|
+
textOverflow: "ellipsis"
|
|
463
|
+
},
|
|
464
|
+
".cm-completionMatchedText": {
|
|
465
|
+
textDecoration: "none",
|
|
466
|
+
fontWeight: "600",
|
|
467
|
+
color: colors.blue.hex
|
|
468
|
+
},
|
|
469
|
+
".cm-completionDetail": {
|
|
470
|
+
marginLeft: "auto",
|
|
471
|
+
paddingLeft: "12px",
|
|
472
|
+
fontStyle: "normal",
|
|
473
|
+
fontSize: "85%",
|
|
474
|
+
color: colors.overlay1.hex
|
|
475
|
+
},
|
|
476
|
+
".cm-completionIcon": {
|
|
477
|
+
width: "14px",
|
|
478
|
+
paddingRight: "8px",
|
|
479
|
+
opacity: "1",
|
|
480
|
+
color: colors.overlay1.hex
|
|
481
|
+
},
|
|
482
|
+
".cm-completionIcon:after": {
|
|
483
|
+
content: "''",
|
|
484
|
+
display: "block",
|
|
485
|
+
width: "12px",
|
|
486
|
+
height: "12px",
|
|
487
|
+
backgroundColor: "currentColor",
|
|
488
|
+
maskImage: COMPLETION_ICON_FALLBACK,
|
|
489
|
+
WebkitMaskImage: COMPLETION_ICON_FALLBACK,
|
|
490
|
+
maskRepeat: "no-repeat",
|
|
491
|
+
WebkitMaskRepeat: "no-repeat",
|
|
492
|
+
maskPosition: "center",
|
|
493
|
+
WebkitMaskPosition: "center",
|
|
494
|
+
maskSize: "contain",
|
|
495
|
+
WebkitMaskSize: "contain"
|
|
496
|
+
},
|
|
497
|
+
...completionIconRules(),
|
|
498
|
+
".cm-completionIcon-keyword": { color: colors.mauve.hex },
|
|
499
|
+
".cm-completionIcon-function, .cm-completionIcon-method": { color: colors.blue.hex },
|
|
500
|
+
".cm-completionIcon-variable": { color: colors.peach.hex },
|
|
501
|
+
".cm-completionIcon-constant": { color: colors.sky.hex },
|
|
502
|
+
".cm-completionIcon-property": { color: colors.teal.hex },
|
|
503
|
+
".cm-completionIcon-namespace": { color: colors.sapphire.hex },
|
|
504
|
+
".cm-completionIcon-text": { color: colors.overlay1.hex },
|
|
505
|
+
".cm-completionIcon-class, .cm-completionIcon-type, .cm-completionIcon-interface, .cm-completionIcon-enum": { color: colors.yellow.hex },
|
|
506
|
+
".cm-tooltip.cm-completionInfo": {
|
|
507
|
+
...frame,
|
|
508
|
+
padding: "8px 10px",
|
|
509
|
+
maxWidth: "26em"
|
|
510
|
+
},
|
|
511
|
+
".cm-tooltip-lint": {
|
|
512
|
+
padding: "4px",
|
|
513
|
+
maxWidth: "26em",
|
|
514
|
+
overflowWrap: "anywhere"
|
|
515
|
+
},
|
|
516
|
+
".cm-diagnostic": {
|
|
517
|
+
margin: "0",
|
|
518
|
+
padding: "3px 8px",
|
|
519
|
+
borderLeftWidth: "3px",
|
|
520
|
+
borderRadius: "5px",
|
|
521
|
+
lineHeight: "1.45"
|
|
522
|
+
},
|
|
523
|
+
".cm-diagnostic-error": { borderLeftColor: colors.red.hex },
|
|
524
|
+
".cm-diagnostic-warning": { borderLeftColor: colors.yellow.hex },
|
|
525
|
+
".cm-diagnostic-info": { borderLeftColor: colors.overlay1.hex },
|
|
526
|
+
".cm-diagnostic-hint": { borderLeftColor: colors.blue.hex },
|
|
527
|
+
".cm-diagnosticAction": {
|
|
528
|
+
padding: "2px 6px",
|
|
529
|
+
backgroundColor: colors.surface1.hex,
|
|
530
|
+
color: colors.text.hex,
|
|
531
|
+
borderRadius: "4px"
|
|
532
|
+
},
|
|
533
|
+
".cm-diagnosticSource": {
|
|
534
|
+
fontSize: "85%",
|
|
535
|
+
color: colors.overlay1.hex,
|
|
536
|
+
opacity: "1"
|
|
537
|
+
},
|
|
538
|
+
"&.cm-focused": { outline: "none" },
|
|
539
|
+
".cm-activeLine": { backgroundColor: alphaOf(colors.overlay0, .12) },
|
|
540
|
+
".cm-activeLineGutter": { backgroundColor: alphaOf(colors.overlay0, .12) },
|
|
541
|
+
"&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": { backgroundColor: alphaOf(colors.blue, dark ? .35 : .25) },
|
|
542
|
+
".cm-selectionBackground": { backgroundColor: alphaOf(colors.blue, dark ? .2 : .14) },
|
|
543
|
+
".cm-content ::selection": { backgroundColor: alphaOf(colors.blue, dark ? .35 : .25) },
|
|
544
|
+
".cm-scroller, .cm-tooltip-autocomplete > ul, .cm-tooltip.cm-completionInfo": {
|
|
545
|
+
scrollbarWidth: "thin",
|
|
546
|
+
scrollbarColor: `${alphaOf(colors.overlay0, .55)} transparent`
|
|
547
|
+
},
|
|
548
|
+
".cm-panels.cm-panels-top": { borderBottom: hairline },
|
|
549
|
+
".cm-panels.cm-panels-bottom": { borderTop: hairline },
|
|
550
|
+
".cm-panel.cm-search, .cm-panel.cm-gotoLine": {
|
|
551
|
+
position: "relative",
|
|
552
|
+
display: "flex",
|
|
553
|
+
flexWrap: "wrap",
|
|
554
|
+
alignItems: "center",
|
|
555
|
+
columnGap: "8px",
|
|
556
|
+
rowGap: "8px",
|
|
557
|
+
margin: "0",
|
|
558
|
+
padding: "10px 44px 10px 14px"
|
|
559
|
+
},
|
|
560
|
+
".cm-panel.cm-search br": {
|
|
561
|
+
flexBasis: "100%",
|
|
562
|
+
height: "0",
|
|
563
|
+
margin: "0",
|
|
564
|
+
border: "none"
|
|
565
|
+
},
|
|
566
|
+
".cm-panel.cm-search label, .cm-panel.cm-gotoLine label": {
|
|
567
|
+
display: "inline-flex",
|
|
568
|
+
alignItems: "center",
|
|
569
|
+
gap: "6px",
|
|
570
|
+
margin: "0",
|
|
571
|
+
fontSize: "12.5px",
|
|
572
|
+
color: colors.subtext0.hex,
|
|
573
|
+
cursor: "pointer",
|
|
574
|
+
userSelect: "none"
|
|
575
|
+
},
|
|
576
|
+
".cm-panel.cm-search input[type=checkbox]": {
|
|
577
|
+
margin: "0",
|
|
578
|
+
width: "14px",
|
|
579
|
+
height: "14px",
|
|
580
|
+
accentColor: colors.blue.hex
|
|
581
|
+
},
|
|
582
|
+
".cm-panel.cm-search button[name=close]": {
|
|
583
|
+
position: "absolute",
|
|
584
|
+
top: "10px",
|
|
585
|
+
right: "10px",
|
|
586
|
+
boxSizing: "border-box",
|
|
587
|
+
width: "28px",
|
|
588
|
+
height: "28px",
|
|
589
|
+
padding: "0",
|
|
590
|
+
display: "inline-flex",
|
|
591
|
+
alignItems: "center",
|
|
592
|
+
justifyContent: "center",
|
|
593
|
+
fontSize: "16px",
|
|
594
|
+
lineHeight: "1",
|
|
595
|
+
color: colors.overlay1.hex,
|
|
596
|
+
background: "transparent",
|
|
597
|
+
border: "none",
|
|
598
|
+
borderRadius: "6px",
|
|
599
|
+
cursor: "pointer"
|
|
600
|
+
},
|
|
601
|
+
".cm-panel.cm-search button[name=close]:hover": {
|
|
602
|
+
backgroundColor: colors.surface0.hex,
|
|
603
|
+
color: colors.text.hex
|
|
604
|
+
},
|
|
605
|
+
".cm-panel .cm-textfield": {
|
|
606
|
+
boxSizing: "border-box",
|
|
607
|
+
height: "28px",
|
|
608
|
+
width: "240px",
|
|
609
|
+
maxWidth: "100%",
|
|
610
|
+
margin: "0",
|
|
611
|
+
padding: "0 10px",
|
|
612
|
+
fontSize: "12.5px",
|
|
613
|
+
color: colors.text.hex,
|
|
614
|
+
backgroundColor: colors.base.hex,
|
|
615
|
+
border: hairline,
|
|
616
|
+
borderRadius: "6px"
|
|
617
|
+
},
|
|
618
|
+
".cm-panel .cm-textfield:focus": {
|
|
619
|
+
outline: "none",
|
|
620
|
+
borderColor: alphaOf(colors.blue, .6),
|
|
621
|
+
boxShadow: `0 0 0 2px ${alphaOf(colors.blue, .2)}`
|
|
622
|
+
},
|
|
623
|
+
".cm-panel .cm-button": {
|
|
624
|
+
boxSizing: "border-box",
|
|
625
|
+
height: "28px",
|
|
626
|
+
margin: "0",
|
|
627
|
+
padding: "0 12px",
|
|
628
|
+
fontSize: "12.5px",
|
|
629
|
+
color: colors.text.hex,
|
|
630
|
+
backgroundImage: "none",
|
|
631
|
+
backgroundColor: colors.surface0.hex,
|
|
632
|
+
border: hairline,
|
|
633
|
+
borderRadius: "6px",
|
|
634
|
+
cursor: "pointer"
|
|
635
|
+
},
|
|
636
|
+
".cm-panel .cm-button:hover": { backgroundColor: colors.surface1.hex },
|
|
637
|
+
".cm-panel .cm-button:active": {
|
|
638
|
+
backgroundImage: "none",
|
|
639
|
+
backgroundColor: colors.surface1.hex
|
|
640
|
+
}
|
|
641
|
+
}, { dark });
|
|
642
|
+
}
|
|
643
|
+
function defaultThemeExtensions(dark, height, width, fontSize, lineHeight) {
|
|
644
|
+
const extensions = [Prec.low(chromeTheme(dark)), Prec.low(dark ? catppuccinMacchiato : catppuccinLatte)];
|
|
645
|
+
const cssHeight = toCssSize(height);
|
|
646
|
+
const cssWidth = toCssSize(width);
|
|
647
|
+
if (cssHeight !== void 0 || cssWidth !== void 0 || fontSize !== void 0 || lineHeight !== void 0) {
|
|
648
|
+
const root = {};
|
|
649
|
+
if (cssHeight !== void 0) root.height = cssHeight;
|
|
650
|
+
if (cssWidth !== void 0) root.width = cssWidth;
|
|
651
|
+
if (fontSize !== void 0) root.fontSize = `${fontSize}px`;
|
|
652
|
+
const spec = { "&": root };
|
|
653
|
+
const scroller = {};
|
|
654
|
+
if (cssHeight !== void 0) scroller.overflow = "auto";
|
|
655
|
+
if (lineHeight !== void 0) scroller.lineHeight = lineHeight < 8 ? String(lineHeight) : `${lineHeight}px`;
|
|
656
|
+
if (Object.keys(scroller).length > 0) spec[".cm-scroller"] = scroller;
|
|
657
|
+
extensions.push(EditorView.theme(spec));
|
|
658
|
+
}
|
|
659
|
+
return extensions;
|
|
660
|
+
}
|
|
661
|
+
//#endregion
|
|
662
|
+
//#region src/merge-chrome.ts
|
|
663
|
+
function mergeTheme(dark) {
|
|
664
|
+
const { colors } = dark ? flavors.macchiato : flavors.latte;
|
|
665
|
+
const removed = colors.red;
|
|
666
|
+
const added = colors.green;
|
|
667
|
+
const underline = (color) => `linear-gradient(${alphaOf(color, .5)}, ${alphaOf(color, .5)}) bottom/100% 2px no-repeat`;
|
|
668
|
+
return EditorView.theme({
|
|
669
|
+
"&.cm-merge-a .cm-changedLine": { backgroundColor: alphaOf(removed, dark ? .14 : .09) },
|
|
670
|
+
"&.cm-merge-b .cm-changedLine": { backgroundColor: alphaOf(added, dark ? .14 : .09) },
|
|
671
|
+
"&.cm-merge-a .cm-changedText": { background: underline(removed) },
|
|
672
|
+
"&.cm-merge-b .cm-changedText": { background: underline(added) },
|
|
673
|
+
"&.cm-merge-a .cm-changedLineGutter": { background: removed.hex },
|
|
674
|
+
"&.cm-merge-b .cm-changedLineGutter": { background: added.hex },
|
|
675
|
+
".cm-collapsedLines": {
|
|
676
|
+
color: colors.subtext0.hex,
|
|
677
|
+
background: `linear-gradient(to bottom, transparent 0, ${colors.surface0.hex} 30%, ${colors.surface0.hex} 70%, transparent 100%)`
|
|
678
|
+
}
|
|
679
|
+
}, { dark });
|
|
680
|
+
}
|
|
681
|
+
function diffChromeColor(dark) {
|
|
682
|
+
return (dark ? flavors.macchiato : flavors.latte).colors.overlay1.hex;
|
|
683
|
+
}
|
|
684
|
+
const DIFF_CHROME_STYLE_SELECTOR = "style[data-inkstone=\"codemirror-diff\"]";
|
|
685
|
+
function installDiffChrome(root) {
|
|
686
|
+
if (root.querySelector(DIFF_CHROME_STYLE_SELECTOR)) return;
|
|
687
|
+
const style = (root.nodeType === 9 ? root : root.host.ownerDocument).createElement("style");
|
|
688
|
+
style.dataset.inkstone = "codemirror-diff";
|
|
689
|
+
style.textContent = [
|
|
690
|
+
"[data-inkstone-diff] > .cm-mergeView { height: 100%; }",
|
|
691
|
+
"[data-inkstone-diff] .cm-merge-revert button { color: inherit; border-radius: 4px; }",
|
|
692
|
+
"[data-inkstone-diff] .cm-merge-revert button:hover { background-color: color-mix(in srgb, currentColor 15%, transparent); }"
|
|
693
|
+
].join("\n");
|
|
694
|
+
if (root.nodeType === 9) root.head.append(style);
|
|
695
|
+
else root.append(style);
|
|
696
|
+
}
|
|
697
|
+
function editorRoot(container) {
|
|
698
|
+
const root = container.getRootNode();
|
|
699
|
+
if (root.nodeType === 9 || root.nodeType === 11 && "host" in root) return root;
|
|
700
|
+
return container.ownerDocument;
|
|
701
|
+
}
|
|
702
|
+
function eventElement(event) {
|
|
703
|
+
const target = event.target;
|
|
704
|
+
return target?.nodeType === 1 ? target : target?.parentElement ?? null;
|
|
705
|
+
}
|
|
706
|
+
function installDiffControlKeyboardSupport(container) {
|
|
707
|
+
const enhanceControls = () => {
|
|
708
|
+
for (const control of container.querySelectorAll(":scope .cm-collapsedLines")) {
|
|
709
|
+
control.setAttribute("role", "button");
|
|
710
|
+
control.tabIndex = 0;
|
|
711
|
+
}
|
|
712
|
+
for (const button of container.querySelectorAll(":scope .cm-merge-revert button")) button.type = "button";
|
|
713
|
+
};
|
|
714
|
+
const handleClick = (event) => {
|
|
715
|
+
if (event.detail !== 0) return;
|
|
716
|
+
const button = eventElement(event)?.closest(".cm-merge-revert button");
|
|
717
|
+
if (!button || !container.contains(button)) return;
|
|
718
|
+
event.preventDefault();
|
|
719
|
+
const MouseEventConstructor = container.ownerDocument.defaultView?.MouseEvent ?? MouseEvent;
|
|
720
|
+
button.dispatchEvent(new MouseEventConstructor("mousedown", {
|
|
721
|
+
bubbles: true,
|
|
722
|
+
button: 0,
|
|
723
|
+
cancelable: true
|
|
724
|
+
}));
|
|
725
|
+
};
|
|
726
|
+
const handleKeyDown = (event) => {
|
|
727
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
728
|
+
const control = eventElement(event)?.closest(".cm-collapsedLines");
|
|
729
|
+
if (!control || !container.contains(control)) return;
|
|
730
|
+
event.preventDefault();
|
|
731
|
+
event.stopPropagation();
|
|
732
|
+
control.click();
|
|
733
|
+
};
|
|
734
|
+
enhanceControls();
|
|
735
|
+
const observer = new MutationObserver(enhanceControls);
|
|
736
|
+
observer.observe(container, {
|
|
737
|
+
childList: true,
|
|
738
|
+
subtree: true
|
|
739
|
+
});
|
|
740
|
+
container.addEventListener("click", handleClick);
|
|
741
|
+
container.addEventListener("keydown", handleKeyDown, { capture: true });
|
|
742
|
+
return () => {
|
|
743
|
+
observer.disconnect();
|
|
744
|
+
container.removeEventListener("click", handleClick);
|
|
745
|
+
container.removeEventListener("keydown", handleKeyDown, { capture: true });
|
|
746
|
+
};
|
|
747
|
+
}
|
|
392
748
|
//#endregion
|
|
393
749
|
//#region src/merge-host.ts
|
|
394
750
|
var ControlledMergeHost = class {
|
|
@@ -405,8 +761,6 @@ var ControlledMergeHost = class {
|
|
|
405
761
|
doc: original,
|
|
406
762
|
extensions: [
|
|
407
763
|
...originalExtensions,
|
|
408
|
-
minijinjaContextField,
|
|
409
|
-
sqlSchemaField,
|
|
410
764
|
...extensions,
|
|
411
765
|
this.originalCompartment.of(dynamicExtensions),
|
|
412
766
|
EditorView.updateListener.of((update) => {
|
|
@@ -418,8 +772,6 @@ var ControlledMergeHost = class {
|
|
|
418
772
|
doc: modified,
|
|
419
773
|
extensions: [
|
|
420
774
|
...modifiedExtensions,
|
|
421
|
-
minijinjaContextField,
|
|
422
|
-
sqlSchemaField,
|
|
423
775
|
...extensions,
|
|
424
776
|
this.modifiedCompartment.of(dynamicExtensions),
|
|
425
777
|
EditorView.updateListener.of((update) => {
|
|
@@ -457,4 +809,4 @@ var ControlledMergeHost = class {
|
|
|
457
809
|
}
|
|
458
810
|
};
|
|
459
811
|
//#endregion
|
|
460
|
-
export { ControlledEditorHost, ControlledMergeHost, codeMirrorLanguages, documentExtensions, loadLanguage, minijinjaContextField, normalizeContext, resolveMembers, searchPhrasesZhCn, setMinijinjaContext, setSqlSchema, sqlSchemaField, typeAtPath };
|
|
812
|
+
export { ControlledEditorHost, ControlledMergeHost, codeMirrorLanguages, defaultThemeExtensions, diffChromeColor, documentExtensions, editorRoot, installDiffChrome, installDiffControlKeyboardSupport, loadLanguage, mergeTheme, minijinjaContextField, normalizeContext, resolveMembers, searchPhrasesZhCn, setMinijinjaContext, setSqlSchema, sqlSchemaField, toCssSize, typeAtPath };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coldsmirk/inkstone-codemirror",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Framework-agnostic CodeMirror 6 plumbing: a controlled editor host (create-once, external-value reconcile, in-place theme swap)
|
|
3
|
+
"version": "0.13.0",
|
|
4
|
+
"description": "Framework-agnostic CodeMirror 6 plumbing: a controlled editor host (create-once, external-value reconcile, in-place theme swap), the standard document extension bundle, and the editors' catppuccin theming.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codemirror",
|
|
7
7
|
"codemirror6",
|
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
"dist"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
+
"@catppuccin/codemirror": "^1.0.1",
|
|
38
|
+
"@catppuccin/palette": "^1.8.0",
|
|
37
39
|
"@codemirror/lang-angular": "^0.1.4",
|
|
38
40
|
"@codemirror/lang-cpp": "^6.0.3",
|
|
39
41
|
"@codemirror/lang-css": "^6.3.1",
|
|
@@ -59,7 +61,8 @@
|
|
|
59
61
|
"@codemirror/legacy-modes": "^6.5.3",
|
|
60
62
|
"@codemirror/lint": "^6.9.7",
|
|
61
63
|
"@codemirror/merge": "^6.12.2",
|
|
62
|
-
"@lezer/common": "^1.5.2"
|
|
64
|
+
"@lezer/common": "^1.5.2",
|
|
65
|
+
"@coldsmirk/inkstone-core": "^0.13.0"
|
|
63
66
|
},
|
|
64
67
|
"devDependencies": {
|
|
65
68
|
"@codemirror/autocomplete": "^6.20.3",
|