@vimee/plugin-monaco 0.1.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 ADDED
@@ -0,0 +1,112 @@
1
+ # @vimee/plugin-monaco
2
+
3
+ **Attach vim editing to any Monaco Editor instance**
4
+
5
+ [![npm](https://img.shields.io/npm/v/@vimee/plugin-monaco)](https://www.npmjs.com/package/@vimee/plugin-monaco)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ Framework-agnostic plugin that adds vim keybindings to a [Monaco Editor](https://microsoft.github.io/monaco-editor/) instance. Works with vanilla JS, React, or any Monaco wrapper.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install @vimee/core @vimee/plugin-monaco
14
+ ```
15
+
16
+ > **Note:** You also need `monaco-editor` as a peer dependency in your project.
17
+
18
+ ## Quick Start
19
+
20
+ ```ts
21
+ import * as monaco from "monaco-editor";
22
+ import { attach } from "@vimee/plugin-monaco";
23
+
24
+ const editor = monaco.editor.create(document.getElementById("editor")!, {
25
+ value: 'console.log("Hello, vim!");',
26
+ language: "typescript",
27
+ });
28
+
29
+ const vim = attach(editor, {
30
+ onChange: (value) => console.log("Content:", value),
31
+ onModeChange: (mode) => console.log("Mode:", mode),
32
+ onSave: (value) => console.log("Saved:", value),
33
+ });
34
+
35
+ // Later...
36
+ vim.destroy();
37
+ ```
38
+
39
+ ## API
40
+
41
+ ### `attach(editor, options?)`
42
+
43
+ Attaches vim keybindings to a Monaco Editor instance. Returns a `VimMonaco` handle.
44
+
45
+ The `editor` parameter accepts any object satisfying the `MonacoEditor` interface — typically a `monaco.editor.IStandaloneCodeEditor`.
46
+
47
+ #### Options
48
+
49
+ | Option | Type | Default | Description |
50
+ |--------|------|---------|-------------|
51
+ | `readOnly` | `boolean` | `false` | Read-only mode (motions work, edits blocked) |
52
+ | `onChange` | `(value: string) => void` | — | Content change callback |
53
+ | `onModeChange` | `(mode: VimMode) => void` | — | Mode change callback |
54
+ | `onYank` | `(text: string) => void` | — | Yank callback |
55
+ | `onSave` | `(value: string) => void` | — | `:w` callback |
56
+ | `onAction` | `(action: VimAction, key: string) => void` | — | Action callback |
57
+ | `indentStyle` | `"space" \| "tab"` | `"space"` | Indent character |
58
+ | `indentWidth` | `number` | `2` | Spaces per indent |
59
+
60
+ #### VimMonaco
61
+
62
+ | Method | Return | Description |
63
+ |--------|--------|-------------|
64
+ | `getMode()` | `VimMode` | Current vim mode |
65
+ | `getCursor()` | `CursorPosition` | Current cursor position (0-based) |
66
+ | `getContent()` | `string` | Current editor content |
67
+ | `destroy()` | `void` | Detach all listeners and clean up |
68
+
69
+ ## Cursor Style
70
+
71
+ The plugin automatically switches Monaco's cursor style based on vim mode:
72
+
73
+ - **Normal / Visual / Command-line mode** → Block cursor
74
+ - **Insert mode** → Line cursor
75
+
76
+ ## Visual Mode Decorations
77
+
78
+ In visual and visual-line mode, the plugin applies a CSS class `vimee-visual-selection` to the selected range. You can style it:
79
+
80
+ ```css
81
+ .vimee-visual-selection {
82
+ background-color: rgba(255, 165, 0, 0.3);
83
+ }
84
+ ```
85
+
86
+ ## Features
87
+
88
+ - Automatic cursor style switching (block ↔ line)
89
+ - Visual mode selection highlighting via decorations
90
+ - H/M/L motions with viewport tracking
91
+ - Ctrl-U/D/B/F page scrolling
92
+ - IME composition support (CJK input)
93
+ - Auto-scrolls to keep cursor visible (`revealLine`)
94
+ - All vim features from `@vimee/core` (motions, operators, text objects, search, macros, marks, etc.)
95
+
96
+ ## Utilities
97
+
98
+ The package also exports cursor and viewport utilities for advanced usage:
99
+
100
+ ```ts
101
+ import {
102
+ cursorToMonacoPosition, // Convert vimee CursorPosition (0-based) → Monaco IPosition (1-based)
103
+ monacoPositionToCursor, // Convert Monaco IPosition (1-based) → vimee CursorPosition (0-based)
104
+ getTopLine, // Get first visible line (0-based)
105
+ getVisibleLines, // Get visible line count
106
+ revealLine, // Scroll to a specific line (0-based)
107
+ } from "@vimee/plugin-monaco";
108
+ ```
109
+
110
+ ## License
111
+
112
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,272 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ attach: () => attach,
24
+ cursorToMonacoPosition: () => cursorToMonacoPosition,
25
+ getTopLine: () => getTopLine,
26
+ getVisibleLines: () => getVisibleLines,
27
+ monacoPositionToCursor: () => monacoPositionToCursor,
28
+ revealLine: () => revealLine
29
+ });
30
+ module.exports = __toCommonJS(index_exports);
31
+
32
+ // src/attach.ts
33
+ var import_core = require("@vimee/core");
34
+
35
+ // src/cursor.ts
36
+ function cursorToMonacoPosition(cursor) {
37
+ return {
38
+ lineNumber: cursor.line + 1,
39
+ column: cursor.col + 1
40
+ };
41
+ }
42
+ function monacoPositionToCursor(position) {
43
+ return {
44
+ line: position.lineNumber - 1,
45
+ col: position.column - 1
46
+ };
47
+ }
48
+
49
+ // src/viewport.ts
50
+ function getTopLine(editor) {
51
+ const ranges = editor.getVisibleRanges();
52
+ if (ranges.length === 0) return 0;
53
+ return ranges[0].startLineNumber - 1;
54
+ }
55
+ function getVisibleLines(editor) {
56
+ const ranges = editor.getVisibleRanges();
57
+ if (ranges.length === 0) return 20;
58
+ const first = ranges[0];
59
+ const last = ranges[ranges.length - 1];
60
+ return last.endLineNumber - first.startLineNumber + 1;
61
+ }
62
+ function revealLine(editor, line) {
63
+ editor.revealLine(line + 1);
64
+ }
65
+
66
+ // src/attach.ts
67
+ function attach(editor, options = {}) {
68
+ const {
69
+ readOnly = false,
70
+ onChange,
71
+ onModeChange,
72
+ onYank,
73
+ onSave,
74
+ onAction,
75
+ indentStyle,
76
+ indentWidth
77
+ } = options;
78
+ const buffer = new import_core.TextBuffer(editor.getValue());
79
+ const pos = editor.getPosition();
80
+ const initialCursor = pos ? monacoPositionToCursor(pos) : { line: 0, col: 0 };
81
+ let ctx = (0, import_core.createInitialContext)(initialCursor, {
82
+ indentStyle,
83
+ indentWidth
84
+ });
85
+ updateCursorStyle(ctx.mode);
86
+ let isComposing = false;
87
+ const decorationCollection = editor.createDecorationsCollection();
88
+ function updateCursorStyle(mode) {
89
+ const cursorStyle = mode === "insert" ? 1 : 2;
90
+ editor.updateOptions({ cursorStyle });
91
+ }
92
+ function syncContentToEditor() {
93
+ const content = buffer.getContent();
94
+ if (content !== editor.getValue()) {
95
+ editor.setValue(content);
96
+ }
97
+ }
98
+ function syncCursorToEditor(cursor) {
99
+ editor.setPosition(cursorToMonacoPosition(cursor));
100
+ }
101
+ function updateVisualDecorations() {
102
+ if (ctx.mode !== "visual" && ctx.mode !== "visual-line" && ctx.mode !== "visual-block") {
103
+ decorationCollection.clear();
104
+ return;
105
+ }
106
+ const anchor = ctx.visualAnchor ?? ctx.cursor;
107
+ const before = anchor.line < ctx.cursor.line || anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col;
108
+ const start = before ? anchor : ctx.cursor;
109
+ const end = before ? ctx.cursor : anchor;
110
+ if (ctx.mode === "visual-line") {
111
+ decorationCollection.set([
112
+ {
113
+ range: {
114
+ startLineNumber: start.line + 1,
115
+ startColumn: 1,
116
+ endLineNumber: end.line + 1,
117
+ endColumn: (buffer.getLineLength(end.line) || 0) + 2
118
+ },
119
+ options: { className: "vimee-visual-selection", isWholeLine: true }
120
+ }
121
+ ]);
122
+ } else {
123
+ decorationCollection.set([
124
+ {
125
+ range: {
126
+ startLineNumber: start.line + 1,
127
+ startColumn: start.col + 1,
128
+ endLineNumber: end.line + 1,
129
+ endColumn: end.col + 2
130
+ // +2: Monaco end is exclusive & col is 0-based
131
+ },
132
+ options: { className: "vimee-visual-selection" }
133
+ }
134
+ ]);
135
+ }
136
+ }
137
+ function processActions(actions, newCtx, key) {
138
+ for (const action of actions) {
139
+ onAction?.(action, key);
140
+ switch (action.type) {
141
+ case "content-change":
142
+ syncContentToEditor();
143
+ onChange?.(action.content);
144
+ break;
145
+ case "mode-change":
146
+ updateCursorStyle(action.mode);
147
+ onModeChange?.(action.mode);
148
+ break;
149
+ case "yank":
150
+ onYank?.(action.text);
151
+ break;
152
+ case "save":
153
+ onSave?.(action.content);
154
+ break;
155
+ case "set-option":
156
+ case "status-message":
157
+ case "scroll":
158
+ case "noop":
159
+ break;
160
+ }
161
+ }
162
+ syncCursorToEditor(newCtx.cursor);
163
+ revealLine(editor, newCtx.cursor.line);
164
+ updateVisualDecorations();
165
+ }
166
+ function syncViewport() {
167
+ const topLine = getTopLine(editor);
168
+ const height = getVisibleLines(editor);
169
+ ctx = {
170
+ ...ctx,
171
+ viewportTopLine: topLine,
172
+ viewportHeight: height
173
+ };
174
+ }
175
+ function shouldPreventDefault(e) {
176
+ const mode = ctx.mode;
177
+ if (mode !== "insert") {
178
+ if (e.ctrlKey && (e.key === "c" || e.key === "a")) return false;
179
+ if (e.key === "Shift" || e.key === "Control" || e.key === "Alt" || e.key === "Meta") {
180
+ return false;
181
+ }
182
+ return true;
183
+ }
184
+ if (e.key === "Escape") return true;
185
+ if (e.key === "Tab") return true;
186
+ if (e.key === "Backspace") return true;
187
+ if (e.key === "Enter") return true;
188
+ if (e.ctrlKey) {
189
+ const ctrlKeys = ["r", "b", "f", "d", "u", "v", "w"];
190
+ if (ctrlKeys.includes(e.key)) return true;
191
+ }
192
+ return true;
193
+ }
194
+ function handleScroll(direction, amount) {
195
+ const visibleLines = getVisibleLines(editor);
196
+ const scrollLines = Math.max(1, Math.floor(visibleLines * amount));
197
+ const newLine = direction === "up" ? Math.max(0, ctx.cursor.line - scrollLines) : Math.min(buffer.getLineCount() - 1, ctx.cursor.line + scrollLines);
198
+ const maxCol = Math.max(0, (buffer.getLineLength(newLine) || 1) - 1);
199
+ const newCursor = {
200
+ line: newLine,
201
+ col: Math.min(ctx.cursor.col, maxCol)
202
+ };
203
+ ctx = { ...ctx, cursor: newCursor };
204
+ syncCursorToEditor(newCursor);
205
+ revealLine(editor, newLine);
206
+ }
207
+ function onKeyDown(e) {
208
+ if (isComposing) return;
209
+ const browserEvent = e.browserEvent;
210
+ syncViewport();
211
+ if (browserEvent.ctrlKey) {
212
+ const scrollKeys = {
213
+ b: { direction: "up", amount: 1 },
214
+ f: { direction: "down", amount: 1 },
215
+ u: { direction: "up", amount: 0.5 },
216
+ d: { direction: "down", amount: 0.5 }
217
+ };
218
+ const scroll = scrollKeys[browserEvent.key];
219
+ if (scroll) {
220
+ e.preventDefault();
221
+ e.stopPropagation();
222
+ handleScroll(scroll.direction, scroll.amount);
223
+ return;
224
+ }
225
+ }
226
+ if (shouldPreventDefault(browserEvent)) {
227
+ e.preventDefault();
228
+ e.stopPropagation();
229
+ }
230
+ const { newCtx, actions } = (0, import_core.processKeystroke)(
231
+ browserEvent.key,
232
+ ctx,
233
+ buffer,
234
+ browserEvent.ctrlKey,
235
+ readOnly
236
+ );
237
+ ctx = newCtx;
238
+ processActions(actions, newCtx, browserEvent.key);
239
+ }
240
+ const disposables = [
241
+ editor.onKeyDown(onKeyDown),
242
+ editor.onDidCompositionStart(() => {
243
+ isComposing = true;
244
+ }),
245
+ editor.onDidCompositionEnd(() => {
246
+ isComposing = false;
247
+ })
248
+ ];
249
+ syncViewport();
250
+ return {
251
+ getMode: () => ctx.mode,
252
+ getCursor: () => ({ ...ctx.cursor }),
253
+ getContent: () => buffer.getContent(),
254
+ destroy: () => {
255
+ for (const d of disposables) {
256
+ d.dispose();
257
+ }
258
+ decorationCollection.clear();
259
+ editor.updateOptions({ cursorStyle: 1 });
260
+ }
261
+ };
262
+ }
263
+ // Annotate the CommonJS export names for ESM import in node:
264
+ 0 && (module.exports = {
265
+ attach,
266
+ cursorToMonacoPosition,
267
+ getTopLine,
268
+ getVisibleLines,
269
+ monacoPositionToCursor,
270
+ revealLine
271
+ });
272
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/attach.ts","../src/cursor.ts","../src/viewport.ts"],"sourcesContent":["/**\n * @vimee/plugin-monaco\n *\n * Attach vim editing to any Monaco Editor instance.\n * Framework-agnostic — works with vanilla JS, React, or any Monaco wrapper.\n *\n * @example\n * ```ts\n * import { attach } from '@vimee/plugin-monaco'\n *\n * const vim = attach(monacoEditor, {\n * onChange: (value) => console.log(value),\n * onModeChange: (mode) => console.log(mode),\n * })\n *\n * vim.destroy()\n * ```\n */\n\n// Main function\nexport { attach } from \"./attach\";\n\n// Types\nexport type { AttachOptions, VimMonaco, MonacoEditor } from \"./types\";\nexport type {\n IDisposable,\n IPosition,\n IRange,\n IKeyboardEvent,\n ITextModel,\n IModelDeltaDecoration,\n IModelDecorationOptions,\n IEditorDecorationsCollection,\n} from \"./types\";\n\n// Cursor utilities (for advanced usage)\nexport { cursorToMonacoPosition, monacoPositionToCursor } from \"./cursor\";\n\n// Viewport utilities (for advanced usage)\nexport { getTopLine, getVisibleLines, revealLine } from \"./viewport\";\n\n// Re-export commonly used core types for convenience\nexport type { VimMode, VimAction, CursorPosition } from \"@vimee/core\";\n","/**\n * attach.ts\n *\n * Core implementation of the plugin-monaco package.\n * Attaches vim keybindings to an existing Monaco Editor instance.\n */\n\nimport type { VimContext, VimAction, CursorPosition } from \"@vimee/core\";\nimport { TextBuffer, createInitialContext, processKeystroke } from \"@vimee/core\";\nimport type { AttachOptions, VimMonaco, MonacoEditor, IKeyboardEvent } from \"./types\";\nimport { cursorToMonacoPosition, monacoPositionToCursor } from \"./cursor\";\nimport { getTopLine, getVisibleLines, revealLine } from \"./viewport\";\n\n/**\n * Attach vim editing to a Monaco Editor instance.\n *\n * @example\n * ```ts\n * const vim = attach(monacoEditor, {\n * onChange: (value) => console.log(value),\n * onModeChange: (mode) => console.log(mode),\n * });\n *\n * // Later...\n * vim.destroy();\n * ```\n */\nexport function attach(editor: MonacoEditor, options: AttachOptions = {}): VimMonaco {\n const {\n readOnly = false,\n onChange,\n onModeChange,\n onYank,\n onSave,\n onAction,\n indentStyle,\n indentWidth,\n } = options;\n\n // --- Initialize vim engine ---\n const buffer = new TextBuffer(editor.getValue());\n const pos = editor.getPosition();\n const initialCursor: CursorPosition = pos ? monacoPositionToCursor(pos) : { line: 0, col: 0 };\n let ctx: VimContext = createInitialContext(initialCursor, {\n indentStyle,\n indentWidth,\n });\n\n // --- Set initial cursor style (block for normal mode) ---\n updateCursorStyle(ctx.mode);\n\n // --- Track composing state (IME input) ---\n let isComposing = false;\n\n // --- Visual mode decorations ---\n const decorationCollection = editor.createDecorationsCollection();\n\n // --- Update Monaco cursor style based on vim mode ---\n function updateCursorStyle(mode: string): void {\n // Monaco CursorStyle: Line = 1, Block = 2, Underline = 3\n const cursorStyle = mode === \"insert\" ? 1 : 2;\n editor.updateOptions({ cursorStyle });\n }\n\n // --- Sync vimee buffer content to Monaco editor ---\n function syncContentToEditor(): void {\n const content = buffer.getContent();\n if (content !== editor.getValue()) {\n editor.setValue(content);\n }\n }\n\n // --- Sync cursor position to Monaco editor ---\n function syncCursorToEditor(cursor: CursorPosition): void {\n editor.setPosition(cursorToMonacoPosition(cursor));\n }\n\n // --- Update visual mode selection decorations ---\n function updateVisualDecorations(): void {\n if (ctx.mode !== \"visual\" && ctx.mode !== \"visual-line\" && ctx.mode !== \"visual-block\") {\n decorationCollection.clear();\n return;\n }\n\n const anchor = ctx.visualAnchor ?? ctx.cursor;\n const before =\n anchor.line < ctx.cursor.line ||\n (anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col);\n const start = before ? anchor : ctx.cursor;\n const end = before ? ctx.cursor : anchor;\n\n if (ctx.mode === \"visual-line\") {\n decorationCollection.set([\n {\n range: {\n startLineNumber: start.line + 1,\n startColumn: 1,\n endLineNumber: end.line + 1,\n endColumn: (buffer.getLineLength(end.line) || 0) + 2,\n },\n options: { className: \"vimee-visual-selection\", isWholeLine: true },\n },\n ]);\n } else {\n decorationCollection.set([\n {\n range: {\n startLineNumber: start.line + 1,\n startColumn: start.col + 1,\n endLineNumber: end.line + 1,\n endColumn: end.col + 2, // +2: Monaco end is exclusive & col is 0-based\n },\n options: { className: \"vimee-visual-selection\" },\n },\n ]);\n }\n }\n\n // --- Process vim actions and sync state ---\n function processActions(actions: VimAction[], newCtx: VimContext, key: string): void {\n for (const action of actions) {\n onAction?.(action, key);\n\n switch (action.type) {\n case \"content-change\":\n syncContentToEditor();\n onChange?.(action.content);\n break;\n\n case \"mode-change\":\n updateCursorStyle(action.mode);\n onModeChange?.(action.mode);\n break;\n\n case \"yank\":\n onYank?.(action.text);\n break;\n\n case \"save\":\n onSave?.(action.content);\n break;\n\n case \"set-option\":\n case \"status-message\":\n case \"scroll\":\n case \"noop\":\n break;\n }\n }\n\n // Always sync cursor and decorations from context\n syncCursorToEditor(newCtx.cursor);\n revealLine(editor, newCtx.cursor.line);\n updateVisualDecorations();\n }\n\n // --- Update viewport info on the VimContext ---\n function syncViewport(): void {\n const topLine = getTopLine(editor);\n const height = getVisibleLines(editor);\n ctx = {\n ...ctx,\n viewportTopLine: topLine,\n viewportHeight: height,\n };\n }\n\n // --- Determine if default behavior should be prevented ---\n function shouldPreventDefault(e: KeyboardEvent): boolean {\n const mode = ctx.mode;\n\n // In normal/visual/command-line mode, prevent all printable keys\n if (mode !== \"insert\") {\n // Allow modifier-only keys and browser shortcuts like Ctrl-C (copy)\n if (e.ctrlKey && (e.key === \"c\" || e.key === \"a\")) return false;\n if (e.key === \"Shift\" || e.key === \"Control\" || e.key === \"Alt\" || e.key === \"Meta\") {\n return false;\n }\n return true;\n }\n\n // In insert mode, prevent special keys handled by vim engine\n if (e.key === \"Escape\") return true;\n if (e.key === \"Tab\") return true;\n if (e.key === \"Backspace\") return true;\n if (e.key === \"Enter\") return true;\n if (e.ctrlKey) {\n const ctrlKeys = [\"r\", \"b\", \"f\", \"d\", \"u\", \"v\", \"w\"];\n if (ctrlKeys.includes(e.key)) return true;\n }\n\n return true; // Prevent all — vim engine handles insert mode character input\n }\n\n // --- Scroll handler for Ctrl-U/D/B/F ---\n function handleScroll(direction: \"up\" | \"down\", amount: number): void {\n const visibleLines = getVisibleLines(editor);\n const scrollLines = Math.max(1, Math.floor(visibleLines * amount));\n const newLine =\n direction === \"up\"\n ? Math.max(0, ctx.cursor.line - scrollLines)\n : Math.min(buffer.getLineCount() - 1, ctx.cursor.line + scrollLines);\n\n const maxCol = Math.max(0, (buffer.getLineLength(newLine) || 1) - 1);\n const newCursor: CursorPosition = {\n line: newLine,\n col: Math.min(ctx.cursor.col, maxCol),\n };\n\n ctx = { ...ctx, cursor: newCursor };\n syncCursorToEditor(newCursor);\n revealLine(editor, newLine);\n }\n\n // --- Keyboard handler ---\n function onKeyDown(e: IKeyboardEvent): void {\n if (isComposing) return;\n\n const browserEvent = e.browserEvent;\n\n // Update viewport before processing (for H/M/L motions)\n syncViewport();\n\n // Handle Ctrl scroll keys at this level\n if (browserEvent.ctrlKey) {\n const scrollKeys: Record<string, { direction: \"up\" | \"down\"; amount: number }> = {\n b: { direction: \"up\", amount: 1.0 },\n f: { direction: \"down\", amount: 1.0 },\n u: { direction: \"up\", amount: 0.5 },\n d: { direction: \"down\", amount: 0.5 },\n };\n const scroll = scrollKeys[browserEvent.key];\n if (scroll) {\n e.preventDefault();\n e.stopPropagation();\n handleScroll(scroll.direction, scroll.amount);\n return;\n }\n }\n\n if (shouldPreventDefault(browserEvent)) {\n e.preventDefault();\n e.stopPropagation();\n }\n\n const { newCtx, actions } = processKeystroke(\n browserEvent.key,\n ctx,\n buffer,\n browserEvent.ctrlKey,\n readOnly,\n );\n\n ctx = newCtx;\n processActions(actions, newCtx, browserEvent.key);\n }\n\n // --- Attach event listeners ---\n const disposables = [\n editor.onKeyDown(onKeyDown),\n editor.onDidCompositionStart(() => {\n isComposing = true;\n }),\n editor.onDidCompositionEnd(() => {\n isComposing = false;\n }),\n ];\n\n // Initial viewport sync\n syncViewport();\n\n // --- Return the VimMonaco handle ---\n return {\n getMode: () => ctx.mode,\n getCursor: () => ({ ...ctx.cursor }),\n getContent: () => buffer.getContent(),\n destroy: () => {\n for (const d of disposables) {\n d.dispose();\n }\n decorationCollection.clear();\n // Reset cursor style to line (default)\n editor.updateOptions({ cursorStyle: 1 });\n },\n };\n}\n","/**\n * cursor.ts\n *\n * Utilities for converting between vimee's 0-based CursorPosition\n * and Monaco's 1-based IPosition.\n */\n\nimport type { CursorPosition } from \"@vimee/core\";\nimport type { IPosition } from \"./types\";\n\n/**\n * Convert a vimee 0-based CursorPosition to a Monaco 1-based IPosition.\n */\nexport function cursorToMonacoPosition(cursor: CursorPosition): IPosition {\n return {\n lineNumber: cursor.line + 1,\n column: cursor.col + 1,\n };\n}\n\n/**\n * Convert a Monaco 1-based IPosition to a vimee 0-based CursorPosition.\n */\nexport function monacoPositionToCursor(position: IPosition): CursorPosition {\n return {\n line: position.lineNumber - 1,\n col: position.column - 1,\n };\n}\n","/**\n * viewport.ts\n *\n * Utilities for computing viewport information from a Monaco Editor.\n * Handles viewport tracking for H/M/L motions and\n * Ctrl-U/D/B/F page scrolling.\n */\n\nimport type { MonacoEditor } from \"./types\";\n\n/**\n * Get the first visible line (0-based) from the Monaco editor.\n */\nexport function getTopLine(editor: MonacoEditor): number {\n const ranges = editor.getVisibleRanges();\n if (ranges.length === 0) return 0;\n return ranges[0].startLineNumber - 1; // Convert to 0-based\n}\n\n/**\n * Get the number of visible lines in the Monaco editor viewport.\n */\nexport function getVisibleLines(editor: MonacoEditor): number {\n const ranges = editor.getVisibleRanges();\n if (ranges.length === 0) return 20; // Fallback\n const first = ranges[0];\n const last = ranges[ranges.length - 1];\n return last.endLineNumber - first.startLineNumber + 1;\n}\n\n/**\n * Scroll the Monaco editor to reveal a specific line (0-based).\n */\nexport function revealLine(editor: MonacoEditor, line: number): void {\n editor.revealLine(line + 1); // Convert to 1-based\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQA,kBAAmE;;;ACK5D,SAAS,uBAAuB,QAAmC;AACxE,SAAO;AAAA,IACL,YAAY,OAAO,OAAO;AAAA,IAC1B,QAAQ,OAAO,MAAM;AAAA,EACvB;AACF;AAKO,SAAS,uBAAuB,UAAqC;AAC1E,SAAO;AAAA,IACL,MAAM,SAAS,aAAa;AAAA,IAC5B,KAAK,SAAS,SAAS;AAAA,EACzB;AACF;;;ACfO,SAAS,WAAW,QAA8B;AACvD,QAAM,SAAS,OAAO,iBAAiB;AACvC,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,SAAO,OAAO,CAAC,EAAE,kBAAkB;AACrC;AAKO,SAAS,gBAAgB,QAA8B;AAC5D,QAAM,SAAS,OAAO,iBAAiB;AACvC,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,QAAQ,OAAO,CAAC;AACtB,QAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,SAAO,KAAK,gBAAgB,MAAM,kBAAkB;AACtD;AAKO,SAAS,WAAW,QAAsB,MAAoB;AACnE,SAAO,WAAW,OAAO,CAAC;AAC5B;;;AFRO,SAAS,OAAO,QAAsB,UAAyB,CAAC,GAAc;AACnF,QAAM;AAAA,IACJ,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AAGJ,QAAM,SAAS,IAAI,uBAAW,OAAO,SAAS,CAAC;AAC/C,QAAM,MAAM,OAAO,YAAY;AAC/B,QAAM,gBAAgC,MAAM,uBAAuB,GAAG,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE;AAC5F,MAAI,UAAkB,kCAAqB,eAAe;AAAA,IACxD;AAAA,IACA;AAAA,EACF,CAAC;AAGD,oBAAkB,IAAI,IAAI;AAG1B,MAAI,cAAc;AAGlB,QAAM,uBAAuB,OAAO,4BAA4B;AAGhE,WAAS,kBAAkB,MAAoB;AAE7C,UAAM,cAAc,SAAS,WAAW,IAAI;AAC5C,WAAO,cAAc,EAAE,YAAY,CAAC;AAAA,EACtC;AAGA,WAAS,sBAA4B;AACnC,UAAM,UAAU,OAAO,WAAW;AAClC,QAAI,YAAY,OAAO,SAAS,GAAG;AACjC,aAAO,SAAS,OAAO;AAAA,IACzB;AAAA,EACF;AAGA,WAAS,mBAAmB,QAA8B;AACxD,WAAO,YAAY,uBAAuB,MAAM,CAAC;AAAA,EACnD;AAGA,WAAS,0BAAgC;AACvC,QAAI,IAAI,SAAS,YAAY,IAAI,SAAS,iBAAiB,IAAI,SAAS,gBAAgB;AACtF,2BAAqB,MAAM;AAC3B;AAAA,IACF;AAEA,UAAM,SAAS,IAAI,gBAAgB,IAAI;AACvC,UAAM,SACJ,OAAO,OAAO,IAAI,OAAO,QACxB,OAAO,SAAS,IAAI,OAAO,QAAQ,OAAO,OAAO,IAAI,OAAO;AAC/D,UAAM,QAAQ,SAAS,SAAS,IAAI;AACpC,UAAM,MAAM,SAAS,IAAI,SAAS;AAElC,QAAI,IAAI,SAAS,eAAe;AAC9B,2BAAqB,IAAI;AAAA,QACvB;AAAA,UACE,OAAO;AAAA,YACL,iBAAiB,MAAM,OAAO;AAAA,YAC9B,aAAa;AAAA,YACb,eAAe,IAAI,OAAO;AAAA,YAC1B,YAAY,OAAO,cAAc,IAAI,IAAI,KAAK,KAAK;AAAA,UACrD;AAAA,UACA,SAAS,EAAE,WAAW,0BAA0B,aAAa,KAAK;AAAA,QACpE;AAAA,MACF,CAAC;AAAA,IACH,OAAO;AACL,2BAAqB,IAAI;AAAA,QACvB;AAAA,UACE,OAAO;AAAA,YACL,iBAAiB,MAAM,OAAO;AAAA,YAC9B,aAAa,MAAM,MAAM;AAAA,YACzB,eAAe,IAAI,OAAO;AAAA,YAC1B,WAAW,IAAI,MAAM;AAAA;AAAA,UACvB;AAAA,UACA,SAAS,EAAE,WAAW,yBAAyB;AAAA,QACjD;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAGA,WAAS,eAAe,SAAsB,QAAoB,KAAmB;AACnF,eAAW,UAAU,SAAS;AAC5B,iBAAW,QAAQ,GAAG;AAEtB,cAAQ,OAAO,MAAM;AAAA,QACnB,KAAK;AACH,8BAAoB;AACpB,qBAAW,OAAO,OAAO;AACzB;AAAA,QAEF,KAAK;AACH,4BAAkB,OAAO,IAAI;AAC7B,yBAAe,OAAO,IAAI;AAC1B;AAAA,QAEF,KAAK;AACH,mBAAS,OAAO,IAAI;AACpB;AAAA,QAEF,KAAK;AACH,mBAAS,OAAO,OAAO;AACvB;AAAA,QAEF,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AACH;AAAA,MACJ;AAAA,IACF;AAGA,uBAAmB,OAAO,MAAM;AAChC,eAAW,QAAQ,OAAO,OAAO,IAAI;AACrC,4BAAwB;AAAA,EAC1B;AAGA,WAAS,eAAqB;AAC5B,UAAM,UAAU,WAAW,MAAM;AACjC,UAAM,SAAS,gBAAgB,MAAM;AACrC,UAAM;AAAA,MACJ,GAAG;AAAA,MACH,iBAAiB;AAAA,MACjB,gBAAgB;AAAA,IAClB;AAAA,EACF;AAGA,WAAS,qBAAqB,GAA2B;AACvD,UAAM,OAAO,IAAI;AAGjB,QAAI,SAAS,UAAU;AAErB,UAAI,EAAE,YAAY,EAAE,QAAQ,OAAO,EAAE,QAAQ,KAAM,QAAO;AAC1D,UAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,aAAa,EAAE,QAAQ,SAAS,EAAE,QAAQ,QAAQ;AACnF,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAGA,QAAI,EAAE,QAAQ,SAAU,QAAO;AAC/B,QAAI,EAAE,QAAQ,MAAO,QAAO;AAC5B,QAAI,EAAE,QAAQ,YAAa,QAAO;AAClC,QAAI,EAAE,QAAQ,QAAS,QAAO;AAC9B,QAAI,EAAE,SAAS;AACb,YAAM,WAAW,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AACnD,UAAI,SAAS,SAAS,EAAE,GAAG,EAAG,QAAO;AAAA,IACvC;AAEA,WAAO;AAAA,EACT;AAGA,WAAS,aAAa,WAA0B,QAAsB;AACpE,UAAM,eAAe,gBAAgB,MAAM;AAC3C,UAAM,cAAc,KAAK,IAAI,GAAG,KAAK,MAAM,eAAe,MAAM,CAAC;AACjE,UAAM,UACJ,cAAc,OACV,KAAK,IAAI,GAAG,IAAI,OAAO,OAAO,WAAW,IACzC,KAAK,IAAI,OAAO,aAAa,IAAI,GAAG,IAAI,OAAO,OAAO,WAAW;AAEvE,UAAM,SAAS,KAAK,IAAI,IAAI,OAAO,cAAc,OAAO,KAAK,KAAK,CAAC;AACnE,UAAM,YAA4B;AAAA,MAChC,MAAM;AAAA,MACN,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM;AAAA,IACtC;AAEA,UAAM,EAAE,GAAG,KAAK,QAAQ,UAAU;AAClC,uBAAmB,SAAS;AAC5B,eAAW,QAAQ,OAAO;AAAA,EAC5B;AAGA,WAAS,UAAU,GAAyB;AAC1C,QAAI,YAAa;AAEjB,UAAM,eAAe,EAAE;AAGvB,iBAAa;AAGb,QAAI,aAAa,SAAS;AACxB,YAAM,aAA2E;AAAA,QAC/E,GAAG,EAAE,WAAW,MAAM,QAAQ,EAAI;AAAA,QAClC,GAAG,EAAE,WAAW,QAAQ,QAAQ,EAAI;AAAA,QACpC,GAAG,EAAE,WAAW,MAAM,QAAQ,IAAI;AAAA,QAClC,GAAG,EAAE,WAAW,QAAQ,QAAQ,IAAI;AAAA,MACtC;AACA,YAAM,SAAS,WAAW,aAAa,GAAG;AAC1C,UAAI,QAAQ;AACV,UAAE,eAAe;AACjB,UAAE,gBAAgB;AAClB,qBAAa,OAAO,WAAW,OAAO,MAAM;AAC5C;AAAA,MACF;AAAA,IACF;AAEA,QAAI,qBAAqB,YAAY,GAAG;AACtC,QAAE,eAAe;AACjB,QAAE,gBAAgB;AAAA,IACpB;AAEA,UAAM,EAAE,QAAQ,QAAQ,QAAI;AAAA,MAC1B,aAAa;AAAA,MACb;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb;AAAA,IACF;AAEA,UAAM;AACN,mBAAe,SAAS,QAAQ,aAAa,GAAG;AAAA,EAClD;AAGA,QAAM,cAAc;AAAA,IAClB,OAAO,UAAU,SAAS;AAAA,IAC1B,OAAO,sBAAsB,MAAM;AACjC,oBAAc;AAAA,IAChB,CAAC;AAAA,IACD,OAAO,oBAAoB,MAAM;AAC/B,oBAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAGA,eAAa;AAGb,SAAO;AAAA,IACL,SAAS,MAAM,IAAI;AAAA,IACnB,WAAW,OAAO,EAAE,GAAG,IAAI,OAAO;AAAA,IAClC,YAAY,MAAM,OAAO,WAAW;AAAA,IACpC,SAAS,MAAM;AACb,iBAAW,KAAK,aAAa;AAC3B,UAAE,QAAQ;AAAA,MACZ;AACA,2BAAqB,MAAM;AAE3B,aAAO,cAAc,EAAE,aAAa,EAAE,CAAC;AAAA,IACzC;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,166 @@
1
+ import { VimMode, VimAction, CursorPosition } from '@vimee/core';
2
+ export { CursorPosition, VimAction, VimMode } from '@vimee/core';
3
+
4
+ /**
5
+ * types.ts
6
+ *
7
+ * Public types for @vimee/plugin-monaco.
8
+ */
9
+
10
+ /** Disposable handle returned by Monaco event subscriptions. */
11
+ interface IDisposable {
12
+ dispose(): void;
13
+ }
14
+ /** 1-based position in Monaco (lineNumber ≥ 1, column ≥ 1). */
15
+ interface IPosition {
16
+ readonly lineNumber: number;
17
+ readonly column: number;
18
+ }
19
+ /** 1-based range in Monaco. */
20
+ interface IRange {
21
+ readonly startLineNumber: number;
22
+ readonly startColumn: number;
23
+ readonly endLineNumber: number;
24
+ readonly endColumn: number;
25
+ }
26
+ /** Decoration options applied to a range. */
27
+ interface IModelDecorationOptions {
28
+ className?: string | null;
29
+ isWholeLine?: boolean;
30
+ }
31
+ /** A single decoration descriptor. */
32
+ interface IModelDeltaDecoration {
33
+ range: IRange;
34
+ options: IModelDecorationOptions;
35
+ }
36
+ /** Monaco keyboard event wrapper. */
37
+ interface IKeyboardEvent {
38
+ readonly browserEvent: KeyboardEvent;
39
+ preventDefault(): void;
40
+ stopPropagation(): void;
41
+ }
42
+ /** Minimal subset of Monaco's ITextModel. */
43
+ interface ITextModel {
44
+ getValue(): string;
45
+ setValue(value: string): void;
46
+ getLineContent(lineNumber: number): string;
47
+ getLineCount(): number;
48
+ getLineMaxColumn(lineNumber: number): number;
49
+ }
50
+ /** Decoration collection (Monaco ≥ 0.34). */
51
+ interface IEditorDecorationsCollection {
52
+ set(decorations: IModelDeltaDecoration[]): void;
53
+ clear(): void;
54
+ }
55
+ /**
56
+ * Minimal subset of `monaco.editor.IStandaloneCodeEditor`.
57
+ *
58
+ * Any object satisfying this interface can be passed to `attach()`.
59
+ */
60
+ interface MonacoEditor {
61
+ getValue(): string;
62
+ setValue(value: string): void;
63
+ getPosition(): IPosition | null;
64
+ setPosition(position: IPosition): void;
65
+ getModel(): ITextModel | null;
66
+ onKeyDown(listener: (e: IKeyboardEvent) => void): IDisposable;
67
+ onDidCompositionStart(listener: () => void): IDisposable;
68
+ onDidCompositionEnd(listener: () => void): IDisposable;
69
+ createDecorationsCollection(decorations?: IModelDeltaDecoration[]): IEditorDecorationsCollection;
70
+ getVisibleRanges(): IRange[];
71
+ revealLine(lineNumber: number): void;
72
+ updateOptions(options: Record<string, unknown>): void;
73
+ focus(): void;
74
+ }
75
+ /** Options passed to `attach()`. */
76
+ interface AttachOptions {
77
+ /** Read-only mode — vim motions work but no edits. */
78
+ readOnly?: boolean;
79
+ /** Called whenever the editor content changes via vim commands. */
80
+ onChange?: (value: string) => void;
81
+ /** Called whenever the vim mode changes. */
82
+ onModeChange?: (mode: VimMode) => void;
83
+ /** Called when text is yanked. */
84
+ onYank?: (text: string) => void;
85
+ /** Called when `:w` is executed. */
86
+ onSave?: (value: string) => void;
87
+ /** Called for every vim action (low-level). */
88
+ onAction?: (action: VimAction, key: string) => void;
89
+ /** Indent style: "space" or "tab" (default: "space"). */
90
+ indentStyle?: "space" | "tab";
91
+ /** Indent width (default: 2). */
92
+ indentWidth?: number;
93
+ }
94
+ /** The object returned by `attach()` — the handle to the vim-enabled editor. */
95
+ interface VimMonaco {
96
+ /** Current vim mode. */
97
+ getMode(): VimMode;
98
+ /** Current cursor position (0-based line/col). */
99
+ getCursor(): CursorPosition;
100
+ /** Current editor content (from the vim buffer). */
101
+ getContent(): string;
102
+ /** Detach all event listeners and restore the editor to its original state. */
103
+ destroy(): void;
104
+ }
105
+
106
+ /**
107
+ * attach.ts
108
+ *
109
+ * Core implementation of the plugin-monaco package.
110
+ * Attaches vim keybindings to an existing Monaco Editor instance.
111
+ */
112
+
113
+ /**
114
+ * Attach vim editing to a Monaco Editor instance.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * const vim = attach(monacoEditor, {
119
+ * onChange: (value) => console.log(value),
120
+ * onModeChange: (mode) => console.log(mode),
121
+ * });
122
+ *
123
+ * // Later...
124
+ * vim.destroy();
125
+ * ```
126
+ */
127
+ declare function attach(editor: MonacoEditor, options?: AttachOptions): VimMonaco;
128
+
129
+ /**
130
+ * cursor.ts
131
+ *
132
+ * Utilities for converting between vimee's 0-based CursorPosition
133
+ * and Monaco's 1-based IPosition.
134
+ */
135
+
136
+ /**
137
+ * Convert a vimee 0-based CursorPosition to a Monaco 1-based IPosition.
138
+ */
139
+ declare function cursorToMonacoPosition(cursor: CursorPosition): IPosition;
140
+ /**
141
+ * Convert a Monaco 1-based IPosition to a vimee 0-based CursorPosition.
142
+ */
143
+ declare function monacoPositionToCursor(position: IPosition): CursorPosition;
144
+
145
+ /**
146
+ * viewport.ts
147
+ *
148
+ * Utilities for computing viewport information from a Monaco Editor.
149
+ * Handles viewport tracking for H/M/L motions and
150
+ * Ctrl-U/D/B/F page scrolling.
151
+ */
152
+
153
+ /**
154
+ * Get the first visible line (0-based) from the Monaco editor.
155
+ */
156
+ declare function getTopLine(editor: MonacoEditor): number;
157
+ /**
158
+ * Get the number of visible lines in the Monaco editor viewport.
159
+ */
160
+ declare function getVisibleLines(editor: MonacoEditor): number;
161
+ /**
162
+ * Scroll the Monaco editor to reveal a specific line (0-based).
163
+ */
164
+ declare function revealLine(editor: MonacoEditor, line: number): void;
165
+
166
+ export { type AttachOptions, type IDisposable, type IEditorDecorationsCollection, type IKeyboardEvent, type IModelDecorationOptions, type IModelDeltaDecoration, type IPosition, type IRange, type ITextModel, type MonacoEditor, type VimMonaco, attach, cursorToMonacoPosition, getTopLine, getVisibleLines, monacoPositionToCursor, revealLine };
@@ -0,0 +1,166 @@
1
+ import { VimMode, VimAction, CursorPosition } from '@vimee/core';
2
+ export { CursorPosition, VimAction, VimMode } from '@vimee/core';
3
+
4
+ /**
5
+ * types.ts
6
+ *
7
+ * Public types for @vimee/plugin-monaco.
8
+ */
9
+
10
+ /** Disposable handle returned by Monaco event subscriptions. */
11
+ interface IDisposable {
12
+ dispose(): void;
13
+ }
14
+ /** 1-based position in Monaco (lineNumber ≥ 1, column ≥ 1). */
15
+ interface IPosition {
16
+ readonly lineNumber: number;
17
+ readonly column: number;
18
+ }
19
+ /** 1-based range in Monaco. */
20
+ interface IRange {
21
+ readonly startLineNumber: number;
22
+ readonly startColumn: number;
23
+ readonly endLineNumber: number;
24
+ readonly endColumn: number;
25
+ }
26
+ /** Decoration options applied to a range. */
27
+ interface IModelDecorationOptions {
28
+ className?: string | null;
29
+ isWholeLine?: boolean;
30
+ }
31
+ /** A single decoration descriptor. */
32
+ interface IModelDeltaDecoration {
33
+ range: IRange;
34
+ options: IModelDecorationOptions;
35
+ }
36
+ /** Monaco keyboard event wrapper. */
37
+ interface IKeyboardEvent {
38
+ readonly browserEvent: KeyboardEvent;
39
+ preventDefault(): void;
40
+ stopPropagation(): void;
41
+ }
42
+ /** Minimal subset of Monaco's ITextModel. */
43
+ interface ITextModel {
44
+ getValue(): string;
45
+ setValue(value: string): void;
46
+ getLineContent(lineNumber: number): string;
47
+ getLineCount(): number;
48
+ getLineMaxColumn(lineNumber: number): number;
49
+ }
50
+ /** Decoration collection (Monaco ≥ 0.34). */
51
+ interface IEditorDecorationsCollection {
52
+ set(decorations: IModelDeltaDecoration[]): void;
53
+ clear(): void;
54
+ }
55
+ /**
56
+ * Minimal subset of `monaco.editor.IStandaloneCodeEditor`.
57
+ *
58
+ * Any object satisfying this interface can be passed to `attach()`.
59
+ */
60
+ interface MonacoEditor {
61
+ getValue(): string;
62
+ setValue(value: string): void;
63
+ getPosition(): IPosition | null;
64
+ setPosition(position: IPosition): void;
65
+ getModel(): ITextModel | null;
66
+ onKeyDown(listener: (e: IKeyboardEvent) => void): IDisposable;
67
+ onDidCompositionStart(listener: () => void): IDisposable;
68
+ onDidCompositionEnd(listener: () => void): IDisposable;
69
+ createDecorationsCollection(decorations?: IModelDeltaDecoration[]): IEditorDecorationsCollection;
70
+ getVisibleRanges(): IRange[];
71
+ revealLine(lineNumber: number): void;
72
+ updateOptions(options: Record<string, unknown>): void;
73
+ focus(): void;
74
+ }
75
+ /** Options passed to `attach()`. */
76
+ interface AttachOptions {
77
+ /** Read-only mode — vim motions work but no edits. */
78
+ readOnly?: boolean;
79
+ /** Called whenever the editor content changes via vim commands. */
80
+ onChange?: (value: string) => void;
81
+ /** Called whenever the vim mode changes. */
82
+ onModeChange?: (mode: VimMode) => void;
83
+ /** Called when text is yanked. */
84
+ onYank?: (text: string) => void;
85
+ /** Called when `:w` is executed. */
86
+ onSave?: (value: string) => void;
87
+ /** Called for every vim action (low-level). */
88
+ onAction?: (action: VimAction, key: string) => void;
89
+ /** Indent style: "space" or "tab" (default: "space"). */
90
+ indentStyle?: "space" | "tab";
91
+ /** Indent width (default: 2). */
92
+ indentWidth?: number;
93
+ }
94
+ /** The object returned by `attach()` — the handle to the vim-enabled editor. */
95
+ interface VimMonaco {
96
+ /** Current vim mode. */
97
+ getMode(): VimMode;
98
+ /** Current cursor position (0-based line/col). */
99
+ getCursor(): CursorPosition;
100
+ /** Current editor content (from the vim buffer). */
101
+ getContent(): string;
102
+ /** Detach all event listeners and restore the editor to its original state. */
103
+ destroy(): void;
104
+ }
105
+
106
+ /**
107
+ * attach.ts
108
+ *
109
+ * Core implementation of the plugin-monaco package.
110
+ * Attaches vim keybindings to an existing Monaco Editor instance.
111
+ */
112
+
113
+ /**
114
+ * Attach vim editing to a Monaco Editor instance.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * const vim = attach(monacoEditor, {
119
+ * onChange: (value) => console.log(value),
120
+ * onModeChange: (mode) => console.log(mode),
121
+ * });
122
+ *
123
+ * // Later...
124
+ * vim.destroy();
125
+ * ```
126
+ */
127
+ declare function attach(editor: MonacoEditor, options?: AttachOptions): VimMonaco;
128
+
129
+ /**
130
+ * cursor.ts
131
+ *
132
+ * Utilities for converting between vimee's 0-based CursorPosition
133
+ * and Monaco's 1-based IPosition.
134
+ */
135
+
136
+ /**
137
+ * Convert a vimee 0-based CursorPosition to a Monaco 1-based IPosition.
138
+ */
139
+ declare function cursorToMonacoPosition(cursor: CursorPosition): IPosition;
140
+ /**
141
+ * Convert a Monaco 1-based IPosition to a vimee 0-based CursorPosition.
142
+ */
143
+ declare function monacoPositionToCursor(position: IPosition): CursorPosition;
144
+
145
+ /**
146
+ * viewport.ts
147
+ *
148
+ * Utilities for computing viewport information from a Monaco Editor.
149
+ * Handles viewport tracking for H/M/L motions and
150
+ * Ctrl-U/D/B/F page scrolling.
151
+ */
152
+
153
+ /**
154
+ * Get the first visible line (0-based) from the Monaco editor.
155
+ */
156
+ declare function getTopLine(editor: MonacoEditor): number;
157
+ /**
158
+ * Get the number of visible lines in the Monaco editor viewport.
159
+ */
160
+ declare function getVisibleLines(editor: MonacoEditor): number;
161
+ /**
162
+ * Scroll the Monaco editor to reveal a specific line (0-based).
163
+ */
164
+ declare function revealLine(editor: MonacoEditor, line: number): void;
165
+
166
+ export { type AttachOptions, type IDisposable, type IEditorDecorationsCollection, type IKeyboardEvent, type IModelDecorationOptions, type IModelDeltaDecoration, type IPosition, type IRange, type ITextModel, type MonacoEditor, type VimMonaco, attach, cursorToMonacoPosition, getTopLine, getVisibleLines, monacoPositionToCursor, revealLine };
package/dist/index.js ADDED
@@ -0,0 +1,240 @@
1
+ // src/attach.ts
2
+ import { TextBuffer, createInitialContext, processKeystroke } from "@vimee/core";
3
+
4
+ // src/cursor.ts
5
+ function cursorToMonacoPosition(cursor) {
6
+ return {
7
+ lineNumber: cursor.line + 1,
8
+ column: cursor.col + 1
9
+ };
10
+ }
11
+ function monacoPositionToCursor(position) {
12
+ return {
13
+ line: position.lineNumber - 1,
14
+ col: position.column - 1
15
+ };
16
+ }
17
+
18
+ // src/viewport.ts
19
+ function getTopLine(editor) {
20
+ const ranges = editor.getVisibleRanges();
21
+ if (ranges.length === 0) return 0;
22
+ return ranges[0].startLineNumber - 1;
23
+ }
24
+ function getVisibleLines(editor) {
25
+ const ranges = editor.getVisibleRanges();
26
+ if (ranges.length === 0) return 20;
27
+ const first = ranges[0];
28
+ const last = ranges[ranges.length - 1];
29
+ return last.endLineNumber - first.startLineNumber + 1;
30
+ }
31
+ function revealLine(editor, line) {
32
+ editor.revealLine(line + 1);
33
+ }
34
+
35
+ // src/attach.ts
36
+ function attach(editor, options = {}) {
37
+ const {
38
+ readOnly = false,
39
+ onChange,
40
+ onModeChange,
41
+ onYank,
42
+ onSave,
43
+ onAction,
44
+ indentStyle,
45
+ indentWidth
46
+ } = options;
47
+ const buffer = new TextBuffer(editor.getValue());
48
+ const pos = editor.getPosition();
49
+ const initialCursor = pos ? monacoPositionToCursor(pos) : { line: 0, col: 0 };
50
+ let ctx = createInitialContext(initialCursor, {
51
+ indentStyle,
52
+ indentWidth
53
+ });
54
+ updateCursorStyle(ctx.mode);
55
+ let isComposing = false;
56
+ const decorationCollection = editor.createDecorationsCollection();
57
+ function updateCursorStyle(mode) {
58
+ const cursorStyle = mode === "insert" ? 1 : 2;
59
+ editor.updateOptions({ cursorStyle });
60
+ }
61
+ function syncContentToEditor() {
62
+ const content = buffer.getContent();
63
+ if (content !== editor.getValue()) {
64
+ editor.setValue(content);
65
+ }
66
+ }
67
+ function syncCursorToEditor(cursor) {
68
+ editor.setPosition(cursorToMonacoPosition(cursor));
69
+ }
70
+ function updateVisualDecorations() {
71
+ if (ctx.mode !== "visual" && ctx.mode !== "visual-line" && ctx.mode !== "visual-block") {
72
+ decorationCollection.clear();
73
+ return;
74
+ }
75
+ const anchor = ctx.visualAnchor ?? ctx.cursor;
76
+ const before = anchor.line < ctx.cursor.line || anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col;
77
+ const start = before ? anchor : ctx.cursor;
78
+ const end = before ? ctx.cursor : anchor;
79
+ if (ctx.mode === "visual-line") {
80
+ decorationCollection.set([
81
+ {
82
+ range: {
83
+ startLineNumber: start.line + 1,
84
+ startColumn: 1,
85
+ endLineNumber: end.line + 1,
86
+ endColumn: (buffer.getLineLength(end.line) || 0) + 2
87
+ },
88
+ options: { className: "vimee-visual-selection", isWholeLine: true }
89
+ }
90
+ ]);
91
+ } else {
92
+ decorationCollection.set([
93
+ {
94
+ range: {
95
+ startLineNumber: start.line + 1,
96
+ startColumn: start.col + 1,
97
+ endLineNumber: end.line + 1,
98
+ endColumn: end.col + 2
99
+ // +2: Monaco end is exclusive & col is 0-based
100
+ },
101
+ options: { className: "vimee-visual-selection" }
102
+ }
103
+ ]);
104
+ }
105
+ }
106
+ function processActions(actions, newCtx, key) {
107
+ for (const action of actions) {
108
+ onAction?.(action, key);
109
+ switch (action.type) {
110
+ case "content-change":
111
+ syncContentToEditor();
112
+ onChange?.(action.content);
113
+ break;
114
+ case "mode-change":
115
+ updateCursorStyle(action.mode);
116
+ onModeChange?.(action.mode);
117
+ break;
118
+ case "yank":
119
+ onYank?.(action.text);
120
+ break;
121
+ case "save":
122
+ onSave?.(action.content);
123
+ break;
124
+ case "set-option":
125
+ case "status-message":
126
+ case "scroll":
127
+ case "noop":
128
+ break;
129
+ }
130
+ }
131
+ syncCursorToEditor(newCtx.cursor);
132
+ revealLine(editor, newCtx.cursor.line);
133
+ updateVisualDecorations();
134
+ }
135
+ function syncViewport() {
136
+ const topLine = getTopLine(editor);
137
+ const height = getVisibleLines(editor);
138
+ ctx = {
139
+ ...ctx,
140
+ viewportTopLine: topLine,
141
+ viewportHeight: height
142
+ };
143
+ }
144
+ function shouldPreventDefault(e) {
145
+ const mode = ctx.mode;
146
+ if (mode !== "insert") {
147
+ if (e.ctrlKey && (e.key === "c" || e.key === "a")) return false;
148
+ if (e.key === "Shift" || e.key === "Control" || e.key === "Alt" || e.key === "Meta") {
149
+ return false;
150
+ }
151
+ return true;
152
+ }
153
+ if (e.key === "Escape") return true;
154
+ if (e.key === "Tab") return true;
155
+ if (e.key === "Backspace") return true;
156
+ if (e.key === "Enter") return true;
157
+ if (e.ctrlKey) {
158
+ const ctrlKeys = ["r", "b", "f", "d", "u", "v", "w"];
159
+ if (ctrlKeys.includes(e.key)) return true;
160
+ }
161
+ return true;
162
+ }
163
+ function handleScroll(direction, amount) {
164
+ const visibleLines = getVisibleLines(editor);
165
+ const scrollLines = Math.max(1, Math.floor(visibleLines * amount));
166
+ const newLine = direction === "up" ? Math.max(0, ctx.cursor.line - scrollLines) : Math.min(buffer.getLineCount() - 1, ctx.cursor.line + scrollLines);
167
+ const maxCol = Math.max(0, (buffer.getLineLength(newLine) || 1) - 1);
168
+ const newCursor = {
169
+ line: newLine,
170
+ col: Math.min(ctx.cursor.col, maxCol)
171
+ };
172
+ ctx = { ...ctx, cursor: newCursor };
173
+ syncCursorToEditor(newCursor);
174
+ revealLine(editor, newLine);
175
+ }
176
+ function onKeyDown(e) {
177
+ if (isComposing) return;
178
+ const browserEvent = e.browserEvent;
179
+ syncViewport();
180
+ if (browserEvent.ctrlKey) {
181
+ const scrollKeys = {
182
+ b: { direction: "up", amount: 1 },
183
+ f: { direction: "down", amount: 1 },
184
+ u: { direction: "up", amount: 0.5 },
185
+ d: { direction: "down", amount: 0.5 }
186
+ };
187
+ const scroll = scrollKeys[browserEvent.key];
188
+ if (scroll) {
189
+ e.preventDefault();
190
+ e.stopPropagation();
191
+ handleScroll(scroll.direction, scroll.amount);
192
+ return;
193
+ }
194
+ }
195
+ if (shouldPreventDefault(browserEvent)) {
196
+ e.preventDefault();
197
+ e.stopPropagation();
198
+ }
199
+ const { newCtx, actions } = processKeystroke(
200
+ browserEvent.key,
201
+ ctx,
202
+ buffer,
203
+ browserEvent.ctrlKey,
204
+ readOnly
205
+ );
206
+ ctx = newCtx;
207
+ processActions(actions, newCtx, browserEvent.key);
208
+ }
209
+ const disposables = [
210
+ editor.onKeyDown(onKeyDown),
211
+ editor.onDidCompositionStart(() => {
212
+ isComposing = true;
213
+ }),
214
+ editor.onDidCompositionEnd(() => {
215
+ isComposing = false;
216
+ })
217
+ ];
218
+ syncViewport();
219
+ return {
220
+ getMode: () => ctx.mode,
221
+ getCursor: () => ({ ...ctx.cursor }),
222
+ getContent: () => buffer.getContent(),
223
+ destroy: () => {
224
+ for (const d of disposables) {
225
+ d.dispose();
226
+ }
227
+ decorationCollection.clear();
228
+ editor.updateOptions({ cursorStyle: 1 });
229
+ }
230
+ };
231
+ }
232
+ export {
233
+ attach,
234
+ cursorToMonacoPosition,
235
+ getTopLine,
236
+ getVisibleLines,
237
+ monacoPositionToCursor,
238
+ revealLine
239
+ };
240
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/attach.ts","../src/cursor.ts","../src/viewport.ts"],"sourcesContent":["/**\n * attach.ts\n *\n * Core implementation of the plugin-monaco package.\n * Attaches vim keybindings to an existing Monaco Editor instance.\n */\n\nimport type { VimContext, VimAction, CursorPosition } from \"@vimee/core\";\nimport { TextBuffer, createInitialContext, processKeystroke } from \"@vimee/core\";\nimport type { AttachOptions, VimMonaco, MonacoEditor, IKeyboardEvent } from \"./types\";\nimport { cursorToMonacoPosition, monacoPositionToCursor } from \"./cursor\";\nimport { getTopLine, getVisibleLines, revealLine } from \"./viewport\";\n\n/**\n * Attach vim editing to a Monaco Editor instance.\n *\n * @example\n * ```ts\n * const vim = attach(monacoEditor, {\n * onChange: (value) => console.log(value),\n * onModeChange: (mode) => console.log(mode),\n * });\n *\n * // Later...\n * vim.destroy();\n * ```\n */\nexport function attach(editor: MonacoEditor, options: AttachOptions = {}): VimMonaco {\n const {\n readOnly = false,\n onChange,\n onModeChange,\n onYank,\n onSave,\n onAction,\n indentStyle,\n indentWidth,\n } = options;\n\n // --- Initialize vim engine ---\n const buffer = new TextBuffer(editor.getValue());\n const pos = editor.getPosition();\n const initialCursor: CursorPosition = pos ? monacoPositionToCursor(pos) : { line: 0, col: 0 };\n let ctx: VimContext = createInitialContext(initialCursor, {\n indentStyle,\n indentWidth,\n });\n\n // --- Set initial cursor style (block for normal mode) ---\n updateCursorStyle(ctx.mode);\n\n // --- Track composing state (IME input) ---\n let isComposing = false;\n\n // --- Visual mode decorations ---\n const decorationCollection = editor.createDecorationsCollection();\n\n // --- Update Monaco cursor style based on vim mode ---\n function updateCursorStyle(mode: string): void {\n // Monaco CursorStyle: Line = 1, Block = 2, Underline = 3\n const cursorStyle = mode === \"insert\" ? 1 : 2;\n editor.updateOptions({ cursorStyle });\n }\n\n // --- Sync vimee buffer content to Monaco editor ---\n function syncContentToEditor(): void {\n const content = buffer.getContent();\n if (content !== editor.getValue()) {\n editor.setValue(content);\n }\n }\n\n // --- Sync cursor position to Monaco editor ---\n function syncCursorToEditor(cursor: CursorPosition): void {\n editor.setPosition(cursorToMonacoPosition(cursor));\n }\n\n // --- Update visual mode selection decorations ---\n function updateVisualDecorations(): void {\n if (ctx.mode !== \"visual\" && ctx.mode !== \"visual-line\" && ctx.mode !== \"visual-block\") {\n decorationCollection.clear();\n return;\n }\n\n const anchor = ctx.visualAnchor ?? ctx.cursor;\n const before =\n anchor.line < ctx.cursor.line ||\n (anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col);\n const start = before ? anchor : ctx.cursor;\n const end = before ? ctx.cursor : anchor;\n\n if (ctx.mode === \"visual-line\") {\n decorationCollection.set([\n {\n range: {\n startLineNumber: start.line + 1,\n startColumn: 1,\n endLineNumber: end.line + 1,\n endColumn: (buffer.getLineLength(end.line) || 0) + 2,\n },\n options: { className: \"vimee-visual-selection\", isWholeLine: true },\n },\n ]);\n } else {\n decorationCollection.set([\n {\n range: {\n startLineNumber: start.line + 1,\n startColumn: start.col + 1,\n endLineNumber: end.line + 1,\n endColumn: end.col + 2, // +2: Monaco end is exclusive & col is 0-based\n },\n options: { className: \"vimee-visual-selection\" },\n },\n ]);\n }\n }\n\n // --- Process vim actions and sync state ---\n function processActions(actions: VimAction[], newCtx: VimContext, key: string): void {\n for (const action of actions) {\n onAction?.(action, key);\n\n switch (action.type) {\n case \"content-change\":\n syncContentToEditor();\n onChange?.(action.content);\n break;\n\n case \"mode-change\":\n updateCursorStyle(action.mode);\n onModeChange?.(action.mode);\n break;\n\n case \"yank\":\n onYank?.(action.text);\n break;\n\n case \"save\":\n onSave?.(action.content);\n break;\n\n case \"set-option\":\n case \"status-message\":\n case \"scroll\":\n case \"noop\":\n break;\n }\n }\n\n // Always sync cursor and decorations from context\n syncCursorToEditor(newCtx.cursor);\n revealLine(editor, newCtx.cursor.line);\n updateVisualDecorations();\n }\n\n // --- Update viewport info on the VimContext ---\n function syncViewport(): void {\n const topLine = getTopLine(editor);\n const height = getVisibleLines(editor);\n ctx = {\n ...ctx,\n viewportTopLine: topLine,\n viewportHeight: height,\n };\n }\n\n // --- Determine if default behavior should be prevented ---\n function shouldPreventDefault(e: KeyboardEvent): boolean {\n const mode = ctx.mode;\n\n // In normal/visual/command-line mode, prevent all printable keys\n if (mode !== \"insert\") {\n // Allow modifier-only keys and browser shortcuts like Ctrl-C (copy)\n if (e.ctrlKey && (e.key === \"c\" || e.key === \"a\")) return false;\n if (e.key === \"Shift\" || e.key === \"Control\" || e.key === \"Alt\" || e.key === \"Meta\") {\n return false;\n }\n return true;\n }\n\n // In insert mode, prevent special keys handled by vim engine\n if (e.key === \"Escape\") return true;\n if (e.key === \"Tab\") return true;\n if (e.key === \"Backspace\") return true;\n if (e.key === \"Enter\") return true;\n if (e.ctrlKey) {\n const ctrlKeys = [\"r\", \"b\", \"f\", \"d\", \"u\", \"v\", \"w\"];\n if (ctrlKeys.includes(e.key)) return true;\n }\n\n return true; // Prevent all — vim engine handles insert mode character input\n }\n\n // --- Scroll handler for Ctrl-U/D/B/F ---\n function handleScroll(direction: \"up\" | \"down\", amount: number): void {\n const visibleLines = getVisibleLines(editor);\n const scrollLines = Math.max(1, Math.floor(visibleLines * amount));\n const newLine =\n direction === \"up\"\n ? Math.max(0, ctx.cursor.line - scrollLines)\n : Math.min(buffer.getLineCount() - 1, ctx.cursor.line + scrollLines);\n\n const maxCol = Math.max(0, (buffer.getLineLength(newLine) || 1) - 1);\n const newCursor: CursorPosition = {\n line: newLine,\n col: Math.min(ctx.cursor.col, maxCol),\n };\n\n ctx = { ...ctx, cursor: newCursor };\n syncCursorToEditor(newCursor);\n revealLine(editor, newLine);\n }\n\n // --- Keyboard handler ---\n function onKeyDown(e: IKeyboardEvent): void {\n if (isComposing) return;\n\n const browserEvent = e.browserEvent;\n\n // Update viewport before processing (for H/M/L motions)\n syncViewport();\n\n // Handle Ctrl scroll keys at this level\n if (browserEvent.ctrlKey) {\n const scrollKeys: Record<string, { direction: \"up\" | \"down\"; amount: number }> = {\n b: { direction: \"up\", amount: 1.0 },\n f: { direction: \"down\", amount: 1.0 },\n u: { direction: \"up\", amount: 0.5 },\n d: { direction: \"down\", amount: 0.5 },\n };\n const scroll = scrollKeys[browserEvent.key];\n if (scroll) {\n e.preventDefault();\n e.stopPropagation();\n handleScroll(scroll.direction, scroll.amount);\n return;\n }\n }\n\n if (shouldPreventDefault(browserEvent)) {\n e.preventDefault();\n e.stopPropagation();\n }\n\n const { newCtx, actions } = processKeystroke(\n browserEvent.key,\n ctx,\n buffer,\n browserEvent.ctrlKey,\n readOnly,\n );\n\n ctx = newCtx;\n processActions(actions, newCtx, browserEvent.key);\n }\n\n // --- Attach event listeners ---\n const disposables = [\n editor.onKeyDown(onKeyDown),\n editor.onDidCompositionStart(() => {\n isComposing = true;\n }),\n editor.onDidCompositionEnd(() => {\n isComposing = false;\n }),\n ];\n\n // Initial viewport sync\n syncViewport();\n\n // --- Return the VimMonaco handle ---\n return {\n getMode: () => ctx.mode,\n getCursor: () => ({ ...ctx.cursor }),\n getContent: () => buffer.getContent(),\n destroy: () => {\n for (const d of disposables) {\n d.dispose();\n }\n decorationCollection.clear();\n // Reset cursor style to line (default)\n editor.updateOptions({ cursorStyle: 1 });\n },\n };\n}\n","/**\n * cursor.ts\n *\n * Utilities for converting between vimee's 0-based CursorPosition\n * and Monaco's 1-based IPosition.\n */\n\nimport type { CursorPosition } from \"@vimee/core\";\nimport type { IPosition } from \"./types\";\n\n/**\n * Convert a vimee 0-based CursorPosition to a Monaco 1-based IPosition.\n */\nexport function cursorToMonacoPosition(cursor: CursorPosition): IPosition {\n return {\n lineNumber: cursor.line + 1,\n column: cursor.col + 1,\n };\n}\n\n/**\n * Convert a Monaco 1-based IPosition to a vimee 0-based CursorPosition.\n */\nexport function monacoPositionToCursor(position: IPosition): CursorPosition {\n return {\n line: position.lineNumber - 1,\n col: position.column - 1,\n };\n}\n","/**\n * viewport.ts\n *\n * Utilities for computing viewport information from a Monaco Editor.\n * Handles viewport tracking for H/M/L motions and\n * Ctrl-U/D/B/F page scrolling.\n */\n\nimport type { MonacoEditor } from \"./types\";\n\n/**\n * Get the first visible line (0-based) from the Monaco editor.\n */\nexport function getTopLine(editor: MonacoEditor): number {\n const ranges = editor.getVisibleRanges();\n if (ranges.length === 0) return 0;\n return ranges[0].startLineNumber - 1; // Convert to 0-based\n}\n\n/**\n * Get the number of visible lines in the Monaco editor viewport.\n */\nexport function getVisibleLines(editor: MonacoEditor): number {\n const ranges = editor.getVisibleRanges();\n if (ranges.length === 0) return 20; // Fallback\n const first = ranges[0];\n const last = ranges[ranges.length - 1];\n return last.endLineNumber - first.startLineNumber + 1;\n}\n\n/**\n * Scroll the Monaco editor to reveal a specific line (0-based).\n */\nexport function revealLine(editor: MonacoEditor, line: number): void {\n editor.revealLine(line + 1); // Convert to 1-based\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@vimee/plugin-monaco",
3
+ "version": "0.1.0",
4
+ "description": "Attach vim editing to a Monaco Editor instance",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "typecheck": "tsgo --noEmit",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "test:coverage": "vitest run --coverage"
25
+ },
26
+ "keywords": [
27
+ "vim",
28
+ "monaco",
29
+ "editor",
30
+ "plugin",
31
+ "framework-agnostic"
32
+ ],
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/vimeejs/vimee.git",
37
+ "directory": "packages/plugin-monaco"
38
+ },
39
+ "peerDependencies": {
40
+ "@vimee/core": "0.2.0",
41
+ "monaco-editor": ">=0.34.0"
42
+ },
43
+ "devDependencies": {
44
+ "@vimee/core": "workspace:*",
45
+ "happy-dom": "20.8.4"
46
+ }
47
+ }