@vimee/plugin-codemirror 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/dist/index.cjs ADDED
@@ -0,0 +1,261 @@
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
+ cursorToOffset: () => cursorToOffset,
25
+ getTopLine: () => getTopLine,
26
+ getVisibleLines: () => getVisibleLines,
27
+ offsetToCursor: () => offsetToCursor
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/attach.ts
32
+ var import_core = require("@vimee/core");
33
+
34
+ // src/cursor.ts
35
+ function cursorToOffset(content, cursor) {
36
+ const lines = content.split("\n");
37
+ let offset = 0;
38
+ for (let i = 0; i < cursor.line && i < lines.length; i++) {
39
+ offset += lines[i].length + 1;
40
+ }
41
+ const lineLength = lines[cursor.line]?.length ?? 0;
42
+ offset += Math.min(cursor.col, lineLength);
43
+ return offset;
44
+ }
45
+ function offsetToCursor(content, offset) {
46
+ let remaining = offset;
47
+ const lines = content.split("\n");
48
+ for (let i = 0; i < lines.length; i++) {
49
+ if (remaining <= lines[i].length) {
50
+ return { line: i, col: remaining };
51
+ }
52
+ remaining -= lines[i].length + 1;
53
+ }
54
+ const lastLine = lines.length - 1;
55
+ return { line: lastLine, col: lines[lastLine]?.length ?? 0 };
56
+ }
57
+
58
+ // src/viewport.ts
59
+ function getTopLine(view) {
60
+ return view.state.doc.lineAt(view.viewport.from).number - 1;
61
+ }
62
+ function getVisibleLines(view) {
63
+ const first = view.state.doc.lineAt(view.viewport.from);
64
+ const last = view.state.doc.lineAt(view.viewport.to);
65
+ return last.number - first.number + 1;
66
+ }
67
+
68
+ // src/attach.ts
69
+ function attach(view, options = {}) {
70
+ const {
71
+ readOnly = false,
72
+ onChange,
73
+ onModeChange,
74
+ onYank,
75
+ onSave,
76
+ onAction,
77
+ indentStyle,
78
+ indentWidth
79
+ } = options;
80
+ const content = view.state.doc.toString();
81
+ const buffer = new import_core.TextBuffer(content);
82
+ const initialCursor = offsetToCursor(content, 0);
83
+ let ctx = (0, import_core.createInitialContext)(initialCursor, {
84
+ indentStyle,
85
+ indentWidth
86
+ });
87
+ let isComposing = false;
88
+ function syncContentToEditor() {
89
+ const newContent = buffer.getContent();
90
+ const doc = view.state.doc;
91
+ if (newContent !== doc.toString()) {
92
+ view.dispatch({
93
+ changes: { from: 0, to: doc.length, insert: newContent }
94
+ });
95
+ }
96
+ }
97
+ function syncCursorToEditor(cursor) {
98
+ const offset = cursorToOffset(buffer.getContent(), cursor);
99
+ view.dispatch({
100
+ selection: { anchor: offset },
101
+ scrollIntoView: true
102
+ });
103
+ }
104
+ function updateVisualSelection() {
105
+ if (ctx.mode !== "visual" && ctx.mode !== "visual-line" && ctx.mode !== "visual-block") {
106
+ const offset = cursorToOffset(buffer.getContent(), ctx.cursor);
107
+ view.dispatch({
108
+ selection: { anchor: offset },
109
+ scrollIntoView: true
110
+ });
111
+ return;
112
+ }
113
+ const anchor = ctx.visualAnchor ?? ctx.cursor;
114
+ const content2 = buffer.getContent();
115
+ if (ctx.mode === "visual-line") {
116
+ const before = anchor.line < ctx.cursor.line || anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col;
117
+ const startLine = before ? anchor.line : ctx.cursor.line;
118
+ const endLine = before ? ctx.cursor.line : anchor.line;
119
+ const lines = content2.split("\n");
120
+ const startOffset = cursorToOffset(content2, { line: startLine, col: 0 });
121
+ const endOffset = cursorToOffset(content2, {
122
+ line: endLine,
123
+ col: lines[endLine]?.length ?? 0
124
+ });
125
+ view.dispatch({
126
+ selection: { anchor: startOffset, head: endOffset },
127
+ scrollIntoView: true
128
+ });
129
+ } else {
130
+ const anchorOffset = cursorToOffset(content2, anchor);
131
+ const cursorOffset = cursorToOffset(content2, ctx.cursor);
132
+ const before = anchor.line < ctx.cursor.line || anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col;
133
+ const head = before ? cursorOffset + 1 : cursorOffset;
134
+ const anchorAdj = before ? anchorOffset : anchorOffset + 1;
135
+ view.dispatch({
136
+ selection: { anchor: anchorAdj, head },
137
+ scrollIntoView: true
138
+ });
139
+ }
140
+ }
141
+ function processActions(actionList, newCtx, key) {
142
+ for (const action of actionList) {
143
+ onAction?.(action, key);
144
+ switch (action.type) {
145
+ case "content-change":
146
+ syncContentToEditor();
147
+ onChange?.(action.content);
148
+ break;
149
+ case "mode-change":
150
+ onModeChange?.(action.mode);
151
+ break;
152
+ case "yank":
153
+ onYank?.(action.text);
154
+ break;
155
+ case "save":
156
+ onSave?.(action.content);
157
+ break;
158
+ case "set-option":
159
+ case "status-message":
160
+ case "scroll":
161
+ case "noop":
162
+ break;
163
+ }
164
+ }
165
+ updateVisualSelection();
166
+ }
167
+ function syncViewport() {
168
+ const topLine = getTopLine(view);
169
+ const height = getVisibleLines(view);
170
+ ctx = {
171
+ ...ctx,
172
+ viewportTopLine: topLine,
173
+ viewportHeight: height
174
+ };
175
+ }
176
+ function shouldPreventDefault(e) {
177
+ const mode = ctx.mode;
178
+ if (mode !== "insert") {
179
+ if (e.ctrlKey && (e.key === "c" || e.key === "a")) return false;
180
+ if (e.key === "Shift" || e.key === "Control" || e.key === "Alt" || e.key === "Meta") {
181
+ return false;
182
+ }
183
+ return true;
184
+ }
185
+ if (e.key === "Escape") return true;
186
+ if (e.key === "Tab") return true;
187
+ if (e.key === "Backspace") return true;
188
+ if (e.key === "Enter") return true;
189
+ if (e.ctrlKey) {
190
+ const ctrlKeys = ["r", "b", "f", "d", "u", "v", "w"];
191
+ if (ctrlKeys.includes(e.key)) return true;
192
+ }
193
+ return true;
194
+ }
195
+ function handleScroll(direction, amount) {
196
+ const visibleLines = getVisibleLines(view);
197
+ const scrollLines = Math.max(1, Math.floor(visibleLines * amount));
198
+ const newLine = direction === "up" ? Math.max(0, ctx.cursor.line - scrollLines) : Math.min(buffer.getLineCount() - 1, ctx.cursor.line + scrollLines);
199
+ const maxCol = Math.max(0, (buffer.getLineLength(newLine) || 1) - 1);
200
+ const newCursor = {
201
+ line: newLine,
202
+ col: Math.min(ctx.cursor.col, maxCol)
203
+ };
204
+ ctx = { ...ctx, cursor: newCursor };
205
+ syncCursorToEditor(newCursor);
206
+ }
207
+ function onKeyDown(e) {
208
+ if (isComposing) return;
209
+ syncViewport();
210
+ if (e.ctrlKey) {
211
+ const scrollKeys = {
212
+ b: { direction: "up", amount: 1 },
213
+ f: { direction: "down", amount: 1 },
214
+ u: { direction: "up", amount: 0.5 },
215
+ d: { direction: "down", amount: 0.5 }
216
+ };
217
+ const scroll = scrollKeys[e.key];
218
+ if (scroll) {
219
+ e.preventDefault();
220
+ handleScroll(scroll.direction, scroll.amount);
221
+ return;
222
+ }
223
+ }
224
+ if (shouldPreventDefault(e)) {
225
+ e.preventDefault();
226
+ }
227
+ const { newCtx, actions } = (0, import_core.processKeystroke)(e.key, ctx, buffer, e.ctrlKey, readOnly);
228
+ ctx = newCtx;
229
+ processActions(actions, newCtx, e.key);
230
+ }
231
+ function onCompositionStart() {
232
+ isComposing = true;
233
+ }
234
+ function onCompositionEnd() {
235
+ isComposing = false;
236
+ }
237
+ const target = view.contentDOM;
238
+ target.addEventListener("keydown", onKeyDown);
239
+ target.addEventListener("compositionstart", onCompositionStart);
240
+ target.addEventListener("compositionend", onCompositionEnd);
241
+ syncViewport();
242
+ return {
243
+ getMode: () => ctx.mode,
244
+ getCursor: () => ({ ...ctx.cursor }),
245
+ getContent: () => buffer.getContent(),
246
+ destroy: () => {
247
+ target.removeEventListener("keydown", onKeyDown);
248
+ target.removeEventListener("compositionstart", onCompositionStart);
249
+ target.removeEventListener("compositionend", onCompositionEnd);
250
+ }
251
+ };
252
+ }
253
+ // Annotate the CommonJS export names for ESM import in node:
254
+ 0 && (module.exports = {
255
+ attach,
256
+ cursorToOffset,
257
+ getTopLine,
258
+ getVisibleLines,
259
+ offsetToCursor
260
+ });
261
+ //# 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-codemirror\n *\n * Attach vim editing to any CodeMirror 6 EditorView.\n * Framework-agnostic — works with vanilla JS, React, or any CodeMirror wrapper.\n *\n * @example\n * ```ts\n * import { attach } from '@vimee/plugin-codemirror'\n *\n * const vim = attach(editorView, {\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, VimCodeMirror, CodeMirrorView } from \"./types\";\nexport type {\n CodeMirrorLine,\n CodeMirrorDoc,\n CodeMirrorState,\n CodeMirrorTransactionSpec,\n} from \"./types\";\n\n// Cursor utilities (for advanced usage)\nexport { cursorToOffset, offsetToCursor } from \"./cursor\";\n\n// Viewport utilities (for advanced usage)\nexport { getTopLine, getVisibleLines } 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-codemirror package.\n * Attaches vim keybindings to an existing CodeMirror 6 EditorView.\n */\n\nimport type { VimContext, VimAction, CursorPosition } from \"@vimee/core\";\nimport { TextBuffer, createInitialContext, processKeystroke } from \"@vimee/core\";\nimport type { AttachOptions, VimCodeMirror, CodeMirrorView } from \"./types\";\nimport { cursorToOffset, offsetToCursor } from \"./cursor\";\nimport { getTopLine, getVisibleLines } from \"./viewport\";\n\n/**\n * Attach vim editing to a CodeMirror 6 EditorView.\n *\n * @example\n * ```ts\n * const vim = attach(editorView, {\n * onChange: (value) => console.log(value),\n * onModeChange: (mode) => console.log(mode),\n * });\n *\n * // Later...\n * vim.destroy();\n * ```\n */\nexport function attach(view: CodeMirrorView, options: AttachOptions = {}): VimCodeMirror {\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 content = view.state.doc.toString();\n const buffer = new TextBuffer(content);\n const initialCursor = offsetToCursor(content, 0);\n let ctx: VimContext = createInitialContext(initialCursor, {\n indentStyle,\n indentWidth,\n });\n\n // --- Track composing state (IME input) ---\n let isComposing = false;\n\n // --- Sync vimee buffer content to CodeMirror ---\n function syncContentToEditor(): void {\n const newContent = buffer.getContent();\n const doc = view.state.doc;\n if (newContent !== doc.toString()) {\n view.dispatch({\n changes: { from: 0, to: doc.length, insert: newContent },\n });\n }\n }\n\n // --- Sync cursor position to CodeMirror ---\n function syncCursorToEditor(cursor: CursorPosition): void {\n const offset = cursorToOffset(buffer.getContent(), cursor);\n view.dispatch({\n selection: { anchor: offset },\n scrollIntoView: true,\n });\n }\n\n // --- Update visual mode selection ---\n function updateVisualSelection(): void {\n if (ctx.mode !== \"visual\" && ctx.mode !== \"visual-line\" && ctx.mode !== \"visual-block\") {\n // In non-visual modes, just set cursor position\n const offset = cursorToOffset(buffer.getContent(), ctx.cursor);\n view.dispatch({\n selection: { anchor: offset },\n scrollIntoView: true,\n });\n return;\n }\n\n const anchor = ctx.visualAnchor ?? ctx.cursor;\n const content = buffer.getContent();\n\n if (ctx.mode === \"visual-line\") {\n // Extend selection to full lines\n const before =\n anchor.line < ctx.cursor.line ||\n (anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col);\n const startLine = before ? anchor.line : ctx.cursor.line;\n const endLine = before ? ctx.cursor.line : anchor.line;\n\n const lines = content.split(\"\\n\");\n const startOffset = cursorToOffset(content, { line: startLine, col: 0 });\n const endOffset = cursorToOffset(content, {\n line: endLine,\n col: lines[endLine]?.length ?? 0,\n });\n\n view.dispatch({\n selection: { anchor: startOffset, head: endOffset },\n scrollIntoView: true,\n });\n } else {\n // Character-wise visual mode\n const anchorOffset = cursorToOffset(content, anchor);\n const cursorOffset = cursorToOffset(content, ctx.cursor);\n\n // Extend selection to include the character under cursor\n const before =\n anchor.line < ctx.cursor.line ||\n (anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col);\n const head = before ? cursorOffset + 1 : cursorOffset;\n const anchorAdj = before ? anchorOffset : anchorOffset + 1;\n\n view.dispatch({\n selection: { anchor: anchorAdj, head },\n scrollIntoView: true,\n });\n }\n }\n\n // --- Process vim actions and sync state ---\n function processActions(actionList: VimAction[], newCtx: VimContext, key: string): void {\n for (const action of actionList) {\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 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/selection from context\n updateVisualSelection();\n }\n\n // --- Update viewport info on the VimContext ---\n function syncViewport(): void {\n const topLine = getTopLine(view);\n const height = getVisibleLines(view);\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(view);\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 }\n\n // --- Keyboard handler ---\n function onKeyDown(e: KeyboardEvent): void {\n if (isComposing) return;\n\n // Update viewport before processing (for H/M/L motions)\n syncViewport();\n\n // Handle Ctrl scroll keys at this level\n if (e.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[e.key];\n if (scroll) {\n e.preventDefault();\n handleScroll(scroll.direction, scroll.amount);\n return;\n }\n }\n\n if (shouldPreventDefault(e)) {\n e.preventDefault();\n }\n\n const { newCtx, actions } = processKeystroke(e.key, ctx, buffer, e.ctrlKey, readOnly);\n\n ctx = newCtx;\n processActions(actions, newCtx, e.key);\n }\n\n // --- IME composition handlers ---\n function onCompositionStart(): void {\n isComposing = true;\n }\n\n function onCompositionEnd(): void {\n isComposing = false;\n }\n\n // --- Attach event listeners ---\n const target = view.contentDOM;\n target.addEventListener(\"keydown\", onKeyDown);\n target.addEventListener(\"compositionstart\", onCompositionStart);\n target.addEventListener(\"compositionend\", onCompositionEnd);\n\n // Initial viewport sync\n syncViewport();\n\n // --- Return the VimCodeMirror handle ---\n return {\n getMode: () => ctx.mode,\n getCursor: () => ({ ...ctx.cursor }),\n getContent: () => buffer.getContent(),\n destroy: () => {\n target.removeEventListener(\"keydown\", onKeyDown);\n target.removeEventListener(\"compositionstart\", onCompositionStart);\n target.removeEventListener(\"compositionend\", onCompositionEnd);\n },\n };\n}\n","/**\n * cursor.ts\n *\n * Utilities for converting between vimee's 0-based CursorPosition\n * and CodeMirror's flat character offsets.\n */\n\nimport type { CursorPosition } from \"@vimee/core\";\n\n/**\n * Convert a 0-based CursorPosition to a flat character offset.\n */\nexport function cursorToOffset(content: string, cursor: CursorPosition): number {\n const lines = content.split(\"\\n\");\n let offset = 0;\n for (let i = 0; i < cursor.line && i < lines.length; i++) {\n offset += lines[i].length + 1; // +1 for newline\n }\n const lineLength = lines[cursor.line]?.length ?? 0;\n offset += Math.min(cursor.col, lineLength);\n return offset;\n}\n\n/**\n * Convert a flat character offset to a 0-based CursorPosition.\n */\nexport function offsetToCursor(content: string, offset: number): CursorPosition {\n let remaining = offset;\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (remaining <= lines[i].length) {\n return { line: i, col: remaining };\n }\n remaining -= lines[i].length + 1; // +1 for newline\n }\n // Past end of content\n const lastLine = lines.length - 1;\n return { line: lastLine, col: lines[lastLine]?.length ?? 0 };\n}\n","/**\n * viewport.ts\n *\n * Utilities for computing viewport information from a CodeMirror 6 EditorView.\n * Handles viewport tracking for H/M/L motions and Ctrl-U/D/B/F page scrolling.\n */\n\nimport type { CodeMirrorView } from \"./types\";\n\n/**\n * Get the first visible line (0-based) from the CodeMirror view.\n */\nexport function getTopLine(view: CodeMirrorView): number {\n return view.state.doc.lineAt(view.viewport.from).number - 1; // Convert to 0-based\n}\n\n/**\n * Get the number of visible lines in the CodeMirror viewport.\n */\nexport function getVisibleLines(view: CodeMirrorView): number {\n const first = view.state.doc.lineAt(view.viewport.from);\n const last = view.state.doc.lineAt(view.viewport.to);\n return last.number - first.number + 1;\n}\n"],"mappings":"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","names":["content"]}
@@ -0,0 +1,158 @@
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-codemirror.
8
+ */
9
+
10
+ /** A single line in a CodeMirror document. */
11
+ interface CodeMirrorLine {
12
+ /** 1-based line number. */
13
+ readonly number: number;
14
+ /** Start offset of this line in the document. */
15
+ readonly from: number;
16
+ /** End offset of this line (exclusive of newline). */
17
+ readonly to: number;
18
+ /** Text content of this line. */
19
+ readonly text: string;
20
+ }
21
+ /** Minimal subset of CodeMirror's `Text` (document). */
22
+ interface CodeMirrorDoc {
23
+ toString(): string;
24
+ /** Total character length of the document. */
25
+ readonly length: number;
26
+ /** Total number of lines. */
27
+ readonly lines: number;
28
+ /** Get the line that contains the given character offset. */
29
+ lineAt(pos: number): CodeMirrorLine;
30
+ /** Get a line by its 1-based line number. */
31
+ line(n: number): CodeMirrorLine;
32
+ }
33
+ /** Minimal subset of CodeMirror's `EditorState`. */
34
+ interface CodeMirrorState {
35
+ readonly doc: CodeMirrorDoc;
36
+ }
37
+ /** Transaction spec for `EditorView.dispatch()`. */
38
+ interface CodeMirrorTransactionSpec {
39
+ changes?: {
40
+ from: number;
41
+ to?: number;
42
+ insert?: string;
43
+ };
44
+ selection?: {
45
+ anchor: number;
46
+ head?: number;
47
+ };
48
+ scrollIntoView?: boolean;
49
+ }
50
+ /**
51
+ * Minimal subset of CodeMirror's `EditorView`.
52
+ *
53
+ * Any object satisfying this interface can be passed to `attach()`.
54
+ */
55
+ interface CodeMirrorView {
56
+ /** The outer DOM element of the editor. */
57
+ readonly dom: HTMLElement;
58
+ /** The content-editable DOM element where text is edited. */
59
+ readonly contentDOM: HTMLElement;
60
+ /** The current editor state. */
61
+ readonly state: CodeMirrorState;
62
+ /** The currently visible viewport range (character offsets). */
63
+ readonly viewport: {
64
+ from: number;
65
+ to: number;
66
+ };
67
+ /** Dispatch one or more transaction specs to the editor. */
68
+ dispatch(...specs: CodeMirrorTransactionSpec[]): void;
69
+ /** Focus the editor. */
70
+ focus(): void;
71
+ }
72
+ /** Options passed to `attach()`. */
73
+ interface AttachOptions {
74
+ /** Read-only mode — vim motions work but no edits. */
75
+ readOnly?: boolean;
76
+ /** Called whenever the editor content changes via vim commands. */
77
+ onChange?: (value: string) => void;
78
+ /** Called whenever the vim mode changes. */
79
+ onModeChange?: (mode: VimMode) => void;
80
+ /** Called when text is yanked. */
81
+ onYank?: (text: string) => void;
82
+ /** Called when `:w` is executed. */
83
+ onSave?: (value: string) => void;
84
+ /** Called for every vim action (low-level). */
85
+ onAction?: (action: VimAction, key: string) => void;
86
+ /** Indent style: "space" or "tab" (default: "space"). */
87
+ indentStyle?: "space" | "tab";
88
+ /** Indent width (default: 2). */
89
+ indentWidth?: number;
90
+ }
91
+ /** The object returned by `attach()` — the handle to the vim-enabled editor. */
92
+ interface VimCodeMirror {
93
+ /** Current vim mode. */
94
+ getMode(): VimMode;
95
+ /** Current cursor position (0-based line/col). */
96
+ getCursor(): CursorPosition;
97
+ /** Current editor content (from the vim buffer). */
98
+ getContent(): string;
99
+ /** Detach all event listeners and restore the editor to its original state. */
100
+ destroy(): void;
101
+ }
102
+
103
+ /**
104
+ * attach.ts
105
+ *
106
+ * Core implementation of the plugin-codemirror package.
107
+ * Attaches vim keybindings to an existing CodeMirror 6 EditorView.
108
+ */
109
+
110
+ /**
111
+ * Attach vim editing to a CodeMirror 6 EditorView.
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * const vim = attach(editorView, {
116
+ * onChange: (value) => console.log(value),
117
+ * onModeChange: (mode) => console.log(mode),
118
+ * });
119
+ *
120
+ * // Later...
121
+ * vim.destroy();
122
+ * ```
123
+ */
124
+ declare function attach(view: CodeMirrorView, options?: AttachOptions): VimCodeMirror;
125
+
126
+ /**
127
+ * cursor.ts
128
+ *
129
+ * Utilities for converting between vimee's 0-based CursorPosition
130
+ * and CodeMirror's flat character offsets.
131
+ */
132
+
133
+ /**
134
+ * Convert a 0-based CursorPosition to a flat character offset.
135
+ */
136
+ declare function cursorToOffset(content: string, cursor: CursorPosition): number;
137
+ /**
138
+ * Convert a flat character offset to a 0-based CursorPosition.
139
+ */
140
+ declare function offsetToCursor(content: string, offset: number): CursorPosition;
141
+
142
+ /**
143
+ * viewport.ts
144
+ *
145
+ * Utilities for computing viewport information from a CodeMirror 6 EditorView.
146
+ * Handles viewport tracking for H/M/L motions and Ctrl-U/D/B/F page scrolling.
147
+ */
148
+
149
+ /**
150
+ * Get the first visible line (0-based) from the CodeMirror view.
151
+ */
152
+ declare function getTopLine(view: CodeMirrorView): number;
153
+ /**
154
+ * Get the number of visible lines in the CodeMirror viewport.
155
+ */
156
+ declare function getVisibleLines(view: CodeMirrorView): number;
157
+
158
+ export { type AttachOptions, type CodeMirrorDoc, type CodeMirrorLine, type CodeMirrorState, type CodeMirrorTransactionSpec, type CodeMirrorView, type VimCodeMirror, attach, cursorToOffset, getTopLine, getVisibleLines, offsetToCursor };
@@ -0,0 +1,158 @@
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-codemirror.
8
+ */
9
+
10
+ /** A single line in a CodeMirror document. */
11
+ interface CodeMirrorLine {
12
+ /** 1-based line number. */
13
+ readonly number: number;
14
+ /** Start offset of this line in the document. */
15
+ readonly from: number;
16
+ /** End offset of this line (exclusive of newline). */
17
+ readonly to: number;
18
+ /** Text content of this line. */
19
+ readonly text: string;
20
+ }
21
+ /** Minimal subset of CodeMirror's `Text` (document). */
22
+ interface CodeMirrorDoc {
23
+ toString(): string;
24
+ /** Total character length of the document. */
25
+ readonly length: number;
26
+ /** Total number of lines. */
27
+ readonly lines: number;
28
+ /** Get the line that contains the given character offset. */
29
+ lineAt(pos: number): CodeMirrorLine;
30
+ /** Get a line by its 1-based line number. */
31
+ line(n: number): CodeMirrorLine;
32
+ }
33
+ /** Minimal subset of CodeMirror's `EditorState`. */
34
+ interface CodeMirrorState {
35
+ readonly doc: CodeMirrorDoc;
36
+ }
37
+ /** Transaction spec for `EditorView.dispatch()`. */
38
+ interface CodeMirrorTransactionSpec {
39
+ changes?: {
40
+ from: number;
41
+ to?: number;
42
+ insert?: string;
43
+ };
44
+ selection?: {
45
+ anchor: number;
46
+ head?: number;
47
+ };
48
+ scrollIntoView?: boolean;
49
+ }
50
+ /**
51
+ * Minimal subset of CodeMirror's `EditorView`.
52
+ *
53
+ * Any object satisfying this interface can be passed to `attach()`.
54
+ */
55
+ interface CodeMirrorView {
56
+ /** The outer DOM element of the editor. */
57
+ readonly dom: HTMLElement;
58
+ /** The content-editable DOM element where text is edited. */
59
+ readonly contentDOM: HTMLElement;
60
+ /** The current editor state. */
61
+ readonly state: CodeMirrorState;
62
+ /** The currently visible viewport range (character offsets). */
63
+ readonly viewport: {
64
+ from: number;
65
+ to: number;
66
+ };
67
+ /** Dispatch one or more transaction specs to the editor. */
68
+ dispatch(...specs: CodeMirrorTransactionSpec[]): void;
69
+ /** Focus the editor. */
70
+ focus(): void;
71
+ }
72
+ /** Options passed to `attach()`. */
73
+ interface AttachOptions {
74
+ /** Read-only mode — vim motions work but no edits. */
75
+ readOnly?: boolean;
76
+ /** Called whenever the editor content changes via vim commands. */
77
+ onChange?: (value: string) => void;
78
+ /** Called whenever the vim mode changes. */
79
+ onModeChange?: (mode: VimMode) => void;
80
+ /** Called when text is yanked. */
81
+ onYank?: (text: string) => void;
82
+ /** Called when `:w` is executed. */
83
+ onSave?: (value: string) => void;
84
+ /** Called for every vim action (low-level). */
85
+ onAction?: (action: VimAction, key: string) => void;
86
+ /** Indent style: "space" or "tab" (default: "space"). */
87
+ indentStyle?: "space" | "tab";
88
+ /** Indent width (default: 2). */
89
+ indentWidth?: number;
90
+ }
91
+ /** The object returned by `attach()` — the handle to the vim-enabled editor. */
92
+ interface VimCodeMirror {
93
+ /** Current vim mode. */
94
+ getMode(): VimMode;
95
+ /** Current cursor position (0-based line/col). */
96
+ getCursor(): CursorPosition;
97
+ /** Current editor content (from the vim buffer). */
98
+ getContent(): string;
99
+ /** Detach all event listeners and restore the editor to its original state. */
100
+ destroy(): void;
101
+ }
102
+
103
+ /**
104
+ * attach.ts
105
+ *
106
+ * Core implementation of the plugin-codemirror package.
107
+ * Attaches vim keybindings to an existing CodeMirror 6 EditorView.
108
+ */
109
+
110
+ /**
111
+ * Attach vim editing to a CodeMirror 6 EditorView.
112
+ *
113
+ * @example
114
+ * ```ts
115
+ * const vim = attach(editorView, {
116
+ * onChange: (value) => console.log(value),
117
+ * onModeChange: (mode) => console.log(mode),
118
+ * });
119
+ *
120
+ * // Later...
121
+ * vim.destroy();
122
+ * ```
123
+ */
124
+ declare function attach(view: CodeMirrorView, options?: AttachOptions): VimCodeMirror;
125
+
126
+ /**
127
+ * cursor.ts
128
+ *
129
+ * Utilities for converting between vimee's 0-based CursorPosition
130
+ * and CodeMirror's flat character offsets.
131
+ */
132
+
133
+ /**
134
+ * Convert a 0-based CursorPosition to a flat character offset.
135
+ */
136
+ declare function cursorToOffset(content: string, cursor: CursorPosition): number;
137
+ /**
138
+ * Convert a flat character offset to a 0-based CursorPosition.
139
+ */
140
+ declare function offsetToCursor(content: string, offset: number): CursorPosition;
141
+
142
+ /**
143
+ * viewport.ts
144
+ *
145
+ * Utilities for computing viewport information from a CodeMirror 6 EditorView.
146
+ * Handles viewport tracking for H/M/L motions and Ctrl-U/D/B/F page scrolling.
147
+ */
148
+
149
+ /**
150
+ * Get the first visible line (0-based) from the CodeMirror view.
151
+ */
152
+ declare function getTopLine(view: CodeMirrorView): number;
153
+ /**
154
+ * Get the number of visible lines in the CodeMirror viewport.
155
+ */
156
+ declare function getVisibleLines(view: CodeMirrorView): number;
157
+
158
+ export { type AttachOptions, type CodeMirrorDoc, type CodeMirrorLine, type CodeMirrorState, type CodeMirrorTransactionSpec, type CodeMirrorView, type VimCodeMirror, attach, cursorToOffset, getTopLine, getVisibleLines, offsetToCursor };
package/dist/index.js ADDED
@@ -0,0 +1,230 @@
1
+ // src/attach.ts
2
+ import { TextBuffer, createInitialContext, processKeystroke } from "@vimee/core";
3
+
4
+ // src/cursor.ts
5
+ function cursorToOffset(content, cursor) {
6
+ const lines = content.split("\n");
7
+ let offset = 0;
8
+ for (let i = 0; i < cursor.line && i < lines.length; i++) {
9
+ offset += lines[i].length + 1;
10
+ }
11
+ const lineLength = lines[cursor.line]?.length ?? 0;
12
+ offset += Math.min(cursor.col, lineLength);
13
+ return offset;
14
+ }
15
+ function offsetToCursor(content, offset) {
16
+ let remaining = offset;
17
+ const lines = content.split("\n");
18
+ for (let i = 0; i < lines.length; i++) {
19
+ if (remaining <= lines[i].length) {
20
+ return { line: i, col: remaining };
21
+ }
22
+ remaining -= lines[i].length + 1;
23
+ }
24
+ const lastLine = lines.length - 1;
25
+ return { line: lastLine, col: lines[lastLine]?.length ?? 0 };
26
+ }
27
+
28
+ // src/viewport.ts
29
+ function getTopLine(view) {
30
+ return view.state.doc.lineAt(view.viewport.from).number - 1;
31
+ }
32
+ function getVisibleLines(view) {
33
+ const first = view.state.doc.lineAt(view.viewport.from);
34
+ const last = view.state.doc.lineAt(view.viewport.to);
35
+ return last.number - first.number + 1;
36
+ }
37
+
38
+ // src/attach.ts
39
+ function attach(view, options = {}) {
40
+ const {
41
+ readOnly = false,
42
+ onChange,
43
+ onModeChange,
44
+ onYank,
45
+ onSave,
46
+ onAction,
47
+ indentStyle,
48
+ indentWidth
49
+ } = options;
50
+ const content = view.state.doc.toString();
51
+ const buffer = new TextBuffer(content);
52
+ const initialCursor = offsetToCursor(content, 0);
53
+ let ctx = createInitialContext(initialCursor, {
54
+ indentStyle,
55
+ indentWidth
56
+ });
57
+ let isComposing = false;
58
+ function syncContentToEditor() {
59
+ const newContent = buffer.getContent();
60
+ const doc = view.state.doc;
61
+ if (newContent !== doc.toString()) {
62
+ view.dispatch({
63
+ changes: { from: 0, to: doc.length, insert: newContent }
64
+ });
65
+ }
66
+ }
67
+ function syncCursorToEditor(cursor) {
68
+ const offset = cursorToOffset(buffer.getContent(), cursor);
69
+ view.dispatch({
70
+ selection: { anchor: offset },
71
+ scrollIntoView: true
72
+ });
73
+ }
74
+ function updateVisualSelection() {
75
+ if (ctx.mode !== "visual" && ctx.mode !== "visual-line" && ctx.mode !== "visual-block") {
76
+ const offset = cursorToOffset(buffer.getContent(), ctx.cursor);
77
+ view.dispatch({
78
+ selection: { anchor: offset },
79
+ scrollIntoView: true
80
+ });
81
+ return;
82
+ }
83
+ const anchor = ctx.visualAnchor ?? ctx.cursor;
84
+ const content2 = buffer.getContent();
85
+ if (ctx.mode === "visual-line") {
86
+ const before = anchor.line < ctx.cursor.line || anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col;
87
+ const startLine = before ? anchor.line : ctx.cursor.line;
88
+ const endLine = before ? ctx.cursor.line : anchor.line;
89
+ const lines = content2.split("\n");
90
+ const startOffset = cursorToOffset(content2, { line: startLine, col: 0 });
91
+ const endOffset = cursorToOffset(content2, {
92
+ line: endLine,
93
+ col: lines[endLine]?.length ?? 0
94
+ });
95
+ view.dispatch({
96
+ selection: { anchor: startOffset, head: endOffset },
97
+ scrollIntoView: true
98
+ });
99
+ } else {
100
+ const anchorOffset = cursorToOffset(content2, anchor);
101
+ const cursorOffset = cursorToOffset(content2, ctx.cursor);
102
+ const before = anchor.line < ctx.cursor.line || anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col;
103
+ const head = before ? cursorOffset + 1 : cursorOffset;
104
+ const anchorAdj = before ? anchorOffset : anchorOffset + 1;
105
+ view.dispatch({
106
+ selection: { anchor: anchorAdj, head },
107
+ scrollIntoView: true
108
+ });
109
+ }
110
+ }
111
+ function processActions(actionList, newCtx, key) {
112
+ for (const action of actionList) {
113
+ onAction?.(action, key);
114
+ switch (action.type) {
115
+ case "content-change":
116
+ syncContentToEditor();
117
+ onChange?.(action.content);
118
+ break;
119
+ case "mode-change":
120
+ onModeChange?.(action.mode);
121
+ break;
122
+ case "yank":
123
+ onYank?.(action.text);
124
+ break;
125
+ case "save":
126
+ onSave?.(action.content);
127
+ break;
128
+ case "set-option":
129
+ case "status-message":
130
+ case "scroll":
131
+ case "noop":
132
+ break;
133
+ }
134
+ }
135
+ updateVisualSelection();
136
+ }
137
+ function syncViewport() {
138
+ const topLine = getTopLine(view);
139
+ const height = getVisibleLines(view);
140
+ ctx = {
141
+ ...ctx,
142
+ viewportTopLine: topLine,
143
+ viewportHeight: height
144
+ };
145
+ }
146
+ function shouldPreventDefault(e) {
147
+ const mode = ctx.mode;
148
+ if (mode !== "insert") {
149
+ if (e.ctrlKey && (e.key === "c" || e.key === "a")) return false;
150
+ if (e.key === "Shift" || e.key === "Control" || e.key === "Alt" || e.key === "Meta") {
151
+ return false;
152
+ }
153
+ return true;
154
+ }
155
+ if (e.key === "Escape") return true;
156
+ if (e.key === "Tab") return true;
157
+ if (e.key === "Backspace") return true;
158
+ if (e.key === "Enter") return true;
159
+ if (e.ctrlKey) {
160
+ const ctrlKeys = ["r", "b", "f", "d", "u", "v", "w"];
161
+ if (ctrlKeys.includes(e.key)) return true;
162
+ }
163
+ return true;
164
+ }
165
+ function handleScroll(direction, amount) {
166
+ const visibleLines = getVisibleLines(view);
167
+ const scrollLines = Math.max(1, Math.floor(visibleLines * amount));
168
+ const newLine = direction === "up" ? Math.max(0, ctx.cursor.line - scrollLines) : Math.min(buffer.getLineCount() - 1, ctx.cursor.line + scrollLines);
169
+ const maxCol = Math.max(0, (buffer.getLineLength(newLine) || 1) - 1);
170
+ const newCursor = {
171
+ line: newLine,
172
+ col: Math.min(ctx.cursor.col, maxCol)
173
+ };
174
+ ctx = { ...ctx, cursor: newCursor };
175
+ syncCursorToEditor(newCursor);
176
+ }
177
+ function onKeyDown(e) {
178
+ if (isComposing) return;
179
+ syncViewport();
180
+ if (e.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[e.key];
188
+ if (scroll) {
189
+ e.preventDefault();
190
+ handleScroll(scroll.direction, scroll.amount);
191
+ return;
192
+ }
193
+ }
194
+ if (shouldPreventDefault(e)) {
195
+ e.preventDefault();
196
+ }
197
+ const { newCtx, actions } = processKeystroke(e.key, ctx, buffer, e.ctrlKey, readOnly);
198
+ ctx = newCtx;
199
+ processActions(actions, newCtx, e.key);
200
+ }
201
+ function onCompositionStart() {
202
+ isComposing = true;
203
+ }
204
+ function onCompositionEnd() {
205
+ isComposing = false;
206
+ }
207
+ const target = view.contentDOM;
208
+ target.addEventListener("keydown", onKeyDown);
209
+ target.addEventListener("compositionstart", onCompositionStart);
210
+ target.addEventListener("compositionend", onCompositionEnd);
211
+ syncViewport();
212
+ return {
213
+ getMode: () => ctx.mode,
214
+ getCursor: () => ({ ...ctx.cursor }),
215
+ getContent: () => buffer.getContent(),
216
+ destroy: () => {
217
+ target.removeEventListener("keydown", onKeyDown);
218
+ target.removeEventListener("compositionstart", onCompositionStart);
219
+ target.removeEventListener("compositionend", onCompositionEnd);
220
+ }
221
+ };
222
+ }
223
+ export {
224
+ attach,
225
+ cursorToOffset,
226
+ getTopLine,
227
+ getVisibleLines,
228
+ offsetToCursor
229
+ };
230
+ //# 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-codemirror package.\n * Attaches vim keybindings to an existing CodeMirror 6 EditorView.\n */\n\nimport type { VimContext, VimAction, CursorPosition } from \"@vimee/core\";\nimport { TextBuffer, createInitialContext, processKeystroke } from \"@vimee/core\";\nimport type { AttachOptions, VimCodeMirror, CodeMirrorView } from \"./types\";\nimport { cursorToOffset, offsetToCursor } from \"./cursor\";\nimport { getTopLine, getVisibleLines } from \"./viewport\";\n\n/**\n * Attach vim editing to a CodeMirror 6 EditorView.\n *\n * @example\n * ```ts\n * const vim = attach(editorView, {\n * onChange: (value) => console.log(value),\n * onModeChange: (mode) => console.log(mode),\n * });\n *\n * // Later...\n * vim.destroy();\n * ```\n */\nexport function attach(view: CodeMirrorView, options: AttachOptions = {}): VimCodeMirror {\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 content = view.state.doc.toString();\n const buffer = new TextBuffer(content);\n const initialCursor = offsetToCursor(content, 0);\n let ctx: VimContext = createInitialContext(initialCursor, {\n indentStyle,\n indentWidth,\n });\n\n // --- Track composing state (IME input) ---\n let isComposing = false;\n\n // --- Sync vimee buffer content to CodeMirror ---\n function syncContentToEditor(): void {\n const newContent = buffer.getContent();\n const doc = view.state.doc;\n if (newContent !== doc.toString()) {\n view.dispatch({\n changes: { from: 0, to: doc.length, insert: newContent },\n });\n }\n }\n\n // --- Sync cursor position to CodeMirror ---\n function syncCursorToEditor(cursor: CursorPosition): void {\n const offset = cursorToOffset(buffer.getContent(), cursor);\n view.dispatch({\n selection: { anchor: offset },\n scrollIntoView: true,\n });\n }\n\n // --- Update visual mode selection ---\n function updateVisualSelection(): void {\n if (ctx.mode !== \"visual\" && ctx.mode !== \"visual-line\" && ctx.mode !== \"visual-block\") {\n // In non-visual modes, just set cursor position\n const offset = cursorToOffset(buffer.getContent(), ctx.cursor);\n view.dispatch({\n selection: { anchor: offset },\n scrollIntoView: true,\n });\n return;\n }\n\n const anchor = ctx.visualAnchor ?? ctx.cursor;\n const content = buffer.getContent();\n\n if (ctx.mode === \"visual-line\") {\n // Extend selection to full lines\n const before =\n anchor.line < ctx.cursor.line ||\n (anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col);\n const startLine = before ? anchor.line : ctx.cursor.line;\n const endLine = before ? ctx.cursor.line : anchor.line;\n\n const lines = content.split(\"\\n\");\n const startOffset = cursorToOffset(content, { line: startLine, col: 0 });\n const endOffset = cursorToOffset(content, {\n line: endLine,\n col: lines[endLine]?.length ?? 0,\n });\n\n view.dispatch({\n selection: { anchor: startOffset, head: endOffset },\n scrollIntoView: true,\n });\n } else {\n // Character-wise visual mode\n const anchorOffset = cursorToOffset(content, anchor);\n const cursorOffset = cursorToOffset(content, ctx.cursor);\n\n // Extend selection to include the character under cursor\n const before =\n anchor.line < ctx.cursor.line ||\n (anchor.line === ctx.cursor.line && anchor.col <= ctx.cursor.col);\n const head = before ? cursorOffset + 1 : cursorOffset;\n const anchorAdj = before ? anchorOffset : anchorOffset + 1;\n\n view.dispatch({\n selection: { anchor: anchorAdj, head },\n scrollIntoView: true,\n });\n }\n }\n\n // --- Process vim actions and sync state ---\n function processActions(actionList: VimAction[], newCtx: VimContext, key: string): void {\n for (const action of actionList) {\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 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/selection from context\n updateVisualSelection();\n }\n\n // --- Update viewport info on the VimContext ---\n function syncViewport(): void {\n const topLine = getTopLine(view);\n const height = getVisibleLines(view);\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(view);\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 }\n\n // --- Keyboard handler ---\n function onKeyDown(e: KeyboardEvent): void {\n if (isComposing) return;\n\n // Update viewport before processing (for H/M/L motions)\n syncViewport();\n\n // Handle Ctrl scroll keys at this level\n if (e.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[e.key];\n if (scroll) {\n e.preventDefault();\n handleScroll(scroll.direction, scroll.amount);\n return;\n }\n }\n\n if (shouldPreventDefault(e)) {\n e.preventDefault();\n }\n\n const { newCtx, actions } = processKeystroke(e.key, ctx, buffer, e.ctrlKey, readOnly);\n\n ctx = newCtx;\n processActions(actions, newCtx, e.key);\n }\n\n // --- IME composition handlers ---\n function onCompositionStart(): void {\n isComposing = true;\n }\n\n function onCompositionEnd(): void {\n isComposing = false;\n }\n\n // --- Attach event listeners ---\n const target = view.contentDOM;\n target.addEventListener(\"keydown\", onKeyDown);\n target.addEventListener(\"compositionstart\", onCompositionStart);\n target.addEventListener(\"compositionend\", onCompositionEnd);\n\n // Initial viewport sync\n syncViewport();\n\n // --- Return the VimCodeMirror handle ---\n return {\n getMode: () => ctx.mode,\n getCursor: () => ({ ...ctx.cursor }),\n getContent: () => buffer.getContent(),\n destroy: () => {\n target.removeEventListener(\"keydown\", onKeyDown);\n target.removeEventListener(\"compositionstart\", onCompositionStart);\n target.removeEventListener(\"compositionend\", onCompositionEnd);\n },\n };\n}\n","/**\n * cursor.ts\n *\n * Utilities for converting between vimee's 0-based CursorPosition\n * and CodeMirror's flat character offsets.\n */\n\nimport type { CursorPosition } from \"@vimee/core\";\n\n/**\n * Convert a 0-based CursorPosition to a flat character offset.\n */\nexport function cursorToOffset(content: string, cursor: CursorPosition): number {\n const lines = content.split(\"\\n\");\n let offset = 0;\n for (let i = 0; i < cursor.line && i < lines.length; i++) {\n offset += lines[i].length + 1; // +1 for newline\n }\n const lineLength = lines[cursor.line]?.length ?? 0;\n offset += Math.min(cursor.col, lineLength);\n return offset;\n}\n\n/**\n * Convert a flat character offset to a 0-based CursorPosition.\n */\nexport function offsetToCursor(content: string, offset: number): CursorPosition {\n let remaining = offset;\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n if (remaining <= lines[i].length) {\n return { line: i, col: remaining };\n }\n remaining -= lines[i].length + 1; // +1 for newline\n }\n // Past end of content\n const lastLine = lines.length - 1;\n return { line: lastLine, col: lines[lastLine]?.length ?? 0 };\n}\n","/**\n * viewport.ts\n *\n * Utilities for computing viewport information from a CodeMirror 6 EditorView.\n * Handles viewport tracking for H/M/L motions and Ctrl-U/D/B/F page scrolling.\n */\n\nimport type { CodeMirrorView } from \"./types\";\n\n/**\n * Get the first visible line (0-based) from the CodeMirror view.\n */\nexport function getTopLine(view: CodeMirrorView): number {\n return view.state.doc.lineAt(view.viewport.from).number - 1; // Convert to 0-based\n}\n\n/**\n * Get the number of visible lines in the CodeMirror viewport.\n */\nexport function getVisibleLines(view: CodeMirrorView): number {\n const first = view.state.doc.lineAt(view.viewport.from);\n const last = view.state.doc.lineAt(view.viewport.to);\n return last.number - first.number + 1;\n}\n"],"mappings":"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","names":["content"]}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@vimee/plugin-codemirror",
3
+ "version": "0.1.0",
4
+ "description": "Attach vim editing to a CodeMirror 6 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
+ "codemirror",
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-codemirror"
38
+ },
39
+ "peerDependencies": {
40
+ "@vimee/core": "0.2.0",
41
+ "@codemirror/view": "6.40.0",
42
+ "@codemirror/state": "6.6.0"
43
+ },
44
+ "devDependencies": {
45
+ "@vimee/core": "workspace:*",
46
+ "@codemirror/view": "6.40.0",
47
+ "@codemirror/state": "6.6.0",
48
+ "happy-dom": "20.8.4"
49
+ }
50
+ }