vimlm 0.0.6__tar.gz → 0.0.7__tar.gz

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.
vimlm-0.0.7/PKG-INFO ADDED
@@ -0,0 +1,204 @@
1
+ Metadata-Version: 2.2
2
+ Name: vimlm
3
+ Version: 0.0.7
4
+ Summary: VimLM - LLM-powered Vim assistant
5
+ Home-page: https://github.com/JosefAlbers/vimlm
6
+ Author: Josef Albers
7
+ Author-email: albersj66@gmail.com
8
+ Requires-Python: >=3.12.8
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: nanollama==0.0.5
12
+ Requires-Dist: mlx_lm_utils==0.0.2
13
+ Requires-Dist: watchfiles==1.0.4
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: home-page
19
+ Dynamic: requires-dist
20
+ Dynamic: requires-python
21
+ Dynamic: summary
22
+
23
+
24
+ # VimLM - Local LLM-Powered Coding Assistant for Vim
25
+
26
+ ![vimlm](https://raw.githubusercontent.com/JosefAlbers/VimLM/main/assets/captioned_vimlm.gif)
27
+
28
+ LLM-powered coding companion for Vim, inspired by GitHub Copilot/Cursor. Integrates contextual code understanding, summarization, and AI assistance directly into your Vim workflow.
29
+
30
+ ## Features
31
+
32
+ - **Model Agnostic** - Use any MLX-compatible model via a configuration file
33
+ - **Vim-Native UX** - Intuitive keybindings and split-window responses
34
+ - **Deep Context** - Understands code context from:
35
+ - Current file
36
+ - Visual selections
37
+ - Referenced files
38
+ - Project directory structure
39
+ - **Conversational Coding** - Iterative refinement with follow-up queries
40
+ - **Air-Gapped Security** - 100% offline - no APIs, no tracking, no data leaks
41
+
42
+ ## Requirements
43
+
44
+ - Apple M-series chip
45
+ - Python 3.12.8
46
+
47
+ ## Quick Start
48
+
49
+ ```zsh
50
+ pip install vimlm
51
+ vimlm
52
+ ```
53
+
54
+ ## Basic Usage
55
+
56
+ ### 1. **From Normal Mode**
57
+ **`Ctrl-l`**: Add current line + file to context
58
+
59
+ *Example prompt:* `"Regex for removing HTML tags from item.content"`
60
+
61
+ ### 2. **From Visual Mode**
62
+ Select code → **`Ctrl-l`**: Add selected block + current file to context
63
+
64
+ *Example prompt:* `"Convert this to async/await syntax"`
65
+
66
+ ### 3. **Follow-Up Conversations**
67
+ **`Ctrl-j`**: Continue current thread
68
+
69
+ *Example follow-up:* `"Use Manifest V3 instead"`
70
+
71
+ ### 4. **Code Extraction & Replacement**
72
+ **`Ctrl-p`**: Insert code blocks from response into:
73
+ - Last visual selection (Normal mode)
74
+ - Active selection (Visual mode)
75
+
76
+ **Workflow Example**:
77
+ 1. Select a block of code in Visual mode
78
+ 2. Prompt with `Ctrl-l`: `"Convert this to async/await syntax"`
79
+ 3. Press `Ctrl-p` to replace selection with generated code
80
+
81
+ ### 5. **Inline Commands**
82
+
83
+ #### `!include` - Add External Context
84
+ ```text
85
+ !include [PATH] # Add files/folders to context
86
+ ```
87
+ - **`!include`** (no path): Current folder
88
+ - **`!include ~/projects/utils.py`**: Specific file
89
+ - **`!include ~/docs/api-specs/`**: Entire folder
90
+
91
+ *Example:* `"AJAX-ify this app !include ~/scrap/hypermedia-applications.summ.md"`
92
+
93
+ #### `!deploy` - Generate Project Files
94
+ ```text
95
+ !deploy [DEST_DIR] # Extract code blocks to directory
96
+ ```
97
+ - **`!deploy`** (no path): Current directory
98
+ - **`!deploy ./src`**: Specific directory
99
+
100
+ *Example:* `"Create REST API endpoint !deploy ./api"`
101
+
102
+ #### `!continue` - Resume Generation
103
+ ```text
104
+ !continue [MAX_TOKENS] # Continue stopped response
105
+ ```
106
+ - **`!continue`**: Default 2000 tokens
107
+ - **`!continue 3000`**: Custom token limit
108
+
109
+ *Example:* `"tl;dr !include large-file.txt !continue 5000"`
110
+
111
+ #### `!followup` - Thread Continuation
112
+ ```text
113
+ !followup # Equivalent to Ctrl-j
114
+ ```
115
+ *Example:*
116
+
117
+ Initial: `"Create Chrome extension"`
118
+
119
+ Follow-up: `"Add dark mode support !followup"`
120
+
121
+ #### **Command Combinations**
122
+ Chain multiple commands in one prompt:
123
+ ```text
124
+ "Create HTMX component !include ~/lib/styles.css !deploy ./components !continue 4000"
125
+ ```
126
+
127
+ ### 6. **Command-Line Mode `:VimLM`**
128
+ ```vim
129
+ :VimLM "prompt" [!command1] [!command2]...
130
+ ```
131
+ Use predefined command chains for repetitive tasks:
132
+
133
+ **Example 1 – CI/CD Fixer Macro**:
134
+ ```vim
135
+ " Debug CI failures using error logs
136
+ :VimLM Fix Dockerfile !include .gitlab-ci.yml !include $(tail -n 20 ci.log)
137
+ ```
138
+
139
+ **Example 2 – Test Generation Workflow**:
140
+ ```vim
141
+ " Generate unit tests for selected functions and save to test/
142
+ :VimLM Write pytest tests for this !include ./src !deploy ./test
143
+ ```
144
+
145
+ **Example 3 – Documentation Helper**:
146
+ ```vim
147
+ " Add docstrings to all Python functions in file
148
+ :VimLM Add Google-style docstrings !include % !continue 4000
149
+ ```
150
+
151
+ ### Key Bindings
152
+
153
+ | Binding | Mode | Action |
154
+ |------------|---------------|----------------------------------------|
155
+ | `Ctrl-l` | Normal/Visual | Send current file + selection to LLM |
156
+ | `Ctrl-j` | Normal | Continue conversation |
157
+ | `Ctrl-p` | Normal/Visual | Replace the selection with generated code |
158
+ | `Esc` | Prompt | Cancel input |
159
+
160
+ ## Advanced Configuration
161
+ VimLM uses a JSON config file with the following configurable parameters:
162
+ ```json
163
+ {
164
+ "LLM_MODEL": null,
165
+ "NUM_TOKEN": 2000,
166
+ "USE_LEADER": false,
167
+ "KEY_MAP": {},
168
+ "DO_RESET": true,
169
+ "SHOW_USER": false,
170
+ "SEP_CMD": "!",
171
+ "VERSION": "0.0.7",
172
+ "DEBUG": true
173
+ }
174
+ ```
175
+ ### Custom Model Setup
176
+ 1. **Browse models**: [MLX Community Models on Hugging Face](https://huggingface.co/mlx-community)
177
+ 2. **Edit config file**:
178
+ ```json
179
+ {
180
+ "LLM_MODEL": "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit",
181
+ "NUM_TOKEN": 9999
182
+ }
183
+ ```
184
+ 3. **Save to**: `~/vimlm/cfg.json`
185
+ 4. **Restart VimLM**
186
+
187
+ ### Custom Key Bindings
188
+ You can also configure shortcuts:
189
+ ```json
190
+ {
191
+ "USE_LEADER": true, // Swap Ctrl for Leader key
192
+ "KEY_MAP": { // Remap default keys (l/j/p)
193
+ "l": "a", // <Leader>a instead of <Leader>l
194
+ "j": "s", // <Leader>s instead of <Leader>j
195
+ "p": "d" // <Leader>d instead of <Leader>p
196
+ }
197
+ }
198
+ ```
199
+
200
+ ## License
201
+
202
+ VimLM is licensed under the [Apache-2.0 license](LICENSE).
203
+
204
+
vimlm-0.0.7/README.md ADDED
@@ -0,0 +1,182 @@
1
+
2
+ # VimLM - Local LLM-Powered Coding Assistant for Vim
3
+
4
+ ![vimlm](https://raw.githubusercontent.com/JosefAlbers/VimLM/main/assets/captioned_vimlm.gif)
5
+
6
+ LLM-powered coding companion for Vim, inspired by GitHub Copilot/Cursor. Integrates contextual code understanding, summarization, and AI assistance directly into your Vim workflow.
7
+
8
+ ## Features
9
+
10
+ - **Model Agnostic** - Use any MLX-compatible model via a configuration file
11
+ - **Vim-Native UX** - Intuitive keybindings and split-window responses
12
+ - **Deep Context** - Understands code context from:
13
+ - Current file
14
+ - Visual selections
15
+ - Referenced files
16
+ - Project directory structure
17
+ - **Conversational Coding** - Iterative refinement with follow-up queries
18
+ - **Air-Gapped Security** - 100% offline - no APIs, no tracking, no data leaks
19
+
20
+ ## Requirements
21
+
22
+ - Apple M-series chip
23
+ - Python 3.12.8
24
+
25
+ ## Quick Start
26
+
27
+ ```zsh
28
+ pip install vimlm
29
+ vimlm
30
+ ```
31
+
32
+ ## Basic Usage
33
+
34
+ ### 1. **From Normal Mode**
35
+ **`Ctrl-l`**: Add current line + file to context
36
+
37
+ *Example prompt:* `"Regex for removing HTML tags from item.content"`
38
+
39
+ ### 2. **From Visual Mode**
40
+ Select code → **`Ctrl-l`**: Add selected block + current file to context
41
+
42
+ *Example prompt:* `"Convert this to async/await syntax"`
43
+
44
+ ### 3. **Follow-Up Conversations**
45
+ **`Ctrl-j`**: Continue current thread
46
+
47
+ *Example follow-up:* `"Use Manifest V3 instead"`
48
+
49
+ ### 4. **Code Extraction & Replacement**
50
+ **`Ctrl-p`**: Insert code blocks from response into:
51
+ - Last visual selection (Normal mode)
52
+ - Active selection (Visual mode)
53
+
54
+ **Workflow Example**:
55
+ 1. Select a block of code in Visual mode
56
+ 2. Prompt with `Ctrl-l`: `"Convert this to async/await syntax"`
57
+ 3. Press `Ctrl-p` to replace selection with generated code
58
+
59
+ ### 5. **Inline Commands**
60
+
61
+ #### `!include` - Add External Context
62
+ ```text
63
+ !include [PATH] # Add files/folders to context
64
+ ```
65
+ - **`!include`** (no path): Current folder
66
+ - **`!include ~/projects/utils.py`**: Specific file
67
+ - **`!include ~/docs/api-specs/`**: Entire folder
68
+
69
+ *Example:* `"AJAX-ify this app !include ~/scrap/hypermedia-applications.summ.md"`
70
+
71
+ #### `!deploy` - Generate Project Files
72
+ ```text
73
+ !deploy [DEST_DIR] # Extract code blocks to directory
74
+ ```
75
+ - **`!deploy`** (no path): Current directory
76
+ - **`!deploy ./src`**: Specific directory
77
+
78
+ *Example:* `"Create REST API endpoint !deploy ./api"`
79
+
80
+ #### `!continue` - Resume Generation
81
+ ```text
82
+ !continue [MAX_TOKENS] # Continue stopped response
83
+ ```
84
+ - **`!continue`**: Default 2000 tokens
85
+ - **`!continue 3000`**: Custom token limit
86
+
87
+ *Example:* `"tl;dr !include large-file.txt !continue 5000"`
88
+
89
+ #### `!followup` - Thread Continuation
90
+ ```text
91
+ !followup # Equivalent to Ctrl-j
92
+ ```
93
+ *Example:*
94
+
95
+ Initial: `"Create Chrome extension"`
96
+
97
+ Follow-up: `"Add dark mode support !followup"`
98
+
99
+ #### **Command Combinations**
100
+ Chain multiple commands in one prompt:
101
+ ```text
102
+ "Create HTMX component !include ~/lib/styles.css !deploy ./components !continue 4000"
103
+ ```
104
+
105
+ ### 6. **Command-Line Mode `:VimLM`**
106
+ ```vim
107
+ :VimLM "prompt" [!command1] [!command2]...
108
+ ```
109
+ Use predefined command chains for repetitive tasks:
110
+
111
+ **Example 1 – CI/CD Fixer Macro**:
112
+ ```vim
113
+ " Debug CI failures using error logs
114
+ :VimLM Fix Dockerfile !include .gitlab-ci.yml !include $(tail -n 20 ci.log)
115
+ ```
116
+
117
+ **Example 2 – Test Generation Workflow**:
118
+ ```vim
119
+ " Generate unit tests for selected functions and save to test/
120
+ :VimLM Write pytest tests for this !include ./src !deploy ./test
121
+ ```
122
+
123
+ **Example 3 – Documentation Helper**:
124
+ ```vim
125
+ " Add docstrings to all Python functions in file
126
+ :VimLM Add Google-style docstrings !include % !continue 4000
127
+ ```
128
+
129
+ ### Key Bindings
130
+
131
+ | Binding | Mode | Action |
132
+ |------------|---------------|----------------------------------------|
133
+ | `Ctrl-l` | Normal/Visual | Send current file + selection to LLM |
134
+ | `Ctrl-j` | Normal | Continue conversation |
135
+ | `Ctrl-p` | Normal/Visual | Replace the selection with generated code |
136
+ | `Esc` | Prompt | Cancel input |
137
+
138
+ ## Advanced Configuration
139
+ VimLM uses a JSON config file with the following configurable parameters:
140
+ ```json
141
+ {
142
+ "LLM_MODEL": null,
143
+ "NUM_TOKEN": 2000,
144
+ "USE_LEADER": false,
145
+ "KEY_MAP": {},
146
+ "DO_RESET": true,
147
+ "SHOW_USER": false,
148
+ "SEP_CMD": "!",
149
+ "VERSION": "0.0.7",
150
+ "DEBUG": true
151
+ }
152
+ ```
153
+ ### Custom Model Setup
154
+ 1. **Browse models**: [MLX Community Models on Hugging Face](https://huggingface.co/mlx-community)
155
+ 2. **Edit config file**:
156
+ ```json
157
+ {
158
+ "LLM_MODEL": "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit",
159
+ "NUM_TOKEN": 9999
160
+ }
161
+ ```
162
+ 3. **Save to**: `~/vimlm/cfg.json`
163
+ 4. **Restart VimLM**
164
+
165
+ ### Custom Key Bindings
166
+ You can also configure shortcuts:
167
+ ```json
168
+ {
169
+ "USE_LEADER": true, // Swap Ctrl for Leader key
170
+ "KEY_MAP": { // Remap default keys (l/j/p)
171
+ "l": "a", // <Leader>a instead of <Leader>l
172
+ "j": "s", // <Leader>s instead of <Leader>j
173
+ "p": "d" // <Leader>d instead of <Leader>p
174
+ }
175
+ }
176
+ ```
177
+
178
+ ## License
179
+
180
+ VimLM is licensed under the [Apache-2.0 license](LICENSE).
181
+
182
+
@@ -5,7 +5,7 @@ with open("requirements.txt") as f:
5
5
 
6
6
  setup(
7
7
  name="vimlm",
8
- version="0.0.6",
8
+ version="0.0.7",
9
9
  author="Josef Albers",
10
10
  author_email="albersj66@gmail.com",
11
11
  readme='README.md',
@@ -0,0 +1,204 @@
1
+ Metadata-Version: 2.2
2
+ Name: vimlm
3
+ Version: 0.0.7
4
+ Summary: VimLM - LLM-powered Vim assistant
5
+ Home-page: https://github.com/JosefAlbers/vimlm
6
+ Author: Josef Albers
7
+ Author-email: albersj66@gmail.com
8
+ Requires-Python: >=3.12.8
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: nanollama==0.0.5
12
+ Requires-Dist: mlx_lm_utils==0.0.2
13
+ Requires-Dist: watchfiles==1.0.4
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: home-page
19
+ Dynamic: requires-dist
20
+ Dynamic: requires-python
21
+ Dynamic: summary
22
+
23
+
24
+ # VimLM - Local LLM-Powered Coding Assistant for Vim
25
+
26
+ ![vimlm](https://raw.githubusercontent.com/JosefAlbers/VimLM/main/assets/captioned_vimlm.gif)
27
+
28
+ LLM-powered coding companion for Vim, inspired by GitHub Copilot/Cursor. Integrates contextual code understanding, summarization, and AI assistance directly into your Vim workflow.
29
+
30
+ ## Features
31
+
32
+ - **Model Agnostic** - Use any MLX-compatible model via a configuration file
33
+ - **Vim-Native UX** - Intuitive keybindings and split-window responses
34
+ - **Deep Context** - Understands code context from:
35
+ - Current file
36
+ - Visual selections
37
+ - Referenced files
38
+ - Project directory structure
39
+ - **Conversational Coding** - Iterative refinement with follow-up queries
40
+ - **Air-Gapped Security** - 100% offline - no APIs, no tracking, no data leaks
41
+
42
+ ## Requirements
43
+
44
+ - Apple M-series chip
45
+ - Python 3.12.8
46
+
47
+ ## Quick Start
48
+
49
+ ```zsh
50
+ pip install vimlm
51
+ vimlm
52
+ ```
53
+
54
+ ## Basic Usage
55
+
56
+ ### 1. **From Normal Mode**
57
+ **`Ctrl-l`**: Add current line + file to context
58
+
59
+ *Example prompt:* `"Regex for removing HTML tags from item.content"`
60
+
61
+ ### 2. **From Visual Mode**
62
+ Select code → **`Ctrl-l`**: Add selected block + current file to context
63
+
64
+ *Example prompt:* `"Convert this to async/await syntax"`
65
+
66
+ ### 3. **Follow-Up Conversations**
67
+ **`Ctrl-j`**: Continue current thread
68
+
69
+ *Example follow-up:* `"Use Manifest V3 instead"`
70
+
71
+ ### 4. **Code Extraction & Replacement**
72
+ **`Ctrl-p`**: Insert code blocks from response into:
73
+ - Last visual selection (Normal mode)
74
+ - Active selection (Visual mode)
75
+
76
+ **Workflow Example**:
77
+ 1. Select a block of code in Visual mode
78
+ 2. Prompt with `Ctrl-l`: `"Convert this to async/await syntax"`
79
+ 3. Press `Ctrl-p` to replace selection with generated code
80
+
81
+ ### 5. **Inline Commands**
82
+
83
+ #### `!include` - Add External Context
84
+ ```text
85
+ !include [PATH] # Add files/folders to context
86
+ ```
87
+ - **`!include`** (no path): Current folder
88
+ - **`!include ~/projects/utils.py`**: Specific file
89
+ - **`!include ~/docs/api-specs/`**: Entire folder
90
+
91
+ *Example:* `"AJAX-ify this app !include ~/scrap/hypermedia-applications.summ.md"`
92
+
93
+ #### `!deploy` - Generate Project Files
94
+ ```text
95
+ !deploy [DEST_DIR] # Extract code blocks to directory
96
+ ```
97
+ - **`!deploy`** (no path): Current directory
98
+ - **`!deploy ./src`**: Specific directory
99
+
100
+ *Example:* `"Create REST API endpoint !deploy ./api"`
101
+
102
+ #### `!continue` - Resume Generation
103
+ ```text
104
+ !continue [MAX_TOKENS] # Continue stopped response
105
+ ```
106
+ - **`!continue`**: Default 2000 tokens
107
+ - **`!continue 3000`**: Custom token limit
108
+
109
+ *Example:* `"tl;dr !include large-file.txt !continue 5000"`
110
+
111
+ #### `!followup` - Thread Continuation
112
+ ```text
113
+ !followup # Equivalent to Ctrl-j
114
+ ```
115
+ *Example:*
116
+
117
+ Initial: `"Create Chrome extension"`
118
+
119
+ Follow-up: `"Add dark mode support !followup"`
120
+
121
+ #### **Command Combinations**
122
+ Chain multiple commands in one prompt:
123
+ ```text
124
+ "Create HTMX component !include ~/lib/styles.css !deploy ./components !continue 4000"
125
+ ```
126
+
127
+ ### 6. **Command-Line Mode `:VimLM`**
128
+ ```vim
129
+ :VimLM "prompt" [!command1] [!command2]...
130
+ ```
131
+ Use predefined command chains for repetitive tasks:
132
+
133
+ **Example 1 – CI/CD Fixer Macro**:
134
+ ```vim
135
+ " Debug CI failures using error logs
136
+ :VimLM Fix Dockerfile !include .gitlab-ci.yml !include $(tail -n 20 ci.log)
137
+ ```
138
+
139
+ **Example 2 – Test Generation Workflow**:
140
+ ```vim
141
+ " Generate unit tests for selected functions and save to test/
142
+ :VimLM Write pytest tests for this !include ./src !deploy ./test
143
+ ```
144
+
145
+ **Example 3 – Documentation Helper**:
146
+ ```vim
147
+ " Add docstrings to all Python functions in file
148
+ :VimLM Add Google-style docstrings !include % !continue 4000
149
+ ```
150
+
151
+ ### Key Bindings
152
+
153
+ | Binding | Mode | Action |
154
+ |------------|---------------|----------------------------------------|
155
+ | `Ctrl-l` | Normal/Visual | Send current file + selection to LLM |
156
+ | `Ctrl-j` | Normal | Continue conversation |
157
+ | `Ctrl-p` | Normal/Visual | Replace the selection with generated code |
158
+ | `Esc` | Prompt | Cancel input |
159
+
160
+ ## Advanced Configuration
161
+ VimLM uses a JSON config file with the following configurable parameters:
162
+ ```json
163
+ {
164
+ "LLM_MODEL": null,
165
+ "NUM_TOKEN": 2000,
166
+ "USE_LEADER": false,
167
+ "KEY_MAP": {},
168
+ "DO_RESET": true,
169
+ "SHOW_USER": false,
170
+ "SEP_CMD": "!",
171
+ "VERSION": "0.0.7",
172
+ "DEBUG": true
173
+ }
174
+ ```
175
+ ### Custom Model Setup
176
+ 1. **Browse models**: [MLX Community Models on Hugging Face](https://huggingface.co/mlx-community)
177
+ 2. **Edit config file**:
178
+ ```json
179
+ {
180
+ "LLM_MODEL": "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit",
181
+ "NUM_TOKEN": 9999
182
+ }
183
+ ```
184
+ 3. **Save to**: `~/vimlm/cfg.json`
185
+ 4. **Restart VimLM**
186
+
187
+ ### Custom Key Bindings
188
+ You can also configure shortcuts:
189
+ ```json
190
+ {
191
+ "USE_LEADER": true, // Swap Ctrl for Leader key
192
+ "KEY_MAP": { // Remap default keys (l/j/p)
193
+ "l": "a", // <Leader>a instead of <Leader>l
194
+ "j": "s", // <Leader>s instead of <Leader>j
195
+ "p": "d" // <Leader>d instead of <Leader>p
196
+ }
197
+ }
198
+ ```
199
+
200
+ ## License
201
+
202
+ VimLM is licensed under the [Apache-2.0 license](LICENSE).
203
+
204
+
@@ -26,13 +26,18 @@ from pathlib import Path
26
26
  from string import Template
27
27
  import re
28
28
 
29
- DEBUG = True
30
- LLM_MODEL = None # "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit"
31
- NUM_TOKEN = 2000
32
- SEP_CMD = '!'
33
- USE_LEADER = False
34
- DO_RESET = True
35
- SHOW_USER = False
29
+ DEFAULTS = dict(
30
+ LLM_MODEL = None, # "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit"
31
+ NUM_TOKEN = 2000,
32
+ USE_LEADER = False,
33
+ KEY_MAP = {},
34
+ DO_RESET = True,
35
+ SHOW_USER = False,
36
+ SEP_CMD = '!',
37
+ VERSION = '0.0.7',
38
+ DEBUG = True,
39
+ )
40
+
36
41
  VIMLM_DIR = os.path.expanduser("~/vimlm")
37
42
  WATCH_DIR = os.path.expanduser("~/vimlm/watch_dir")
38
43
  CFG_FILE = 'cfg.json'
@@ -45,6 +50,36 @@ LOG_PATH = os.path.join(VIMLM_DIR, LOG_FILE)
45
50
  LTM_PATH = os.path.join(VIMLM_DIR, LTM_FILE)
46
51
  OUT_PATH = os.path.join(WATCH_DIR, OUT_FILE)
47
52
 
53
+ def is_old(config):
54
+ v_str = config.get('VERSION', 0)
55
+ for min_v, usr_v in zip(DEFAULTS['VERSION'].split('.'), v_str.split('.')):
56
+ if int(min_v) < int(usr_v):
57
+ return False
58
+ elif int(min_v) > int(usr_v):
59
+ return True
60
+ return False
61
+
62
+ if os.path.exists(WATCH_DIR):
63
+ shutil.rmtree(WATCH_DIR)
64
+ os.makedirs(WATCH_DIR)
65
+
66
+ try:
67
+ with open(CFG_PATH, "r") as f:
68
+ config = json.load(f)
69
+ if is_old(config):
70
+ for p in [CFG_PATH, LOG_PATH, LTM_PATH]:
71
+ if os.path.isfile(p):
72
+ os.remove(p)
73
+ raise ValueError(f'Version mismatch')
74
+ except Exception as e:
75
+ print(e)
76
+ config = DEFAULTS
77
+ with open(CFG_PATH, 'w') as f:
78
+ json.dump(DEFAULTS, f, indent=2)
79
+
80
+ for k, v in DEFAULTS.items():
81
+ globals()[k] = config.get(k, v)
82
+
48
83
  def toout(s, key=None, mode=None):
49
84
  key = '' if key is None else ':'+key
50
85
  mode = 'w' if mode is None else mode
@@ -64,23 +99,6 @@ def tolog(log, key='debug'):
64
99
  with open(LOG_PATH, "w", encoding="utf-8") as log_f:
65
100
  json.dump(logs, log_f, indent=2)
66
101
 
67
- if os.path.exists(WATCH_DIR):
68
- shutil.rmtree(WATCH_DIR)
69
- os.makedirs(WATCH_DIR)
70
-
71
- try:
72
- with open(CFG_PATH, "r") as f:
73
- config = json.load(f)
74
- DEBUG = config.get("DEBUG", DEBUG)
75
- LLM_MODEL = config.get("LLM_MODEL", LLM_MODEL)
76
- NUM_TOKEN = config.get("NUM_TOKEN", NUM_TOKEN)
77
- SEP_CMD = config.get("SEP_CMD", SEP_CMD)
78
- USE_LEADER = config.get("USE_LEADER", USE_LEADER)
79
- except Exception as e:
80
- tolog(str(e))
81
- with open(CFG_PATH, 'w') as f:
82
- json.dump(dict(DEBUG=DEBUG, LLM_MODEL=LLM_MODEL, NUM_TOKEN=NUM_TOKEN, SEP_CMD=SEP_CMD, USE_LEADER=USE_LEADER), f, indent=2)
83
-
84
102
  toout('Loading LLM...')
85
103
  if LLM_MODEL is None:
86
104
  from nanollama import Chat
@@ -326,13 +344,27 @@ def process_command(data):
326
344
  data['include'] = ''
327
345
  for cmd in cmds:
328
346
  if cmd.startswith('include'):
329
- arg = cmd.removeprefix('include').strip('(').strip(')').strip().strip('"').strip("'").strip()
347
+ arg = cmd.removeprefix('include').strip().strip('(').strip(')').strip().strip('"').strip("'").strip()
330
348
  src = data['dir'] if len(arg) == 0 else arg
331
- data['include'] += ingest(src)
349
+ if arg == '%':
350
+ continue
351
+ if src.startswith('`') or src.startswith('$('):
352
+ shell_cmd = src.strip('`') if src.startswith('`') else src.strip('$()')
353
+ shell_cmd = shell_cmd.strip()
354
+ try:
355
+ result = subprocess.run(shell_cmd, shell=True, capture_output=True, text=True)
356
+ if result.returncode == 0:
357
+ data['include'] += f'--- **{shell_cmd}** ---\n```\n{result.stdout.strip()}\n```\n---\n\n'
358
+ else:
359
+ tolog(f'{shell_cmd} failed {result.stderr.strip()}')
360
+ except Exception as e:
361
+ tolog(f'Error executing {shell_cmd}: {e}')
362
+ else:
363
+ data['include'] += ingest(src)
332
364
 
333
365
  for cmd in cmds:
334
366
  if cmd.startswith('deploy'):
335
- arg = cmd.removeprefix('deploy').strip('(').strip(')').strip().strip('"').strip("'").strip()
367
+ arg = cmd.removeprefix('deploy').strip().strip('(').strip(')').strip().strip('"').strip("'").strip()
336
368
  if len(data['user_prompt']) == 0:
337
369
  deploy(dest=arg)
338
370
  data['user_prompt'] = ''
@@ -395,8 +427,10 @@ async def process_files(data):
395
427
  if 'deploy_dest' in data:
396
428
  deploy(dest=data['deploy_dest'], reformat=False)
397
429
 
398
- mapl, mapj, mapp = ('<Leader>l', '<Leader>j', '<Leader>p') if USE_LEADER else ('<C-l>', '<C-j>', '<C-p>')
399
-
430
+ KEYL = KEY_MAP.get('l', 'l')
431
+ KEYJ = KEY_MAP.get('j', 'j')
432
+ KEYP = KEY_MAP.get('p', 'p')
433
+ mapl, mapj, mapp = (f'<Leader>{KEYL}', f'<Leader>{KEYJ}', f'<Leader>{KEYP}') if USE_LEADER else (f'<C-{KEYL}>', f'<C-{KEYJ}>', f'<C-{KEYP}>')
400
434
  VIMLMSCRIPT = Template(r"""
401
435
  let s:register_names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u']
402
436
  let s:watched_dir = expand('$WATCH_DIR')
@@ -515,19 +549,26 @@ function! ExtractAllCodeBlocks()
515
549
  return len(code_blocks)
516
550
  endfunction
517
551
 
518
- function! PasteIntoLastVisualSelection()
552
+ function! PasteIntoLastVisualSelection(...)
519
553
  let num_blocks = ExtractAllCodeBlocks()
520
- echo "Extracted " . num_blocks . " blocks into registers @a-@" . s:register_names[num_blocks - 1] . ". Enter register name: "
521
- let register_name = nr2char(getchar())
554
+ if a:0 > 0
555
+ let register_name = a:1
556
+ else
557
+ echo "Extracted " . num_blocks . " blocks into registers @a-@" . s:register_names[num_blocks - 1] . ". Enter register name: "
558
+ let register_name = nr2char(getchar())
559
+ endif
560
+
522
561
  if register_name !~ '^[a-z]$'
523
562
  echoerr "Invalid register name. Please enter a single lowercase letter (e.g., a, b, c)."
524
563
  return
525
564
  endif
565
+
526
566
  let register_content = getreg(register_name)
527
567
  if register_content == ''
528
568
  echoerr "Register @" . register_name . " is empty."
529
569
  return
530
570
  endif
571
+
531
572
  let current_mode = mode()
532
573
  if current_mode == 'v' || current_mode == 'V' || current_mode == ''
533
574
  execute 'normal! "' . register_name . 'p'
@@ -537,6 +578,25 @@ function! PasteIntoLastVisualSelection()
537
578
  endif
538
579
  endfunction
539
580
 
581
+ function! VimLM(...) range
582
+ let user_input = join(a:000, ' ')
583
+ if empty(user_input)
584
+ echo "Usage: :VimLM <prompt> [!command1] [!command2] ..."
585
+ return
586
+ endif
587
+ if line("'<") == line("'>")
588
+ silent! execute "normal! V\<ESC>"
589
+ endif
590
+ silent execute "'<,'>w! " . s:watched_dir . "/yank"
591
+ silent execute "w! " . s:watched_dir . "/context"
592
+ let user_file = s:watched_dir . '/user'
593
+ call writefile([user_input], user_file, 'w')
594
+ let current_file = expand('%:p')
595
+ let tree_file = s:watched_dir . '/tree'
596
+ call writefile([current_file], tree_file, 'w')
597
+ endfunction
598
+
599
+ command! -range -nargs=+ VimLM call VimLM(<f-args>)
540
600
  nnoremap $mapp :call PasteIntoLastVisualSelection()<CR>
541
601
  vnoremap $mapp <Cmd>:call PasteIntoLastVisualSelection()<CR>
542
602
  vnoremap $mapl <Cmd>:call VisualPrompt()<CR>
vimlm-0.0.6/PKG-INFO DELETED
@@ -1,158 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: vimlm
3
- Version: 0.0.6
4
- Summary: VimLM - LLM-powered Vim assistant
5
- Home-page: https://github.com/JosefAlbers/vimlm
6
- Author: Josef Albers
7
- Author-email: albersj66@gmail.com
8
- Requires-Python: >=3.12.8
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE
11
- Requires-Dist: nanollama==0.0.5
12
- Requires-Dist: mlx_lm_utils==0.0.2
13
- Requires-Dist: watchfiles==1.0.4
14
- Dynamic: author
15
- Dynamic: author-email
16
- Dynamic: description
17
- Dynamic: description-content-type
18
- Dynamic: home-page
19
- Dynamic: requires-dist
20
- Dynamic: requires-python
21
- Dynamic: summary
22
-
23
-
24
- # VimLM - Local LLM-Powered Coding Assistant for Vim
25
-
26
- ![vimlm](https://raw.githubusercontent.com/JosefAlbers/VimLM/main/assets/captioned_vimlm.gif)
27
-
28
- LLM-powered coding companion for Vim, inspired by GitHub Copilot/Cursor. Integrates contextual code understanding, summarization, and AI assistance directly into your Vim workflow.
29
-
30
- ## Features
31
-
32
- - **Model Agnostic** - Use any MLX-compatible model via a configuration file
33
- - **Vim-Native UX** - Intuitive keybindings and split-window responses
34
- - **Deep Context** - Understands code context from:
35
- - Current file
36
- - Visual selections
37
- - Referenced files
38
- - Project directory structure
39
- - **Conversational Coding** - Iterative refinement with follow-up queries
40
- - **Air-Gapped Security** - 100% offline - no APIs, no tracking, no data leaks
41
-
42
- ## Requirements
43
-
44
- - Apple M-series chip
45
- - Python 3.12.8
46
-
47
- ## Quick Start
48
-
49
- Install:
50
-
51
- ```zsh
52
- pip install vimlm
53
- ```
54
-
55
- Launch:
56
-
57
- ```zsh
58
- vimlm
59
- ```
60
-
61
- or
62
-
63
- ```zsh
64
- vimlm path/to/your_file
65
- ```
66
-
67
- This launches Vim with the LLM in a split window, ready to assist you.
68
-
69
- ## Basic Usage
70
-
71
- 1. **From Normal Mode**:
72
- - `Ctrl-l`: Adds current line + file to context
73
- - Example prompt: "Regex for removing html tags from item.content"
74
-
75
- 2. **From Visual Mode**:
76
- - Select code → `Ctrl-l`: Adds selected block + current file to context
77
- - Example prompt: "Convert this to async/await syntax"
78
-
79
- 3. **Inline Commands**:
80
-
81
- !include: Adds specified outside files/folders to context:
82
- - `!include` (no path): Current folder
83
- - `!include ~/scrap/jph00/hypermedia-applications.summ.md`: Specific folder
84
- - `!include ~/wtm/utils.py`: Specific file
85
- - Example prompt: "AJAX-ify this app @ ~/scrap/jph00/hypermedia-applications.summ.md"
86
-
87
- !deploy: Extract code blocks to files in user specified dir (current dir if none specified).
88
-
89
- !continue: Lets the LLM resume the generation from where it had halted due to length limits.
90
-
91
- !followup: Continue the thread (equivalent to `Ctrl-j`
92
-
93
- 4. **Follow-Up**: After initial response:
94
- - `Ctrl-j`: Continue thread
95
- - Example follow-up: "In Manifest V3"
96
-
97
- 4. **Code Extraction: Press `Ctrl-p` to choose a code block from the response and insert them into:
98
- - The last selected visual block (in Normal mode)
99
- - The current selection (in Visual mode)
100
- - Example workflow:
101
- 1. Select a block of code in Visual mode.
102
- 2. Prompt the LLM with `Ctrl-l` (e.g., "Convert this to async/await syntax").
103
- 3. Once the response is generated, press `Ctrl-p` to replace the selected block with the extracted code.
104
-
105
- ### Key Bindings
106
-
107
- | Binding | Mode | Action |
108
- |------------|---------------|----------------------------------------|
109
- | `Ctrl-l` | Normal/Visual | Send current file + selection to LLM |
110
- | `Ctrl-j` | Normal | Continue conversation |
111
- | `Ctrl-p` | Normal/Visual | Replace the selection with generated code |
112
- | `Esc` | Prompt | Cancel input |
113
-
114
- ## Advanced Configuration
115
-
116
- VimLM uses a JSON config file with the following configurable parameters:
117
-
118
- ```json
119
- {
120
- "DEBUG": true,
121
- "LLM_MODEL": null,
122
- "NUM_TOKEN": 2000,
123
- "SEP_CMD": "!",
124
- "USE_LEADER": false
125
- }
126
- ```
127
-
128
- ### Custom Model Setup
129
-
130
- 1. **Browse models**: [MLX Community Models on Hugging Face](https://huggingface.co/mlx-community)
131
-
132
- 2. **Edit config file**:
133
-
134
- ```json
135
- {
136
- "LLM_MODEL": "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit"
137
- }
138
- ```
139
- 3. **Save to**:
140
-
141
- ```
142
- ~/vimlm/config.json
143
- ```
144
-
145
- 4. **Restart VimLM**
146
-
147
-
148
- ### Custom Keybinding
149
-
150
- If you prefer using `<Leader>` in place of `<Ctrl>` for the ViMLM key bindings:
151
-
152
- ```json
153
- {
154
- "USER_LEADER": true
155
- }
156
- ```
157
-
158
-
vimlm-0.0.6/README.md DELETED
@@ -1,136 +0,0 @@
1
-
2
- # VimLM - Local LLM-Powered Coding Assistant for Vim
3
-
4
- ![vimlm](https://raw.githubusercontent.com/JosefAlbers/VimLM/main/assets/captioned_vimlm.gif)
5
-
6
- LLM-powered coding companion for Vim, inspired by GitHub Copilot/Cursor. Integrates contextual code understanding, summarization, and AI assistance directly into your Vim workflow.
7
-
8
- ## Features
9
-
10
- - **Model Agnostic** - Use any MLX-compatible model via a configuration file
11
- - **Vim-Native UX** - Intuitive keybindings and split-window responses
12
- - **Deep Context** - Understands code context from:
13
- - Current file
14
- - Visual selections
15
- - Referenced files
16
- - Project directory structure
17
- - **Conversational Coding** - Iterative refinement with follow-up queries
18
- - **Air-Gapped Security** - 100% offline - no APIs, no tracking, no data leaks
19
-
20
- ## Requirements
21
-
22
- - Apple M-series chip
23
- - Python 3.12.8
24
-
25
- ## Quick Start
26
-
27
- Install:
28
-
29
- ```zsh
30
- pip install vimlm
31
- ```
32
-
33
- Launch:
34
-
35
- ```zsh
36
- vimlm
37
- ```
38
-
39
- or
40
-
41
- ```zsh
42
- vimlm path/to/your_file
43
- ```
44
-
45
- This launches Vim with the LLM in a split window, ready to assist you.
46
-
47
- ## Basic Usage
48
-
49
- 1. **From Normal Mode**:
50
- - `Ctrl-l`: Adds current line + file to context
51
- - Example prompt: "Regex for removing html tags from item.content"
52
-
53
- 2. **From Visual Mode**:
54
- - Select code → `Ctrl-l`: Adds selected block + current file to context
55
- - Example prompt: "Convert this to async/await syntax"
56
-
57
- 3. **Inline Commands**:
58
-
59
- !include: Adds specified outside files/folders to context:
60
- - `!include` (no path): Current folder
61
- - `!include ~/scrap/jph00/hypermedia-applications.summ.md`: Specific folder
62
- - `!include ~/wtm/utils.py`: Specific file
63
- - Example prompt: "AJAX-ify this app @ ~/scrap/jph00/hypermedia-applications.summ.md"
64
-
65
- !deploy: Extract code blocks to files in user specified dir (current dir if none specified).
66
-
67
- !continue: Lets the LLM resume the generation from where it had halted due to length limits.
68
-
69
- !followup: Continue the thread (equivalent to `Ctrl-j`
70
-
71
- 4. **Follow-Up**: After initial response:
72
- - `Ctrl-j`: Continue thread
73
- - Example follow-up: "In Manifest V3"
74
-
75
- 4. **Code Extraction: Press `Ctrl-p` to choose a code block from the response and insert them into:
76
- - The last selected visual block (in Normal mode)
77
- - The current selection (in Visual mode)
78
- - Example workflow:
79
- 1. Select a block of code in Visual mode.
80
- 2. Prompt the LLM with `Ctrl-l` (e.g., "Convert this to async/await syntax").
81
- 3. Once the response is generated, press `Ctrl-p` to replace the selected block with the extracted code.
82
-
83
- ### Key Bindings
84
-
85
- | Binding | Mode | Action |
86
- |------------|---------------|----------------------------------------|
87
- | `Ctrl-l` | Normal/Visual | Send current file + selection to LLM |
88
- | `Ctrl-j` | Normal | Continue conversation |
89
- | `Ctrl-p` | Normal/Visual | Replace the selection with generated code |
90
- | `Esc` | Prompt | Cancel input |
91
-
92
- ## Advanced Configuration
93
-
94
- VimLM uses a JSON config file with the following configurable parameters:
95
-
96
- ```json
97
- {
98
- "DEBUG": true,
99
- "LLM_MODEL": null,
100
- "NUM_TOKEN": 2000,
101
- "SEP_CMD": "!",
102
- "USE_LEADER": false
103
- }
104
- ```
105
-
106
- ### Custom Model Setup
107
-
108
- 1. **Browse models**: [MLX Community Models on Hugging Face](https://huggingface.co/mlx-community)
109
-
110
- 2. **Edit config file**:
111
-
112
- ```json
113
- {
114
- "LLM_MODEL": "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit"
115
- }
116
- ```
117
- 3. **Save to**:
118
-
119
- ```
120
- ~/vimlm/config.json
121
- ```
122
-
123
- 4. **Restart VimLM**
124
-
125
-
126
- ### Custom Keybinding
127
-
128
- If you prefer using `<Leader>` in place of `<Ctrl>` for the ViMLM key bindings:
129
-
130
- ```json
131
- {
132
- "USER_LEADER": true
133
- }
134
- ```
135
-
136
-
@@ -1,158 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: vimlm
3
- Version: 0.0.6
4
- Summary: VimLM - LLM-powered Vim assistant
5
- Home-page: https://github.com/JosefAlbers/vimlm
6
- Author: Josef Albers
7
- Author-email: albersj66@gmail.com
8
- Requires-Python: >=3.12.8
9
- Description-Content-Type: text/markdown
10
- License-File: LICENSE
11
- Requires-Dist: nanollama==0.0.5
12
- Requires-Dist: mlx_lm_utils==0.0.2
13
- Requires-Dist: watchfiles==1.0.4
14
- Dynamic: author
15
- Dynamic: author-email
16
- Dynamic: description
17
- Dynamic: description-content-type
18
- Dynamic: home-page
19
- Dynamic: requires-dist
20
- Dynamic: requires-python
21
- Dynamic: summary
22
-
23
-
24
- # VimLM - Local LLM-Powered Coding Assistant for Vim
25
-
26
- ![vimlm](https://raw.githubusercontent.com/JosefAlbers/VimLM/main/assets/captioned_vimlm.gif)
27
-
28
- LLM-powered coding companion for Vim, inspired by GitHub Copilot/Cursor. Integrates contextual code understanding, summarization, and AI assistance directly into your Vim workflow.
29
-
30
- ## Features
31
-
32
- - **Model Agnostic** - Use any MLX-compatible model via a configuration file
33
- - **Vim-Native UX** - Intuitive keybindings and split-window responses
34
- - **Deep Context** - Understands code context from:
35
- - Current file
36
- - Visual selections
37
- - Referenced files
38
- - Project directory structure
39
- - **Conversational Coding** - Iterative refinement with follow-up queries
40
- - **Air-Gapped Security** - 100% offline - no APIs, no tracking, no data leaks
41
-
42
- ## Requirements
43
-
44
- - Apple M-series chip
45
- - Python 3.12.8
46
-
47
- ## Quick Start
48
-
49
- Install:
50
-
51
- ```zsh
52
- pip install vimlm
53
- ```
54
-
55
- Launch:
56
-
57
- ```zsh
58
- vimlm
59
- ```
60
-
61
- or
62
-
63
- ```zsh
64
- vimlm path/to/your_file
65
- ```
66
-
67
- This launches Vim with the LLM in a split window, ready to assist you.
68
-
69
- ## Basic Usage
70
-
71
- 1. **From Normal Mode**:
72
- - `Ctrl-l`: Adds current line + file to context
73
- - Example prompt: "Regex for removing html tags from item.content"
74
-
75
- 2. **From Visual Mode**:
76
- - Select code → `Ctrl-l`: Adds selected block + current file to context
77
- - Example prompt: "Convert this to async/await syntax"
78
-
79
- 3. **Inline Commands**:
80
-
81
- !include: Adds specified outside files/folders to context:
82
- - `!include` (no path): Current folder
83
- - `!include ~/scrap/jph00/hypermedia-applications.summ.md`: Specific folder
84
- - `!include ~/wtm/utils.py`: Specific file
85
- - Example prompt: "AJAX-ify this app @ ~/scrap/jph00/hypermedia-applications.summ.md"
86
-
87
- !deploy: Extract code blocks to files in user specified dir (current dir if none specified).
88
-
89
- !continue: Lets the LLM resume the generation from where it had halted due to length limits.
90
-
91
- !followup: Continue the thread (equivalent to `Ctrl-j`
92
-
93
- 4. **Follow-Up**: After initial response:
94
- - `Ctrl-j`: Continue thread
95
- - Example follow-up: "In Manifest V3"
96
-
97
- 4. **Code Extraction: Press `Ctrl-p` to choose a code block from the response and insert them into:
98
- - The last selected visual block (in Normal mode)
99
- - The current selection (in Visual mode)
100
- - Example workflow:
101
- 1. Select a block of code in Visual mode.
102
- 2. Prompt the LLM with `Ctrl-l` (e.g., "Convert this to async/await syntax").
103
- 3. Once the response is generated, press `Ctrl-p` to replace the selected block with the extracted code.
104
-
105
- ### Key Bindings
106
-
107
- | Binding | Mode | Action |
108
- |------------|---------------|----------------------------------------|
109
- | `Ctrl-l` | Normal/Visual | Send current file + selection to LLM |
110
- | `Ctrl-j` | Normal | Continue conversation |
111
- | `Ctrl-p` | Normal/Visual | Replace the selection with generated code |
112
- | `Esc` | Prompt | Cancel input |
113
-
114
- ## Advanced Configuration
115
-
116
- VimLM uses a JSON config file with the following configurable parameters:
117
-
118
- ```json
119
- {
120
- "DEBUG": true,
121
- "LLM_MODEL": null,
122
- "NUM_TOKEN": 2000,
123
- "SEP_CMD": "!",
124
- "USE_LEADER": false
125
- }
126
- ```
127
-
128
- ### Custom Model Setup
129
-
130
- 1. **Browse models**: [MLX Community Models on Hugging Face](https://huggingface.co/mlx-community)
131
-
132
- 2. **Edit config file**:
133
-
134
- ```json
135
- {
136
- "LLM_MODEL": "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit"
137
- }
138
- ```
139
- 3. **Save to**:
140
-
141
- ```
142
- ~/vimlm/config.json
143
- ```
144
-
145
- 4. **Restart VimLM**
146
-
147
-
148
- ### Custom Keybinding
149
-
150
- If you prefer using `<Leader>` in place of `<Ctrl>` for the ViMLM key bindings:
151
-
152
- ```json
153
- {
154
- "USER_LEADER": true
155
- }
156
- ```
157
-
158
-
File without changes
File without changes
File without changes
File without changes