vim-prose 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/LICENSE +21 -0
- package/README.md +264 -0
- package/dist/extensions/vim/commands.d.ts +26 -0
- package/dist/extensions/vim/commands.js +231 -0
- package/dist/extensions/vim/commands.js.map +1 -0
- package/dist/extensions/vim/index.d.ts +3 -0
- package/dist/extensions/vim/index.js +2 -0
- package/dist/extensions/vim/index.js.map +1 -0
- package/dist/extensions/vim/keyHandler.d.ts +6 -0
- package/dist/extensions/vim/keyHandler.js +1400 -0
- package/dist/extensions/vim/keyHandler.js.map +1 -0
- package/dist/extensions/vim/motions.d.ts +80 -0
- package/dist/extensions/vim/motions.js +437 -0
- package/dist/extensions/vim/motions.js.map +1 -0
- package/dist/extensions/vim/operators.d.ts +36 -0
- package/dist/extensions/vim/operators.js +350 -0
- package/dist/extensions/vim/operators.js.map +1 -0
- package/dist/extensions/vim/state.d.ts +8 -0
- package/dist/extensions/vim/state.js +174 -0
- package/dist/extensions/vim/state.js.map +1 -0
- package/dist/extensions/vim/tiptap.d.ts +17 -0
- package/dist/extensions/vim/tiptap.js +49 -0
- package/dist/extensions/vim/types.d.ts +55 -0
- package/dist/extensions/vim/types.js +29 -0
- package/dist/extensions/vim/types.js.map +1 -0
- package/dist/extensions/vim/utils.d.ts +76 -0
- package/dist/extensions/vim/utils.js +224 -0
- package/dist/extensions/vim/utils.js.map +1 -0
- package/dist/extensions/vim/vim-mode.css +81 -0
- package/dist/extensions/vim/visual.d.ts +15 -0
- package/dist/extensions/vim/visual.js +58 -0
- package/dist/extensions/vim/visual.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { TextSelection, Selection, } from 'prosemirror-state';
|
|
2
|
+
import { charAt, isWordChar, isWhitespace, lineBounds, } from './utils';
|
|
3
|
+
/**
|
|
4
|
+
* Extract complete top-level nodes that overlap the given range.
|
|
5
|
+
* For partially-overlapping nodes (e.g. a list where only one item is selected),
|
|
6
|
+
* we create a copy of the parent with only the selected children.
|
|
7
|
+
*/
|
|
8
|
+
function extractTopLevelNodes(state, from, to) {
|
|
9
|
+
const nodes = [];
|
|
10
|
+
state.doc.nodesBetween(from, to, (node, pos, parent) => {
|
|
11
|
+
if (parent === state.doc) {
|
|
12
|
+
const nodeEnd = pos + node.nodeSize;
|
|
13
|
+
if (pos >= from && nodeEnd <= to) {
|
|
14
|
+
// Fully contained
|
|
15
|
+
nodes.push(node);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
// Partially contained — slice the content
|
|
19
|
+
const contentStart = pos + 1;
|
|
20
|
+
const relFrom = Math.max(from - contentStart, 0);
|
|
21
|
+
const relTo = Math.min(to - contentStart, node.content.size);
|
|
22
|
+
if (relFrom < relTo) {
|
|
23
|
+
nodes.push(node.copy(node.content.cut(relFrom, relTo)));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return false; // Don't descend into children
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return nodes;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolve a text object, returning { from, to } positions.
|
|
33
|
+
*/
|
|
34
|
+
export function resolveTextObject(state, pos, type, object) {
|
|
35
|
+
if (object === 'w') {
|
|
36
|
+
return resolveWordObject(state, pos);
|
|
37
|
+
}
|
|
38
|
+
const pairs = {
|
|
39
|
+
'(': ['(', ')'],
|
|
40
|
+
')': ['(', ')'],
|
|
41
|
+
'[': ['[', ']'],
|
|
42
|
+
']': ['[', ']'],
|
|
43
|
+
'{': ['{', '}'],
|
|
44
|
+
'}': ['{', '}'],
|
|
45
|
+
'<': ['<', '>'],
|
|
46
|
+
'>': ['<', '>'],
|
|
47
|
+
"'": ["'", "'"],
|
|
48
|
+
'"': ['"', '"'],
|
|
49
|
+
'`': ['`', '`'],
|
|
50
|
+
};
|
|
51
|
+
const pair = pairs[object];
|
|
52
|
+
if (!pair)
|
|
53
|
+
return null;
|
|
54
|
+
return resolveDelimiterObject(state, pos, type, pair[0], pair[1]);
|
|
55
|
+
}
|
|
56
|
+
function resolveWordObject(state, pos) {
|
|
57
|
+
const $pos = state.doc.resolve(pos);
|
|
58
|
+
const lineS = $pos.start($pos.depth);
|
|
59
|
+
const lineE = $pos.end($pos.depth);
|
|
60
|
+
const ch = charAt(state, pos);
|
|
61
|
+
if (!ch)
|
|
62
|
+
return null;
|
|
63
|
+
let from = pos;
|
|
64
|
+
let to = pos;
|
|
65
|
+
if (isWordChar(ch)) {
|
|
66
|
+
// Expand to cover full word
|
|
67
|
+
while (from > lineS && isWordChar(charAt(state, from - 1)))
|
|
68
|
+
from--;
|
|
69
|
+
while (to < lineE && isWordChar(charAt(state, to)))
|
|
70
|
+
to++;
|
|
71
|
+
}
|
|
72
|
+
else if (isWhitespace(ch)) {
|
|
73
|
+
while (from > lineS && isWhitespace(charAt(state, from - 1)))
|
|
74
|
+
from--;
|
|
75
|
+
while (to < lineE && isWhitespace(charAt(state, to)))
|
|
76
|
+
to++;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Punctuation
|
|
80
|
+
while (from > lineS &&
|
|
81
|
+
!isWordChar(charAt(state, from - 1)) &&
|
|
82
|
+
!isWhitespace(charAt(state, from - 1)))
|
|
83
|
+
from--;
|
|
84
|
+
while (to < lineE &&
|
|
85
|
+
!isWordChar(charAt(state, to)) &&
|
|
86
|
+
!isWhitespace(charAt(state, to)))
|
|
87
|
+
to++;
|
|
88
|
+
}
|
|
89
|
+
return { from, to };
|
|
90
|
+
}
|
|
91
|
+
function resolveDelimiterObject(state, pos, type, open, close) {
|
|
92
|
+
// For quotes, simple scan within current paragraph
|
|
93
|
+
const $pos = state.doc.resolve(pos);
|
|
94
|
+
const lineS = $pos.start($pos.depth);
|
|
95
|
+
const lineE = $pos.end($pos.depth);
|
|
96
|
+
const text = state.doc.textBetween(lineS, lineE, '\n', '\n');
|
|
97
|
+
const offset = pos - lineS;
|
|
98
|
+
if (open === close) {
|
|
99
|
+
// Quote-like delimiters: find surrounding pair
|
|
100
|
+
let openIdx = -1;
|
|
101
|
+
let closeIdx = -1;
|
|
102
|
+
// Find the quote pair that contains the cursor
|
|
103
|
+
const indices = [];
|
|
104
|
+
for (let i = 0; i < text.length; i++) {
|
|
105
|
+
if (text[i] === open)
|
|
106
|
+
indices.push(i);
|
|
107
|
+
}
|
|
108
|
+
// Find a pair that contains the offset
|
|
109
|
+
for (let i = 0; i < indices.length - 1; i += 2) {
|
|
110
|
+
if (indices[i] <= offset && offset <= indices[i + 1]) {
|
|
111
|
+
openIdx = indices[i];
|
|
112
|
+
closeIdx = indices[i + 1];
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// If cursor is on a delimiter, try to find pair starting from it
|
|
117
|
+
if (openIdx === -1 && text[offset] === open) {
|
|
118
|
+
for (let i = 0; i < indices.length - 1; i++) {
|
|
119
|
+
if (indices[i] === offset) {
|
|
120
|
+
openIdx = indices[i];
|
|
121
|
+
closeIdx = indices[i + 1];
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (openIdx === -1 || closeIdx === -1)
|
|
127
|
+
return null;
|
|
128
|
+
if (type === 'i') {
|
|
129
|
+
return { from: lineS + openIdx + 1, to: lineS + closeIdx };
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
return { from: lineS + openIdx, to: lineS + closeIdx + 1 };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// Bracket-like delimiters: handle nesting
|
|
137
|
+
let depth = 0;
|
|
138
|
+
let openIdx = -1;
|
|
139
|
+
// Search backward for opening bracket
|
|
140
|
+
for (let i = offset; i >= 0; i--) {
|
|
141
|
+
if (text[i] === close && i !== offset)
|
|
142
|
+
depth++;
|
|
143
|
+
if (text[i] === open) {
|
|
144
|
+
if (depth === 0) {
|
|
145
|
+
openIdx = i;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
depth--;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (openIdx === -1)
|
|
152
|
+
return null;
|
|
153
|
+
// Search forward for closing bracket
|
|
154
|
+
depth = 0;
|
|
155
|
+
let closeIdx = -1;
|
|
156
|
+
for (let i = openIdx + 1; i < text.length; i++) {
|
|
157
|
+
if (text[i] === open)
|
|
158
|
+
depth++;
|
|
159
|
+
if (text[i] === close) {
|
|
160
|
+
if (depth === 0) {
|
|
161
|
+
closeIdx = i;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
depth--;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (closeIdx === -1)
|
|
168
|
+
return null;
|
|
169
|
+
if (type === 'i') {
|
|
170
|
+
return { from: lineS + openIdx + 1, to: lineS + closeIdx };
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
return { from: lineS + openIdx, to: lineS + closeIdx + 1 };
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Execute a delete operation on the given range.
|
|
179
|
+
* Returns the transaction and the deleted text.
|
|
180
|
+
*/
|
|
181
|
+
export function executeDelete(state, from, to, vimState, linewise = false) {
|
|
182
|
+
const text = state.doc.textBetween(from, to, '\n', '\n');
|
|
183
|
+
const content = linewise ? extractTopLevelNodes(state, from, to) : null;
|
|
184
|
+
vimState.register = { text, linewise, content };
|
|
185
|
+
let tr;
|
|
186
|
+
if (linewise) {
|
|
187
|
+
tr = state.tr.delete(from, to);
|
|
188
|
+
const newPos = Math.min(from, tr.doc.content.size);
|
|
189
|
+
try {
|
|
190
|
+
const $pos = tr.doc.resolve(newPos);
|
|
191
|
+
const sel = Selection.findFrom($pos, 1, true) || Selection.findFrom($pos, -1, true);
|
|
192
|
+
if (sel)
|
|
193
|
+
tr.setSelection(sel);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// leave as-is
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
tr = state.tr.delete(from, to);
|
|
201
|
+
const newPos = Math.min(from, tr.doc.content.size);
|
|
202
|
+
try {
|
|
203
|
+
tr.setSelection(TextSelection.create(tr.doc, newPos));
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// leave selection as-is
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return tr;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Execute a yank operation on the given range.
|
|
213
|
+
* Does not modify the document.
|
|
214
|
+
*/
|
|
215
|
+
export function executeYank(state, from, to, vimState, linewise = false) {
|
|
216
|
+
const text = state.doc.textBetween(from, to, '\n', '\n');
|
|
217
|
+
const content = linewise ? extractTopLevelNodes(state, from, to) : null;
|
|
218
|
+
vimState.register = { text, linewise, content };
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Execute a change operation: delete range, then enter insert mode.
|
|
222
|
+
* Returns the transaction.
|
|
223
|
+
*/
|
|
224
|
+
export function executeChange(state, from, to, vimState, linewise = false) {
|
|
225
|
+
const text = state.doc.textBetween(from, to, '\n', '\n');
|
|
226
|
+
const content = linewise ? extractTopLevelNodes(state, from, to) : null;
|
|
227
|
+
vimState.register = { text, linewise, content };
|
|
228
|
+
let tr;
|
|
229
|
+
if (linewise) {
|
|
230
|
+
// Delete the selected lines and replace with a single empty paragraph
|
|
231
|
+
tr = state.tr.delete(from, to);
|
|
232
|
+
const paragraphType = state.schema.nodes.paragraph;
|
|
233
|
+
if (paragraphType) {
|
|
234
|
+
const insertAt = Math.min(from, tr.doc.content.size);
|
|
235
|
+
tr.insert(insertAt, paragraphType.create());
|
|
236
|
+
try {
|
|
237
|
+
tr.setSelection(TextSelection.create(tr.doc, insertAt + 1));
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// leave as-is
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
tr = state.tr.delete(from, to);
|
|
246
|
+
const newPos = Math.min(from, tr.doc.content.size);
|
|
247
|
+
try {
|
|
248
|
+
tr.setSelection(TextSelection.create(tr.doc, newPos));
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// leave selection as-is
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
vimState.mode = 'insert';
|
|
255
|
+
return tr;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Delete a number of lines starting from the current cursor position.
|
|
259
|
+
*/
|
|
260
|
+
export function deleteLines(state, pos, count, vimState) {
|
|
261
|
+
let from = lineBounds(state, pos).from;
|
|
262
|
+
let to = from;
|
|
263
|
+
for (let i = 0; i < count; i++) {
|
|
264
|
+
const bounds = lineBounds(state, Math.min(to + 1, state.doc.content.size - 1));
|
|
265
|
+
to = bounds.to;
|
|
266
|
+
if (to >= state.doc.content.size)
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
to = Math.min(to, state.doc.content.size);
|
|
270
|
+
const text = state.doc.textBetween(from, to, '\n', '\n');
|
|
271
|
+
const content = extractTopLevelNodes(state, from, to);
|
|
272
|
+
vimState.register = { text, linewise: true, content };
|
|
273
|
+
const tr = state.tr.delete(from, to);
|
|
274
|
+
// Position cursor at start of next (or previous) line
|
|
275
|
+
const newPos = Math.min(from, tr.doc.content.size);
|
|
276
|
+
try {
|
|
277
|
+
const $pos = tr.doc.resolve(newPos);
|
|
278
|
+
const sel = Selection.findFrom($pos, 1, true) || Selection.findFrom($pos, -1, true);
|
|
279
|
+
if (sel)
|
|
280
|
+
tr.setSelection(sel);
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
// leave as-is
|
|
284
|
+
}
|
|
285
|
+
return tr;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Yank a number of lines starting from the current cursor position.
|
|
289
|
+
*/
|
|
290
|
+
export function yankLines(state, pos, count, vimState) {
|
|
291
|
+
let from = lineBounds(state, pos).from;
|
|
292
|
+
let to = from;
|
|
293
|
+
for (let i = 0; i < count; i++) {
|
|
294
|
+
const bounds = lineBounds(state, Math.min(to + 1, state.doc.content.size - 1));
|
|
295
|
+
to = bounds.to;
|
|
296
|
+
if (to >= state.doc.content.size)
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
to = Math.min(to, state.doc.content.size);
|
|
300
|
+
const text = state.doc.textBetween(from, to, '\n', '\n');
|
|
301
|
+
const content = extractTopLevelNodes(state, from, to);
|
|
302
|
+
vimState.register = { text, linewise: true, content };
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Change a number of lines (clear content, enter insert mode).
|
|
306
|
+
*/
|
|
307
|
+
export function changeLines(state, pos, count, vimState) {
|
|
308
|
+
// For `cc` with count, delete extra lines and clear the first one
|
|
309
|
+
const $pos = state.doc.resolve(pos);
|
|
310
|
+
const firstLineStart = $pos.start($pos.depth);
|
|
311
|
+
const firstLineEnd = $pos.end($pos.depth);
|
|
312
|
+
if (count <= 1) {
|
|
313
|
+
// Just clear the content of the current line
|
|
314
|
+
const text = state.doc.textBetween(firstLineStart, firstLineEnd, '\n', '\n');
|
|
315
|
+
vimState.register = { text, linewise: true, content: null };
|
|
316
|
+
const tr = state.tr.delete(firstLineStart, firstLineEnd);
|
|
317
|
+
tr.setSelection(TextSelection.create(tr.doc, firstLineStart));
|
|
318
|
+
vimState.mode = 'insert';
|
|
319
|
+
return tr;
|
|
320
|
+
}
|
|
321
|
+
// Multiple lines: collect text, delete all lines, keep one empty paragraph
|
|
322
|
+
let from = lineBounds(state, pos).from;
|
|
323
|
+
let to = from;
|
|
324
|
+
for (let i = 0; i < count; i++) {
|
|
325
|
+
const bounds = lineBounds(state, Math.min(to + 1, state.doc.content.size - 1));
|
|
326
|
+
to = bounds.to;
|
|
327
|
+
if (to >= state.doc.content.size)
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
to = Math.min(to, state.doc.content.size);
|
|
331
|
+
const text = state.doc.textBetween(from, to, '\n', '\n');
|
|
332
|
+
const changeContent = extractTopLevelNodes(state, from, to);
|
|
333
|
+
vimState.register = { text, linewise: true, content: changeContent };
|
|
334
|
+
// Delete all the lines
|
|
335
|
+
const tr = state.tr.delete(from, to);
|
|
336
|
+
// Insert an empty paragraph
|
|
337
|
+
const paragraphType = state.schema.nodes.paragraph;
|
|
338
|
+
if (paragraphType) {
|
|
339
|
+
tr.insert(from, paragraphType.create());
|
|
340
|
+
}
|
|
341
|
+
const newPos = Math.min(from + 1, tr.doc.content.size);
|
|
342
|
+
try {
|
|
343
|
+
tr.setSelection(TextSelection.create(tr.doc, newPos));
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
// leave as-is
|
|
347
|
+
}
|
|
348
|
+
vimState.mode = 'insert';
|
|
349
|
+
return tr;
|
|
350
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operators.js","sourceRoot":"","sources":["../../../src/extensions/vim/operators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Plugin, PluginKey, EditorState } from 'prosemirror-state';
|
|
2
|
+
import { VimState, VimEditorCommands } from './types';
|
|
3
|
+
export declare const vimPluginKey: PluginKey<VimState>;
|
|
4
|
+
export declare function createVimPlugin(commands: VimEditorCommands): Plugin<VimState>;
|
|
5
|
+
/**
|
|
6
|
+
* Get the current vim state from an EditorState.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getVimStateFromEditorState(state: EditorState): VimState | null;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { Plugin, PluginKey, Selection, } from 'prosemirror-state';
|
|
2
|
+
import { Decoration, DecorationSet } from 'prosemirror-view';
|
|
3
|
+
import { defaultVimState } from './types';
|
|
4
|
+
import { handleKeyDown } from './keyHandler';
|
|
5
|
+
import { findAllMatches } from './utils';
|
|
6
|
+
export const vimPluginKey = new PluginKey('vimMode');
|
|
7
|
+
export function createVimPlugin(commands) {
|
|
8
|
+
const vimState = defaultVimState();
|
|
9
|
+
return new Plugin({
|
|
10
|
+
key: vimPluginKey,
|
|
11
|
+
state: {
|
|
12
|
+
init() {
|
|
13
|
+
return vimState;
|
|
14
|
+
},
|
|
15
|
+
apply(tr, value) {
|
|
16
|
+
// Map mark positions through document changes
|
|
17
|
+
if (tr.docChanged && Object.keys(value.marks).length > 0) {
|
|
18
|
+
const newMarks = {};
|
|
19
|
+
for (const [key, pos] of Object.entries(value.marks)) {
|
|
20
|
+
newMarks[key] = tr.mapping.map(pos);
|
|
21
|
+
}
|
|
22
|
+
value.marks = newMarks;
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
view(editorView) {
|
|
28
|
+
// Create search bar element
|
|
29
|
+
const searchBar = document.createElement('div');
|
|
30
|
+
searchBar.className = 'vim-search-bar';
|
|
31
|
+
searchBar.style.display = 'none';
|
|
32
|
+
const searchPrefix = document.createElement('span');
|
|
33
|
+
searchPrefix.className = 'vim-search-prefix';
|
|
34
|
+
searchPrefix.textContent = '/';
|
|
35
|
+
searchBar.appendChild(searchPrefix);
|
|
36
|
+
const searchInput = document.createElement('span');
|
|
37
|
+
searchInput.className = 'vim-search-input';
|
|
38
|
+
searchBar.appendChild(searchInput);
|
|
39
|
+
const searchCursor = document.createElement('span');
|
|
40
|
+
searchCursor.className = 'vim-search-cursor';
|
|
41
|
+
searchCursor.textContent = '\u2588';
|
|
42
|
+
searchBar.appendChild(searchCursor);
|
|
43
|
+
// Insert after the editor
|
|
44
|
+
editorView.dom.parentNode?.insertBefore(searchBar, editorView.dom.nextSibling);
|
|
45
|
+
return {
|
|
46
|
+
update() {
|
|
47
|
+
if (vimState.searchActive) {
|
|
48
|
+
searchBar.style.display = 'flex';
|
|
49
|
+
searchInput.textContent = vimState.searchQuery;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
searchBar.style.display = 'none';
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
destroy() {
|
|
56
|
+
searchBar.remove();
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
props: {
|
|
61
|
+
handleDOMEvents: {
|
|
62
|
+
mouseup: (view) => {
|
|
63
|
+
setTimeout(() => {
|
|
64
|
+
const { from, to } = view.state.selection;
|
|
65
|
+
if (from !== to && vimState.mode === 'normal') {
|
|
66
|
+
// Native selection in normal mode → enter visual mode
|
|
67
|
+
vimState.mode = 'visual';
|
|
68
|
+
vimState.visualAnchor = from;
|
|
69
|
+
vimState.visualHead = to > from ? to - 1 : from;
|
|
70
|
+
view.dispatch(view.state.tr);
|
|
71
|
+
}
|
|
72
|
+
else if (from === to &&
|
|
73
|
+
(vimState.mode === 'visual' || vimState.mode === 'visual-line')) {
|
|
74
|
+
// Click (empty selection) in visual mode → exit to normal
|
|
75
|
+
vimState.mode = 'normal';
|
|
76
|
+
vimState.visualAnchor = null;
|
|
77
|
+
vimState.visualHead = null;
|
|
78
|
+
view.dispatch(view.state.tr);
|
|
79
|
+
}
|
|
80
|
+
}, 0);
|
|
81
|
+
return false;
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
handleKeyDown(view, event) {
|
|
85
|
+
return handleKeyDown(view, event, vimState, commands);
|
|
86
|
+
},
|
|
87
|
+
handleTextInput(_view, _from, _to, text) {
|
|
88
|
+
if (vimState.isTrackingInsert) {
|
|
89
|
+
vimState.insertTextBuffer += text;
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
},
|
|
93
|
+
attributes(_state) {
|
|
94
|
+
return {
|
|
95
|
+
'data-vim-mode': vimState.mode,
|
|
96
|
+
class: `vim-mode vim-mode-${vimState.mode}`,
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
decorations(state) {
|
|
100
|
+
const decorations = [];
|
|
101
|
+
const cursorPos = vimState.visualHead ?? state.selection.$head.pos;
|
|
102
|
+
if (vimState.mode !== 'insert') {
|
|
103
|
+
// Block cursor
|
|
104
|
+
try {
|
|
105
|
+
let $pos = state.doc.resolve(cursorPos);
|
|
106
|
+
// If at document root (depth 0), find nearest textblock
|
|
107
|
+
if ($pos.depth === 0) {
|
|
108
|
+
const sel = Selection.findFrom($pos, 1, true) ||
|
|
109
|
+
Selection.findFrom($pos, -1, true);
|
|
110
|
+
if (sel)
|
|
111
|
+
$pos = sel.$from;
|
|
112
|
+
}
|
|
113
|
+
if ($pos.depth > 0) {
|
|
114
|
+
const lineEnd = $pos.end($pos.depth);
|
|
115
|
+
if (cursorPos < lineEnd) {
|
|
116
|
+
decorations.push(Decoration.inline(cursorPos, cursorPos + 1, {
|
|
117
|
+
class: 'vim-block-cursor',
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
decorations.push(Decoration.widget(cursorPos, () => {
|
|
122
|
+
const span = document.createElement('span');
|
|
123
|
+
span.className = 'vim-block-cursor-eol';
|
|
124
|
+
span.textContent = '\u00a0';
|
|
125
|
+
return span;
|
|
126
|
+
}, { side: 0 }));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Position invalid, skip cursor decoration
|
|
132
|
+
}
|
|
133
|
+
// Visual selection highlight via decoration (more reliable than ::selection)
|
|
134
|
+
if ((vimState.mode === 'visual' || vimState.mode === 'visual-line') &&
|
|
135
|
+
state.selection.from < state.selection.to) {
|
|
136
|
+
decorations.push(Decoration.inline(state.selection.from, state.selection.to, {
|
|
137
|
+
class: 'vim-visual-selection',
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Search match highlights (visible in all modes)
|
|
142
|
+
const activeSearchTerm = vimState.searchActive
|
|
143
|
+
? vimState.searchQuery
|
|
144
|
+
: vimState.searchHighlightsVisible
|
|
145
|
+
? vimState.searchTerm
|
|
146
|
+
: '';
|
|
147
|
+
if (activeSearchTerm) {
|
|
148
|
+
const wholeWord = !vimState.searchActive && vimState.searchWholeWord;
|
|
149
|
+
const matches = findAllMatches(state, activeSearchTerm, wholeWord);
|
|
150
|
+
for (const matchPos of matches) {
|
|
151
|
+
const end = matchPos + activeSearchTerm.length;
|
|
152
|
+
if (end <= state.doc.content.size) {
|
|
153
|
+
const isCurrent = matchPos <= cursorPos && cursorPos < end;
|
|
154
|
+
decorations.push(Decoration.inline(matchPos, end, {
|
|
155
|
+
class: isCurrent
|
|
156
|
+
? 'vim-search-match-current'
|
|
157
|
+
: 'vim-search-match',
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return decorations.length > 0
|
|
163
|
+
? DecorationSet.create(state.doc, decorations)
|
|
164
|
+
: DecorationSet.empty;
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get the current vim state from an EditorState.
|
|
171
|
+
*/
|
|
172
|
+
export function getVimStateFromEditorState(state) {
|
|
173
|
+
return vimPluginKey.getState(state) ?? null;
|
|
174
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/extensions/vim/state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5C,OAAO,EAAY,eAAe,EAAE,MAAM,SAAS,CAAA;AAEnD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,SAAS,CAAW,SAAS,CAAC,CAAA;AAE9D,MAAM,UAAU,WAAW,CAAC,WAAgB;IAC1C,OAAO,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,eAAe,EAAE,CAAA;AAChE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAY;IAC5C,EAAE,CAAC,KAAK,GAAG,IAAI,CAAA;IACf,EAAE,CAAC,aAAa,GAAG,IAAI,CAAA;IACvB,EAAE,CAAC,QAAQ,GAAG,IAAI,CAAA;IAClB,EAAE,CAAC,WAAW,GAAG,KAAK,CAAA;IACtB,EAAE,CAAC,UAAU,GAAG,IAAI,CAAA;IACpB,EAAE,CAAC,SAAS,GAAG,KAAK,CAAA;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,EAAY;IACzC,MAAM,OAAO,GAAG,EAAE,CAAC,aAAa,IAAI,CAAC,CAAA;IACrC,MAAM,WAAW,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC,CAAA;IACjC,OAAO,OAAO,GAAG,WAAW,CAAA;AAC9B,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiptap v3 extension wrapper for VimMode.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { VimMode } from './extensions/vim/tiptap'
|
|
6
|
+
* const editor = new Editor({
|
|
7
|
+
* extensions: [VimMode],
|
|
8
|
+
* })
|
|
9
|
+
*
|
|
10
|
+
* Requires @tiptap/core to be installed by the consumer.
|
|
11
|
+
*/
|
|
12
|
+
import { Extension } from '@tiptap/core';
|
|
13
|
+
import type { VimState, Mode } from './types';
|
|
14
|
+
export declare const VimMode: Extension<any, any>;
|
|
15
|
+
export declare function getVimMode(editor: any): Mode;
|
|
16
|
+
export declare function getVimStatus(editor: any): string;
|
|
17
|
+
export type { VimState, Mode };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiptap v3 extension wrapper for VimMode.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { VimMode } from './extensions/vim/tiptap'
|
|
6
|
+
* const editor = new Editor({
|
|
7
|
+
* extensions: [VimMode],
|
|
8
|
+
* })
|
|
9
|
+
*
|
|
10
|
+
* Requires @tiptap/core to be installed by the consumer.
|
|
11
|
+
*/
|
|
12
|
+
import { Extension } from '@tiptap/core';
|
|
13
|
+
import { createVimPlugin, vimPluginKey } from './state';
|
|
14
|
+
export const VimMode = Extension.create({
|
|
15
|
+
name: 'vimMode',
|
|
16
|
+
addProseMirrorPlugins() {
|
|
17
|
+
const editor = this.editor;
|
|
18
|
+
return [
|
|
19
|
+
createVimPlugin({
|
|
20
|
+
undo: () => editor.commands.undo(),
|
|
21
|
+
redo: () => editor.commands.redo(),
|
|
22
|
+
indent: () => {
|
|
23
|
+
try {
|
|
24
|
+
return editor.commands.sinkListItem('listItem');
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
outdent: () => {
|
|
31
|
+
try {
|
|
32
|
+
return editor.commands.liftListItem('listItem');
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
}),
|
|
39
|
+
];
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
export function getVimMode(editor) {
|
|
43
|
+
const state = vimPluginKey.getState(editor.state);
|
|
44
|
+
return state?.mode ?? 'normal';
|
|
45
|
+
}
|
|
46
|
+
export function getVimStatus(editor) {
|
|
47
|
+
const state = vimPluginKey.getState(editor.state);
|
|
48
|
+
return state?.statusMessage ?? '';
|
|
49
|
+
}
|