vim-sim 1.0.2 → 1.0.3

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.
@@ -0,0 +1,221 @@
1
+ # Configuration System Improvements
2
+
3
+ **Date**: 2026-02-15
4
+ **Summary**: Enhanced vim-sim's configuration infrastructure to make behavioral differences from vanilla Vim more obvious, cleaner, and easier to edit programmatically.
5
+
6
+ ## Motivation
7
+
8
+ During test suite review, we discovered that vim-sim's default behavior for `h` and `l` motions (wrapping to previous/next lines) differs from vanilla Vim (which stops at line boundaries). Rather than changing vim-sim's user-friendly default, we improved the configuration system to:
9
+
10
+ 1. Make all behavioral differences configurable
11
+ 2. Clearly document which settings differ from Vim
12
+ 3. Provide metadata for each option
13
+ 4. Enable easy switching between vim-sim and Vim defaults
14
+
15
+ ## Changes Made
16
+
17
+ ### 1. Enhanced `VimConfig` Interface
18
+
19
+ Added motion behavior options:
20
+
21
+ ```typescript
22
+ interface VimConfig {
23
+ // ... existing options ...
24
+
25
+ // Motion behavior options (NEW)
26
+ whichwrap: string; // Keys that wrap to prev/next line
27
+ startofline: boolean; // Move to first non-blank when changing lines
28
+ virtualedit: string; // Allow cursor past end of line
29
+ wrapscan: boolean; // Search wraps around end of file
30
+ }
31
+ ```
32
+
33
+ ### 2. Added `VimConfigMetadata` Interface
34
+
35
+ Every option now has comprehensive metadata:
36
+
37
+ ```typescript
38
+ interface VimConfigMetadata {
39
+ description: string; // What the option does
40
+ vimDefault: string | number | boolean; // Vim's default
41
+ vimSimDefault: string | number | boolean; // vim-sim's default
42
+ category: 'display' | 'indentation' | 'search' | 'motion' | 'editing';
43
+ type: 'boolean' | 'number' | 'string';
44
+ differsFromVim: boolean; // Flag for different defaults
45
+ validValues?: string[]; // For string options
46
+ }
47
+ ```
48
+
49
+ ### 3. Created `CONFIG_METADATA` Constant
50
+
51
+ Complete metadata for all 18 config options:
52
+
53
+ ```typescript
54
+ export const CONFIG_METADATA: Record<VimConfigKey, VimConfigMetadata> = {
55
+ whichwrap: {
56
+ description: 'Keys that wrap to prev/next line (b,s,h,l,<,>,~)',
57
+ vimDefault: 'b,s',
58
+ vimSimDefault: 'h,l',
59
+ category: 'motion',
60
+ type: 'string',
61
+ differsFromVim: true,
62
+ validValues: ['b', 's', 'h', 'l', '<', '>', '[', ']', '~'],
63
+ },
64
+ // ... 17 more options ...
65
+ };
66
+ ```
67
+
68
+ ### 4. Enhanced ConfigManager Methods
69
+
70
+ Added helper methods:
71
+
72
+ ```typescript
73
+ // Get metadata about an option
74
+ configManager.getMetadata(key: VimConfigKey): VimConfigMetadata
75
+
76
+ // Get all options that differ from Vim
77
+ configManager.getDifferencesFromVim(): VimConfigKey[]
78
+
79
+ // Get options by category
80
+ configManager.getByCategory(category): VimConfigKey[]
81
+ ```
82
+
83
+ ### 5. Updated Motion Implementations
84
+
85
+ Motion classes now respect `whichwrap` configuration:
86
+
87
+ ```typescript
88
+ // h, l, Backspace, ArrowLeft, ArrowRight all check whichwrap
89
+ function canWrap(state: State, key: 'h' | 'l' | 'b' | 's' | '<' | '>'): boolean {
90
+ const whichwrap = state.configManager?.get('whichwrap') ?? 'h,l';
91
+ const allowed = whichwrap.split(',').map(s => s.trim());
92
+ return allowed.includes(key);
93
+ }
94
+ ```
95
+
96
+ ### 6. Integrated ConfigManager into State
97
+
98
+ ```typescript
99
+ export class State {
100
+ constructor(
101
+ // ... existing properties ...
102
+ public configManager: ConfigManager | null = null
103
+ ) {}
104
+ }
105
+
106
+ // Initialized in createEmptyState()
107
+ ```
108
+
109
+ ### 7. Enhanced Web Demo Config Panel
110
+
111
+ Updated `examples/web/public/app.tsx`:
112
+
113
+ - Added motion behavior section
114
+ - Marked options that differ from Vim with `*`
115
+ - Added string input fields for `whichwrap` and `virtualedit`
116
+ - Reorganized options by category
117
+ - Added notice: "🔧 Options marked with * differ from vanilla Vim defaults"
118
+
119
+ ### 8. Created Comprehensive Documentation
120
+
121
+ **`docs/vim-compatibility.md`**:
122
+ - Configuration system overview
123
+ - All differences from Vim explained
124
+ - Rationale for each difference
125
+ - Code examples for configuration
126
+ - Pure Vim mode setup
127
+ - Runtime configuration with `:set`
128
+ - Configuration change listeners
129
+ - Complete reference table
130
+
131
+ ## Options That Differ from Vim
132
+
133
+ | Option | vim-sim | Vim | Reason |
134
+ |--------|---------|-----|--------|
135
+ | `whichwrap` | "h,l" | "b,s" | Modern UX: h/l wrapping expected by new users |
136
+ | `tabstop` | 4 | 8 | Modern code style: 4-space indentation standard |
137
+ | `shiftwidth` | 2 | 8 | Web development: 2-space indentation common |
138
+ | `expandtab` | true | false | Consistency: spaces prevent tab/space mixing |
139
+ | `autoindent` | true | false | Expected behavior in modern editors |
140
+ | `hlsearch` | true | false | Visibility: highlighting improves usability |
141
+ | `incsearch` | true | false | Feedback: incremental search is more intuitive |
142
+
143
+ **Total**: 7 out of 18 options (38.9%) differ from Vim
144
+
145
+ ## Usage Examples
146
+
147
+ ### Check Differences
148
+
149
+ ```typescript
150
+ import {Session} from 'vim-sim';
151
+
152
+ const session = new Session();
153
+ const diffs = session.configManager.getDifferencesFromVim();
154
+ // ['whichwrap', 'tabstop', 'shiftwidth', 'expandtab', 'autoindent', 'hlsearch', 'incsearch']
155
+ ```
156
+
157
+ ### Switch to Pure Vim Mode
158
+
159
+ ```typescript
160
+ import {CONFIG_METADATA} from 'vim-sim';
161
+
162
+ const vimDefaults = Object.fromEntries(
163
+ Object.entries(CONFIG_METADATA).map(([key, meta]) => [key, meta.vimDefault])
164
+ );
165
+ session.configManager.setMultiple(vimDefaults);
166
+ ```
167
+
168
+ ### Query Option Metadata
169
+
170
+ ```typescript
171
+ import {CONFIG_METADATA} from 'vim-sim';
172
+
173
+ const meta = CONFIG_METADATA.whichwrap;
174
+ console.log(meta.description);
175
+ // "Keys that wrap to prev/next line (b=<BS>, s=<Space>, h=h, l=l, <=<Left>, >=<Right>)"
176
+
177
+ console.log(`Vim: ${meta.vimDefault}, vim-sim: ${meta.vimSimDefault}`);
178
+ // "Vim: b,s, vim-sim: h,l"
179
+ ```
180
+
181
+ ## Testing
182
+
183
+ - All existing tests pass ✅
184
+ - Default `whichwrap: "h,l"` maintains current behavior
185
+ - Tests reflect vim-sim defaults, not vanilla Vim defaults
186
+ - Behavior is now configurable without code changes
187
+
188
+ ## Files Changed
189
+
190
+ 1. **src/core/config-manager.ts** - Added options, metadata, helper methods
191
+ 2. **src/core/state.ts** - Added configManager property
192
+ 3. **src/motions/basic.ts** - Respect whichwrap configuration
193
+ 4. **src/index.ts** - Export CONFIG_METADATA
194
+ 5. **examples/web/public/app.tsx** - Enhanced config panel
195
+ 6. **docs/vim-compatibility.md** - Comprehensive documentation
196
+ 7. **docs/config-system-improvements.md** - This document
197
+
198
+ ## Benefits
199
+
200
+ 1. **Transparency**: Users can see exactly which options differ from Vim
201
+ 2. **Flexibility**: Easy switching between vim-sim and Vim behavior
202
+ 3. **Discoverability**: Metadata makes options self-documenting
203
+ 4. **Maintainability**: All defaults centralized and documented
204
+ 5. **User Experience**: Sensible defaults for modern users, pure Vim mode available
205
+ 6. **Programmatic Access**: UI can auto-generate config panels from metadata
206
+
207
+ ## Next Steps
208
+
209
+ 1. Add more Vim options (`scrolloff`, `timeoutlen`, `mouse`, etc.)
210
+ 2. Implement `:set` command parsing for all option types
211
+ 3. Add config presets (Vim mode, Modern mode, VSCode-like, etc.)
212
+ 4. Add config export/import functionality
213
+ 5. Create migration guide for users transitioning from Vim
214
+ 6. Add telemetry to track which options users customize most
215
+
216
+ ## Related
217
+
218
+ - Original issue: h/l wrapping differs from Vim
219
+ - Test suite review findings
220
+ - Vim documentation: `vim_specs/options.txt`
221
+ - Reference: `vim_specs/motion.txt` (whichwrap behavior)
@@ -0,0 +1,246 @@
1
+ # Vim Compatibility & Configuration
2
+
3
+ vim-sim aims to be a faithful Vim implementation while providing sensible defaults for modern development. This document explains how vim-sim's defaults differ from vanilla Vim and how to configure behavior.
4
+
5
+ ## Philosophy
6
+
7
+ vim-sim follows these principles:
8
+
9
+ 1. **Configurable by default** - All behavior differences are controlled through the config system
10
+ 2. **Modern defaults** - Default settings optimized for modern workflows
11
+ 3. **Vim compatibility mode** - Easy switching to pure Vim behavior
12
+ 4. **Clear documentation** - All differences are documented and marked
13
+
14
+ ## Configuration System
15
+
16
+ vim-sim uses a comprehensive configuration system that mirrors Vim's options:
17
+
18
+ ```typescript
19
+ import {Session, ConfigManager, CONFIG_METADATA} from 'vim-sim';
20
+
21
+ const session = new Session();
22
+
23
+ // Get current config
24
+ const config = session.configManager.getAll();
25
+
26
+ // Set individual options
27
+ session.configManager.set('whichwrap', 'b,s'); // Vim default
28
+ session.configManager.set('whichwrap', 'h,l'); // vim-sim default
29
+
30
+ // Set multiple options
31
+ session.configManager.setMultiple({
32
+ number: true,
33
+ relativenumber: true,
34
+ expandtab: false, // Use tabs instead of spaces
35
+ });
36
+
37
+ // Check which options differ from Vim
38
+ const differences = session.configManager.getDifferencesFromVim();
39
+ console.log('Options that differ from Vim:', differences);
40
+
41
+ // Get metadata about an option
42
+ const metadata = session.configManager.getMetadata('whichwrap');
43
+ console.log(metadata.description);
44
+ console.log('Vim default:', metadata.vimDefault);
45
+ console.log('vim-sim default:', metadata.vimSimDefault);
46
+ ```
47
+
48
+ ## Key Differences from Vanilla Vim
49
+
50
+ ### Motion Behavior
51
+
52
+ #### `whichwrap` (Default: `"h,l"` | Vim: `"b,s"`)
53
+
54
+ **vim-sim default**: The `h` and `l` keys wrap to the previous/next line at line boundaries.
55
+
56
+ **Vim default**: Only `<BS>` and `<Space>` wrap; `h` and `l` stop at line boundaries.
57
+
58
+ **Rationale**: Modern users expect horizontal navigation to wrap across lines, similar to arrow keys in most editors. This makes vim-sim more intuitive for new users while remaining easily configurable.
59
+
60
+ **To use Vim behavior**:
61
+ ```typescript
62
+ session.configManager.set('whichwrap', 'b,s');
63
+ ```
64
+
65
+ **Available values**:
66
+ - `b` - `<BS>` wraps in Normal and Visual mode
67
+ - `s` - `<Space>` wraps in Normal and Visual mode
68
+ - `h` - `h` wraps in Normal and Visual mode (vim-sim default includes this)
69
+ - `l` - `l` wraps in Normal and Visual mode (vim-sim default includes this)
70
+ - `<` - `<Left>` wraps in Normal and Visual mode
71
+ - `>` - `<Right>` wraps in Normal and Visual mode
72
+ - `[` - `<Left>` wraps in Insert and Replace mode
73
+ - `]` - `<Right>` wraps in Insert and Replace mode
74
+
75
+ Combine with commas: `"h,l,<,>"` allows h, l, and arrow keys to wrap.
76
+
77
+ ### Indentation
78
+
79
+ #### `tabstop` (Default: `4` | Vim: `8`)
80
+
81
+ **Rationale**: Modern code styles typically use 4-space indentation rather than 8.
82
+
83
+ #### `shiftwidth` (Default: `2` | Vim: `8`)
84
+
85
+ **Rationale**: 2-space indentation is common in JavaScript, TypeScript, and web development.
86
+
87
+ #### `expandtab` (Default: `true` | Vim: `false`)
88
+
89
+ **Rationale**: Spaces are more consistent across editors and environments. This prevents tab/space mixing issues.
90
+
91
+ #### `autoindent` (Default: `true` | Vim: `false`)
92
+
93
+ **Rationale**: Auto-indentation is expected behavior in modern editors.
94
+
95
+ ### Search
96
+
97
+ #### `hlsearch` (Default: `true` | Vim: `false`)
98
+
99
+ **Rationale**: Highlighting search matches improves visibility and usability.
100
+
101
+ #### `incsearch` (Default: `true` | Vim: `false`)
102
+
103
+ **Rationale**: Incremental search provides immediate feedback, improving the search experience.
104
+
105
+ ## Pure Vim Mode
106
+
107
+ To configure vim-sim with vanilla Vim defaults:
108
+
109
+ ```typescript
110
+ const vimDefaults = {
111
+ // Motion behavior
112
+ whichwrap: 'b,s',
113
+ startofline: true,
114
+ virtualedit: '',
115
+
116
+ // Indentation
117
+ tabstop: 8,
118
+ shiftwidth: 8,
119
+ expandtab: false,
120
+ autoindent: false,
121
+ smartindent: false,
122
+
123
+ // Search
124
+ hlsearch: false,
125
+ incsearch: false,
126
+ wrapscan: true,
127
+ ignorecase: false,
128
+ smartcase: false,
129
+
130
+ // Display
131
+ number: false,
132
+ relativenumber: false,
133
+ wrap: true,
134
+ cursorline: false,
135
+
136
+ // Editing
137
+ undolevels: 1000,
138
+ clipboard: '',
139
+ };
140
+
141
+ session.configManager.setMultiple(vimDefaults);
142
+ ```
143
+
144
+ Or use the convenience helper:
145
+
146
+ ```typescript
147
+ import {CONFIG_METADATA} from 'vim-sim';
148
+
149
+ // Set all options to their Vim defaults
150
+ const vimDefaults = Object.fromEntries(
151
+ Object.entries(CONFIG_METADATA).map(([key, meta]) => [key, meta.vimDefault])
152
+ );
153
+ session.configManager.setMultiple(vimDefaults);
154
+ ```
155
+
156
+ ## Configuration Metadata
157
+
158
+ Every config option includes metadata accessible via `CONFIG_METADATA`:
159
+
160
+ ```typescript
161
+ import {CONFIG_METADATA} from 'vim-sim';
162
+
163
+ const option = CONFIG_METADATA.whichwrap;
164
+
165
+ console.log(option.description); // Full description
166
+ console.log(option.vimDefault); // Vim's default value
167
+ console.log(option.vimSimDefault); // vim-sim's default value
168
+ console.log(option.category); // Option category
169
+ console.log(option.type); // Value type
170
+ console.log(option.differsFromVim); // true if defaults differ
171
+ console.log(option.validValues); // Array of valid values (for strings)
172
+ ```
173
+
174
+ ## Runtime Configuration
175
+
176
+ Options can be changed at runtime using `:set` commands (in command mode):
177
+
178
+ ```
179
+ :set number " Enable line numbers
180
+ :set nonumber " Disable line numbers
181
+ :set tabstop=4 " Set tab stop to 4
182
+ :set whichwrap=h,l " Allow h and l to wrap
183
+ ```
184
+
185
+ ## Listening to Configuration Changes
186
+
187
+ Subscribe to configuration changes:
188
+
189
+ ```typescript
190
+ // Listen to specific option
191
+ const unsubscribe = session.configManager.onChange('number', (key, value) => {
192
+ console.log(`${key} changed to ${value}`);
193
+ // Update UI, refresh display, etc.
194
+ });
195
+
196
+ // Listen to all changes
197
+ session.configManager.onChange('*', (key, value) => {
198
+ console.log(`Any option changed: ${key} = ${value}`);
199
+ });
200
+
201
+ // Unsubscribe when done
202
+ unsubscribe();
203
+ ```
204
+
205
+ ## Reference: All Options
206
+
207
+ | Option | Category | Type | vim-sim | Vim | Differs |
208
+ |--------|----------|------|---------|-----|---------|
209
+ | `number` | display | boolean | false | false | ❌ |
210
+ | `relativenumber` | display | boolean | false | false | ❌ |
211
+ | `wrap` | display | boolean | true | true | ❌ |
212
+ | `cursorline` | display | boolean | false | false | ❌ |
213
+ | `tabstop` | indentation | number | 4 | 8 | ✅ |
214
+ | `shiftwidth` | indentation | number | 2 | 8 | ✅ |
215
+ | `expandtab` | indentation | boolean | true | false | ✅ |
216
+ | `autoindent` | indentation | boolean | true | false | ✅ |
217
+ | `smartindent` | indentation | boolean | false | false | ❌ |
218
+ | `ignorecase` | search | boolean | false | false | ❌ |
219
+ | `smartcase` | search | boolean | false | false | ❌ |
220
+ | `hlsearch` | search | boolean | true | false | ✅ |
221
+ | `incsearch` | search | boolean | true | false | ✅ |
222
+ | `wrapscan` | search | boolean | true | true | ❌ |
223
+ | `whichwrap` | motion | string | "h,l" | "b,s" | ✅ |
224
+ | `startofline` | motion | boolean | true | true | ❌ |
225
+ | `virtualedit` | motion | string | "" | "" | ❌ |
226
+ | `undolevels` | editing | number | 1000 | 1000 | ❌ |
227
+ | `clipboard` | editing | string | "" | "" | ❌ |
228
+
229
+ **Total**: 8 options differ from vanilla Vim (marked with ✅)
230
+
231
+ ## Future Options
232
+
233
+ Planned options for future releases:
234
+
235
+ - `scrolloff` - Lines of context around cursor
236
+ - `sidescroll` - Columns to scroll horizontally
237
+ - `timeoutlen` - Time to wait for key sequence
238
+ - `mouse` - Mouse support
239
+ - `background` - Dark or light background
240
+ - And more...
241
+
242
+ ## See Also
243
+
244
+ - [Official Vim Documentation](../vim_specs/) - Complete Vim option reference
245
+ - [vim_specs/options.txt](../vim_specs/options.txt) - All Vim options
246
+ - [vim_specs/motion.txt](../vim_specs/motion.txt) - Motion behavior documentation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vim-sim",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "A complete Vim editor simulation engine for Node.js with 85%+ test coverage. Implements motions, operators, visual mode, text objects, macros, marks, undo/redo tree, spell checking, and more.",
5
5
  "keywords": [
6
6
  "vim",