vim-sim 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Cole Foster
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,507 @@
1
+ # vim-sim
2
+
3
+ [![CI](https://github.com/colefoster/vim-sim/actions/workflows/ci.yml/badge.svg)](https://github.com/colefoster/vim-sim/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/vim-sim.svg)](https://www.npmjs.com/package/vim-sim)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
7
+ [![Test Coverage](https://img.shields.io/badge/coverage-85%25-brightgreen.svg)](https://github.com/colefoster/vim-sim)
8
+
9
+ A complete, production-ready Vim editor simulation engine for Node.js. Implements the full Vim editing experience with 85%+ test coverage, including motions, operators, visual mode, text objects, macros, marks, undo/redo tree, spell checking, and more.
10
+
11
+ ## Features
12
+
13
+ ### Core Editing
14
+ - ✅ **All Basic Motions**: `h`, `j`, `k`, `l`, `w`, `b`, `e`, `W`, `B`, `E`, `0`, `$`, `^`, `gg`, `G`, `{`, `}`, `(`, `)`, `%`
15
+ - ✅ **Find & Till**: `f`, `F`, `t`, `T`, `;`, `,`
16
+ - ✅ **Operators**: `d`, `c`, `y`, `>`, `<`, `=`, `g~`, `gu`, `gU`
17
+ - ✅ **Visual Mode**: Character (`v`), Line (`V`), and Block (`<C-v>`) with all operators
18
+ - ✅ **Text Objects**: `iw`, `aw`, `i"`, `a"`, `i'`, `a'`, `i(`, `a(`, `i{`, `a{`, `i[`, `a[`, `it`, `at`, `ip`, `ap`, `is`, `as`
19
+ - ✅ **Insert Mode**: `i`, `I`, `a`, `A`, `o`, `O`, `s`, `S`, `c` commands
20
+ - ✅ **Replace & Change**: `r`, `R`, `~`, `J`, `gJ`
21
+
22
+ ### Advanced Features
23
+ - ✅ **Undo/Redo Tree**: Full vim-style undo tree with branches (`u`, `<C-r>`, `g-`, `g+`)
24
+ - ✅ **Macros**: Record (`q`) and playback (`@`) with count support
25
+ - ✅ **Marks**: Local and global marks (`m`, `'`, `` ` ``)
26
+ - ✅ **Jump List**: `<C-o>`, `<C-i>` navigation
27
+ - ✅ **Registers**: Named, numbered, and special registers
28
+ - ✅ **Spell Checking**: Real-time with custom dictionaries
29
+ - ✅ **Completion**: Keyword, line, file, and omni completion
30
+ - ✅ **Folds**: Code folding support
31
+ - ✅ **Multiple Windows**: Split, navigate, and resize
32
+ - ✅ **Multiple Buffers**: File management and buffer navigation
33
+
34
+ ### Text Formatting
35
+ - ✅ **Auto-indentation**: Smart indentation based on braces
36
+ - ✅ **Text Wrapping**: Format text with `gq`, `gw`
37
+ - ✅ **Alignment**: Column alignment support
38
+ - ✅ **Comment Toggling**: Smart comment handling
39
+ - ✅ **Digraphs**: 150+ special characters
40
+
41
+ ## Installation
42
+
43
+ ```bash
44
+ npm install vim-sim
45
+ ```
46
+
47
+ ## Quick Start
48
+
49
+ ```typescript
50
+ import { Session } from 'vim-sim';
51
+
52
+ // Create a new vim session
53
+ const session = new Session();
54
+
55
+ // Load some text
56
+ session.handleKey(':');
57
+ session.handleKey('e');
58
+ session.handleKey(' ');
59
+ session.handleKey('f');
60
+ session.handleKey('i');
61
+ session.handleKey('l');
62
+ session.handleKey('e');
63
+ session.handleKey('.');
64
+ session.handleKey('t');
65
+ session.handleKey('x');
66
+ session.handleKey('t');
67
+ session.handleKey('Enter');
68
+
69
+ // Or set buffer content directly
70
+ import { State, Buffer, Cursor, Mode } from 'vim-sim';
71
+
72
+ const state = new State(
73
+ new Buffer('Hello, World!\nVim simulation is awesome!'),
74
+ new Cursor(0, 0),
75
+ null,
76
+ Mode.NORMAL
77
+ );
78
+ session.setState(state);
79
+
80
+ // Execute vim commands
81
+ session.handleKey('w'); // Move to next word
82
+ session.handleKey('d'); // Start delete operator
83
+ session.handleKey('w'); // Delete word
84
+
85
+ // Get the current state
86
+ const currentState = session.getState();
87
+ console.log(currentState.buffer.content); // "Hello, is awesome!"
88
+ console.log(currentState.cursor.line); // 0
89
+ console.log(currentState.cursor.column); // 7
90
+ ```
91
+
92
+ ## API Documentation
93
+
94
+ ### Session
95
+
96
+ The main entry point for vim simulation. Manages state and command execution.
97
+
98
+ ```typescript
99
+ class Session {
100
+ constructor(config?: Partial<VimConfig>)
101
+
102
+ // Handle a single keypress
103
+ handleKey(key: string): void
104
+
105
+ // Get current editor state
106
+ getState(): State
107
+
108
+ // Set editor state
109
+ setState(state: State): void
110
+
111
+ // Get command history
112
+ getHistory(): CommandHistoryEntry[]
113
+ }
114
+ ```
115
+
116
+ **Example:**
117
+ ```typescript
118
+ const session = new Session({
119
+ tabSize: 4,
120
+ expandTab: true,
121
+ autoIndent: true
122
+ });
123
+
124
+ session.handleKey('i'); // Enter insert mode
125
+ session.handleKey('H');
126
+ session.handleKey('e');
127
+ session.handleKey('l');
128
+ session.handleKey('l');
129
+ session.handleKey('o');
130
+ session.handleKey('Escape'); // Back to normal mode
131
+ session.handleKey('0'); // Go to start of line
132
+ ```
133
+
134
+ ### State
135
+
136
+ Represents the complete editor state at a point in time.
137
+
138
+ ```typescript
139
+ class State {
140
+ constructor(
141
+ buffer: Buffer,
142
+ cursor: Cursor,
143
+ selection: Range | null,
144
+ mode: Mode,
145
+ // ... other optional parameters
146
+ )
147
+
148
+ readonly buffer: Buffer
149
+ readonly cursor: Cursor
150
+ readonly selection: Range | null
151
+ readonly mode: Mode
152
+ readonly desiredColumn: number | null
153
+ // ... many more properties
154
+ }
155
+ ```
156
+
157
+ ### Buffer
158
+
159
+ Represents the text content being edited.
160
+
161
+ ```typescript
162
+ class Buffer {
163
+ constructor(content: string = '')
164
+
165
+ readonly content: string
166
+
167
+ getLineCount(): number
168
+ getLine(index: number): string
169
+ getLines(): string[]
170
+ }
171
+ ```
172
+
173
+ **Example:**
174
+ ```typescript
175
+ const buffer = new Buffer('Line 1\nLine 2\nLine 3');
176
+ console.log(buffer.getLineCount()); // 3
177
+ console.log(buffer.getLine(1)); // "Line 2"
178
+ ```
179
+
180
+ ### Cursor
181
+
182
+ Represents cursor position (0-indexed).
183
+
184
+ ```typescript
185
+ class Cursor {
186
+ constructor(line: number, column: number)
187
+
188
+ readonly line: number
189
+ readonly column: number
190
+ }
191
+ ```
192
+
193
+ ### Mode
194
+
195
+ Vim editing modes.
196
+
197
+ ```typescript
198
+ enum Mode {
199
+ NORMAL = 'normal',
200
+ INSERT = 'insert',
201
+ VISUAL = 'visual',
202
+ VISUAL_LINE = 'visual_line',
203
+ VISUAL_BLOCK = 'visual_block',
204
+ COMMAND_LINE = 'command_line',
205
+ REPLACE = 'replace'
206
+ }
207
+ ```
208
+
209
+ ## Usage Examples
210
+
211
+ ### Basic Text Editing
212
+
213
+ ```typescript
214
+ import { Session, Buffer, State, Cursor, Mode } from 'vim-sim';
215
+
216
+ const session = new Session();
217
+
218
+ // Start with some text
219
+ session.setState(new State(
220
+ new Buffer('The quick brown fox\njumps over\nthe lazy dog'),
221
+ new Cursor(0, 0),
222
+ null,
223
+ Mode.NORMAL
224
+ ));
225
+
226
+ // Delete a word: dw
227
+ session.handleKey('d');
228
+ session.handleKey('w');
229
+
230
+ console.log(session.getState().buffer.content);
231
+ // "quick brown fox\njumps over\nthe lazy dog"
232
+ ```
233
+
234
+ ### Visual Mode Selection
235
+
236
+ ```typescript
237
+ const session = new Session();
238
+ session.setState(new State(
239
+ new Buffer('Hello World'),
240
+ new Cursor(0, 0),
241
+ null,
242
+ Mode.NORMAL
243
+ ));
244
+
245
+ // Visual select and delete: vlllld
246
+ session.handleKey('v'); // Enter visual mode
247
+ session.handleKey('l'); // Extend selection
248
+ session.handleKey('l');
249
+ session.handleKey('l');
250
+ session.handleKey('l');
251
+ session.handleKey('d'); // Delete selection
252
+
253
+ console.log(session.getState().buffer.content); // " World"
254
+ ```
255
+
256
+ ### Using Text Objects
257
+
258
+ ```typescript
259
+ const session = new Session();
260
+ session.setState(new State(
261
+ new Buffer('function test(arg) { return arg; }'),
262
+ new Cursor(0, 20), // Inside the parentheses
263
+ null,
264
+ Mode.NORMAL
265
+ ));
266
+
267
+ // Delete inside parentheses: di(
268
+ session.handleKey('d');
269
+ session.handleKey('i');
270
+ session.handleKey('(');
271
+
272
+ console.log(session.getState().buffer.content);
273
+ // "function test() { return arg; }"
274
+ ```
275
+
276
+ ### Macros
277
+
278
+ ```typescript
279
+ const session = new Session();
280
+ session.setState(new State(
281
+ new Buffer('line1\nline2\nline3'),
282
+ new Cursor(0, 0),
283
+ null,
284
+ Mode.NORMAL
285
+ ));
286
+
287
+ // Record macro: qaIHello <Esc>jq
288
+ session.handleKey('q');
289
+ session.handleKey('a');
290
+ session.handleKey('I');
291
+ session.handleKey('H');
292
+ session.handleKey('e');
293
+ session.handleKey('l');
294
+ session.handleKey('l');
295
+ session.handleKey('o');
296
+ session.handleKey(' ');
297
+ session.handleKey('Escape');
298
+ session.handleKey('j');
299
+ session.handleKey('q');
300
+
301
+ // Replay macro twice: 2@a
302
+ session.handleKey('2');
303
+ session.handleKey('@');
304
+ session.handleKey('a');
305
+
306
+ console.log(session.getState().buffer.content);
307
+ // "Hello line1\nHello line2\nHello line3"
308
+ ```
309
+
310
+ ### Undo/Redo Tree
311
+
312
+ ```typescript
313
+ const session = new Session();
314
+ const state = new State(
315
+ new Buffer('original text'),
316
+ new Cursor(0, 0),
317
+ null,
318
+ Mode.NORMAL
319
+ );
320
+ session.setState(state);
321
+
322
+ // Make some changes
323
+ session.handleKey('c');
324
+ session.handleKey('w');
325
+ session.handleKey('n');
326
+ session.handleKey('e');
327
+ session.handleKey('w');
328
+ session.handleKey('Escape');
329
+
330
+ // Undo: u
331
+ session.handleKey('u');
332
+ console.log(session.getState().buffer.content); // "original text"
333
+
334
+ // Redo: <C-r>
335
+ session.handleKey('<C-r>');
336
+ console.log(session.getState().buffer.content); // "new text"
337
+ ```
338
+
339
+ ### Working with Registers
340
+
341
+ ```typescript
342
+ const session = new Session();
343
+ session.setState(new State(
344
+ new Buffer('Copy this text\nPaste here'),
345
+ new Cursor(0, 0),
346
+ null,
347
+ Mode.NORMAL
348
+ ));
349
+
350
+ // Yank to register 'a': "ayy
351
+ session.handleKey('"');
352
+ session.handleKey('a');
353
+ session.handleKey('y');
354
+ session.handleKey('y');
355
+
356
+ // Move and paste: jp
357
+ session.handleKey('j');
358
+ session.handleKey('"');
359
+ session.handleKey('a');
360
+ session.handleKey('p');
361
+
362
+ console.log(session.getState().buffer.content);
363
+ // "Copy this text\nPaste here\nCopy this text"
364
+ ```
365
+
366
+ ## Advanced Usage
367
+
368
+ ### Custom Configuration
369
+
370
+ ```typescript
371
+ import { Session, ConfigManager } from 'vim-sim';
372
+
373
+ const session = new Session({
374
+ tabSize: 2,
375
+ expandTab: true,
376
+ autoIndent: true,
377
+ smartIndent: true,
378
+ textWidth: 80,
379
+ wrap: true,
380
+ spell: true
381
+ });
382
+
383
+ // Or update config after creation
384
+ const config = session.getState().configManager;
385
+ // Access config values as needed
386
+ ```
387
+
388
+ ### Spell Checking
389
+
390
+ ```typescript
391
+ const session = new Session();
392
+ const state = session.getState();
393
+
394
+ // Enable spell checking
395
+ state.spellChecker.enable();
396
+
397
+ // Add custom words
398
+ state.spellChecker.addGoodWord('vim-sim');
399
+
400
+ // Check a word
401
+ const isCorrect = state.spellChecker.isCorrect('hello');
402
+
403
+ // Get suggestions
404
+ const suggestions = state.spellChecker.suggest('wrold');
405
+ console.log(suggestions); // ['world']
406
+ ```
407
+
408
+ ### Window Management
409
+
410
+ ```typescript
411
+ const session = new Session();
412
+ const state = session.getState();
413
+
414
+ // Split window horizontally: <C-w>s
415
+ // Split window vertically: <C-w>v
416
+ // Navigate windows: <C-w>h/j/k/l
417
+ // Close window: <C-w>c
418
+
419
+ // Access window manager directly
420
+ const windowManager = state.windowManager;
421
+ const activeWindow = windowManager.getActiveWindow();
422
+ ```
423
+
424
+ ## TypeScript Support
425
+
426
+ This package is written in TypeScript and provides full type definitions.
427
+
428
+ ```typescript
429
+ import type { State, Buffer, Cursor, Mode, Range, Command } from 'vim-sim';
430
+
431
+ function processVimState(state: State): void {
432
+ const { buffer, cursor, mode, selection } = state;
433
+
434
+ if (mode === Mode.VISUAL && selection) {
435
+ console.log(`Selected from ${selection.start} to ${selection.end}`);
436
+ }
437
+ }
438
+ ```
439
+
440
+ ## Testing
441
+
442
+ The vim-sim package has 85%+ test coverage with over 1700 passing tests.
443
+
444
+ ```bash
445
+ # Run tests
446
+ npm test
447
+
448
+ # Run tests in watch mode
449
+ npm run test:watch
450
+
451
+ # Type check
452
+ npm run typecheck
453
+ ```
454
+
455
+ ## Performance
456
+
457
+ - **Immutable State**: All state updates return new state objects
458
+ - **Efficient Algorithms**: O(1) undo/redo, efficient text manipulation
459
+ - **Small Bundle**: Tree-shakeable ES modules
460
+ - **No DOM Dependencies**: Pure Node.js/TypeScript implementation
461
+
462
+ ## Browser Support
463
+
464
+ While designed for Node.js, vim-sim works in browsers with a bundler:
465
+
466
+ ```bash
467
+ npm install vim-sim
468
+ ```
469
+
470
+ ```typescript
471
+ import { Session } from 'vim-sim';
472
+
473
+ const session = new Session();
474
+ // Use in your web application
475
+ ```
476
+
477
+ ## Comparison with Other Vim Implementations
478
+
479
+ | Feature | vim-sim | CodeMirror Vim | Monaco Vim |
480
+ |---------|---------|----------------|------------|
481
+ | Standalone | ✅ | ❌ (requires CodeMirror) | ❌ (requires Monaco) |
482
+ | Node.js API | ✅ | ❌ | ❌ |
483
+ | Undo Tree | ✅ | ❌ | ❌ |
484
+ | Full Text Objects | ✅ | Partial | Partial |
485
+ | Macros | ✅ | ✅ | ❌ |
486
+ | Marks & Jumps | ✅ | Partial | Partial |
487
+ | Spell Checking | ✅ | ❌ | ❌ |
488
+ | TypeScript | ✅ | Partial | ✅ |
489
+
490
+ ## Contributing
491
+
492
+ Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) first.
493
+
494
+ ## License
495
+
496
+ MIT © Cole Foster
497
+
498
+ ## Documentation
499
+
500
+ For more detailed documentation, see:
501
+ - [API Documentation](docs/API.md)
502
+ - [Test Analysis](docs/TEST-ANALYSIS-SUMMARY.md)
503
+ - [Feature Documentation](docs/FINAL-SUMMARY.md)
504
+
505
+ ## Acknowledgments
506
+
507
+ This project implements Vim's behavior as closely as possible to the original Vim editor by Bram Moolenaar.