vimlm 0.0.6__tar.gz → 0.0.8__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.8/PKG-INFO +169 -0
- vimlm-0.0.8/README.md +147 -0
- {vimlm-0.0.6 → vimlm-0.0.8}/setup.py +1 -1
- vimlm-0.0.8/vimlm.egg-info/PKG-INFO +169 -0
- {vimlm-0.0.6 → vimlm-0.0.8}/vimlm.py +167 -43
- vimlm-0.0.6/PKG-INFO +0 -158
- vimlm-0.0.6/README.md +0 -136
- vimlm-0.0.6/vimlm.egg-info/PKG-INFO +0 -158
- {vimlm-0.0.6 → vimlm-0.0.8}/LICENSE +0 -0
- {vimlm-0.0.6 → vimlm-0.0.8}/setup.cfg +0 -0
- {vimlm-0.0.6 → vimlm-0.0.8}/vimlm.egg-info/SOURCES.txt +0 -0
- {vimlm-0.0.6 → vimlm-0.0.8}/vimlm.egg-info/dependency_links.txt +0 -0
- {vimlm-0.0.6 → vimlm-0.0.8}/vimlm.egg-info/entry_points.txt +0 -0
- {vimlm-0.0.6 → vimlm-0.0.8}/vimlm.egg-info/requires.txt +0 -0
- {vimlm-0.0.6 → vimlm-0.0.8}/vimlm.egg-info/top_level.txt +0 -0
vimlm-0.0.8/PKG-INFO
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
Metadata-Version: 2.2
|
2
|
+
Name: vimlm
|
3
|
+
Version: 0.0.8
|
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 - AI-Powered Coding Assistant for Vim
|
25
|
+
|
26
|
+

|
27
|
+
|
28
|
+
VimLM brings the power of AI directly into your Vim workflow. Maintain focus with keyboard-driven interactions while leveraging AI for code generation, refactoring, and documentation.
|
29
|
+
|
30
|
+
Get started quickly with the [tutorial](tutorial.md).
|
31
|
+
|
32
|
+
## Features
|
33
|
+
- **Native Vim Integration** - Split-window responses & intuitive keybindings
|
34
|
+
- **Offline First** - 100% local execution with MLX-compatible models
|
35
|
+
- **Contextual Awareness** - Integrates seamlessly with your codebase and external resources
|
36
|
+
- **Conversational Workflow** - Iterate on responses with follow-up queries
|
37
|
+
- **Project Scaffolding** - Generate and deploy code blocks to directories
|
38
|
+
- **Extensible** - Create custom LLM workflows with command chains
|
39
|
+
|
40
|
+
## Requirements
|
41
|
+
- Apple Silicon (M-series)
|
42
|
+
- Python 3.12.8
|
43
|
+
- Vim 9.1
|
44
|
+
|
45
|
+
## Quick Start
|
46
|
+
```bash
|
47
|
+
pip install vimlm
|
48
|
+
vimlm
|
49
|
+
```
|
50
|
+
|
51
|
+
## Basic Usage
|
52
|
+
|
53
|
+
| Key Binding | Mode | Action |
|
54
|
+
|-------------|---------------|----------------------------------------|
|
55
|
+
| `Ctrl-l` | Normal/Visual | Prompt LLM |
|
56
|
+
| `Ctrl-j` | Normal | Continue conversation |
|
57
|
+
| `Ctrl-p` | Normal/Visual | Import generated code |
|
58
|
+
| `Esc` | Prompt | Cancel input |
|
59
|
+
|
60
|
+
### 1. **Contextual Prompting**
|
61
|
+
`Ctrl-l` to prompt LLM with context:
|
62
|
+
- Normal mode: Current file + line
|
63
|
+
- Visual mode: Current file + selected block
|
64
|
+
|
65
|
+
*Example Prompt*: `Create a Chrome extension`
|
66
|
+
|
67
|
+
### 2. **Conversational Refinement**
|
68
|
+
`Ctrl-j` to continue current thread.
|
69
|
+
|
70
|
+
*Example Prompt*: `Use manifest V3 instead`
|
71
|
+
|
72
|
+
### 3. **Code Substitution**
|
73
|
+
`Ctrl-p` to insert generated code block
|
74
|
+
- In Normal mode: Into last visual selection
|
75
|
+
- In Visual mode: Into current visual selection
|
76
|
+
|
77
|
+
*Example Workflow*:
|
78
|
+
1. Select a block of code in Visual mode
|
79
|
+
2. Prompt with `Ctrl-l`: `Use regex to remove html tags from item.content`
|
80
|
+
3. Press `Ctrl-p` to replace selection with generated code
|
81
|
+
|
82
|
+
## Inline Directives
|
83
|
+
```text
|
84
|
+
:VimLM [PROMPT] [!command1] [!command2]...
|
85
|
+
```
|
86
|
+
|
87
|
+
`!` prefix to embed inline directives in prompts:
|
88
|
+
|
89
|
+
| Directive | Description |
|
90
|
+
|------------------|------------------------------------------|
|
91
|
+
| `!include PATH` | Add file/directory/shell output to context |
|
92
|
+
| `!deploy DEST` | Save code blocks to directory |
|
93
|
+
| `!continue N` | Continue stopped response |
|
94
|
+
| `!followup` | Continue conversation |
|
95
|
+
|
96
|
+
### 1. **Context Layering**
|
97
|
+
```text
|
98
|
+
!include [PATH] # Add files/folders to context
|
99
|
+
```
|
100
|
+
- **`!include`** (no path): Current folder
|
101
|
+
- **`!include ~/projects/utils.py`**: Specific file
|
102
|
+
- **`!include ~/docs/api-specs/`**: Entire folder
|
103
|
+
- **`!include $(...)`**: Shell command output
|
104
|
+
|
105
|
+
*Example*: `Summarize recent changes !include $(git log --oneline -n 50)`
|
106
|
+
|
107
|
+
### 2. **Code Deployment**
|
108
|
+
```text
|
109
|
+
!deploy [DEST_DIR] # Extract code blocks to directory
|
110
|
+
```
|
111
|
+
- **`!deploy`** (no path): Current directory
|
112
|
+
- **`!deploy ./src`**: Specific directory
|
113
|
+
|
114
|
+
*Example:* `Create REST API endpoint !deploy ./api`
|
115
|
+
|
116
|
+
### 3. **Extending Response**
|
117
|
+
```text
|
118
|
+
!continue [MAX_TOKENS] # Continue stopped response
|
119
|
+
```
|
120
|
+
- **`!continue`**: Default 2000 tokens
|
121
|
+
- **`!continue 3000`**: Custom token limit
|
122
|
+
|
123
|
+
*Example:* `tl;dr !include large-file.txt !continue 5000`
|
124
|
+
|
125
|
+
## Command-Line Mode
|
126
|
+
```vim
|
127
|
+
:VimLM prompt [!command1] [!command2]...
|
128
|
+
```
|
129
|
+
|
130
|
+
Simplify complex tasks by chaining multiple commands together into a single, reusable Vim command.
|
131
|
+
|
132
|
+
*Examples*:
|
133
|
+
```vim
|
134
|
+
" Debug CI failures using error logs
|
135
|
+
:VimLM Fix Dockerfile !include .gitlab-ci.yml !include $(tail -n 20 ci.log)
|
136
|
+
|
137
|
+
" Generate unit tests for selected functions and save to test/
|
138
|
+
:VimLM Write pytest tests for this !include ./src !deploy ./test
|
139
|
+
|
140
|
+
" Add docstrings to all Python functions in file
|
141
|
+
:VimLM Add Google-style docstrings !include % !continue 4000
|
142
|
+
```
|
143
|
+
|
144
|
+
## Configuration
|
145
|
+
|
146
|
+
### 1. **Model Settings**
|
147
|
+
Edit `~/vimlm/cfg.json`:
|
148
|
+
```json
|
149
|
+
{
|
150
|
+
"LLM_MODEL": "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit",
|
151
|
+
"NUM_TOKEN": 32768
|
152
|
+
}
|
153
|
+
```
|
154
|
+
|
155
|
+
### 2. **Key Customization**
|
156
|
+
```json
|
157
|
+
{
|
158
|
+
"USE_LEADER": true,
|
159
|
+
"KEY_MAP": {
|
160
|
+
"l": "]",
|
161
|
+
"j": "[",
|
162
|
+
"p": "p"
|
163
|
+
}
|
164
|
+
}
|
165
|
+
```
|
166
|
+
|
167
|
+
## License
|
168
|
+
|
169
|
+
Apache 2.0 - See [LICENSE](LICENSE) for details.
|
vimlm-0.0.8/README.md
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
|
2
|
+
# VimLM - AI-Powered Coding Assistant for Vim
|
3
|
+
|
4
|
+

|
5
|
+
|
6
|
+
VimLM brings the power of AI directly into your Vim workflow. Maintain focus with keyboard-driven interactions while leveraging AI for code generation, refactoring, and documentation.
|
7
|
+
|
8
|
+
Get started quickly with the [tutorial](tutorial.md).
|
9
|
+
|
10
|
+
## Features
|
11
|
+
- **Native Vim Integration** - Split-window responses & intuitive keybindings
|
12
|
+
- **Offline First** - 100% local execution with MLX-compatible models
|
13
|
+
- **Contextual Awareness** - Integrates seamlessly with your codebase and external resources
|
14
|
+
- **Conversational Workflow** - Iterate on responses with follow-up queries
|
15
|
+
- **Project Scaffolding** - Generate and deploy code blocks to directories
|
16
|
+
- **Extensible** - Create custom LLM workflows with command chains
|
17
|
+
|
18
|
+
## Requirements
|
19
|
+
- Apple Silicon (M-series)
|
20
|
+
- Python 3.12.8
|
21
|
+
- Vim 9.1
|
22
|
+
|
23
|
+
## Quick Start
|
24
|
+
```bash
|
25
|
+
pip install vimlm
|
26
|
+
vimlm
|
27
|
+
```
|
28
|
+
|
29
|
+
## Basic Usage
|
30
|
+
|
31
|
+
| Key Binding | Mode | Action |
|
32
|
+
|-------------|---------------|----------------------------------------|
|
33
|
+
| `Ctrl-l` | Normal/Visual | Prompt LLM |
|
34
|
+
| `Ctrl-j` | Normal | Continue conversation |
|
35
|
+
| `Ctrl-p` | Normal/Visual | Import generated code |
|
36
|
+
| `Esc` | Prompt | Cancel input |
|
37
|
+
|
38
|
+
### 1. **Contextual Prompting**
|
39
|
+
`Ctrl-l` to prompt LLM with context:
|
40
|
+
- Normal mode: Current file + line
|
41
|
+
- Visual mode: Current file + selected block
|
42
|
+
|
43
|
+
*Example Prompt*: `Create a Chrome extension`
|
44
|
+
|
45
|
+
### 2. **Conversational Refinement**
|
46
|
+
`Ctrl-j` to continue current thread.
|
47
|
+
|
48
|
+
*Example Prompt*: `Use manifest V3 instead`
|
49
|
+
|
50
|
+
### 3. **Code Substitution**
|
51
|
+
`Ctrl-p` to insert generated code block
|
52
|
+
- In Normal mode: Into last visual selection
|
53
|
+
- In Visual mode: Into current visual selection
|
54
|
+
|
55
|
+
*Example Workflow*:
|
56
|
+
1. Select a block of code in Visual mode
|
57
|
+
2. Prompt with `Ctrl-l`: `Use regex to remove html tags from item.content`
|
58
|
+
3. Press `Ctrl-p` to replace selection with generated code
|
59
|
+
|
60
|
+
## Inline Directives
|
61
|
+
```text
|
62
|
+
:VimLM [PROMPT] [!command1] [!command2]...
|
63
|
+
```
|
64
|
+
|
65
|
+
`!` prefix to embed inline directives in prompts:
|
66
|
+
|
67
|
+
| Directive | Description |
|
68
|
+
|------------------|------------------------------------------|
|
69
|
+
| `!include PATH` | Add file/directory/shell output to context |
|
70
|
+
| `!deploy DEST` | Save code blocks to directory |
|
71
|
+
| `!continue N` | Continue stopped response |
|
72
|
+
| `!followup` | Continue conversation |
|
73
|
+
|
74
|
+
### 1. **Context Layering**
|
75
|
+
```text
|
76
|
+
!include [PATH] # Add files/folders to context
|
77
|
+
```
|
78
|
+
- **`!include`** (no path): Current folder
|
79
|
+
- **`!include ~/projects/utils.py`**: Specific file
|
80
|
+
- **`!include ~/docs/api-specs/`**: Entire folder
|
81
|
+
- **`!include $(...)`**: Shell command output
|
82
|
+
|
83
|
+
*Example*: `Summarize recent changes !include $(git log --oneline -n 50)`
|
84
|
+
|
85
|
+
### 2. **Code Deployment**
|
86
|
+
```text
|
87
|
+
!deploy [DEST_DIR] # Extract code blocks to directory
|
88
|
+
```
|
89
|
+
- **`!deploy`** (no path): Current directory
|
90
|
+
- **`!deploy ./src`**: Specific directory
|
91
|
+
|
92
|
+
*Example:* `Create REST API endpoint !deploy ./api`
|
93
|
+
|
94
|
+
### 3. **Extending Response**
|
95
|
+
```text
|
96
|
+
!continue [MAX_TOKENS] # Continue stopped response
|
97
|
+
```
|
98
|
+
- **`!continue`**: Default 2000 tokens
|
99
|
+
- **`!continue 3000`**: Custom token limit
|
100
|
+
|
101
|
+
*Example:* `tl;dr !include large-file.txt !continue 5000`
|
102
|
+
|
103
|
+
## Command-Line Mode
|
104
|
+
```vim
|
105
|
+
:VimLM prompt [!command1] [!command2]...
|
106
|
+
```
|
107
|
+
|
108
|
+
Simplify complex tasks by chaining multiple commands together into a single, reusable Vim command.
|
109
|
+
|
110
|
+
*Examples*:
|
111
|
+
```vim
|
112
|
+
" Debug CI failures using error logs
|
113
|
+
:VimLM Fix Dockerfile !include .gitlab-ci.yml !include $(tail -n 20 ci.log)
|
114
|
+
|
115
|
+
" Generate unit tests for selected functions and save to test/
|
116
|
+
:VimLM Write pytest tests for this !include ./src !deploy ./test
|
117
|
+
|
118
|
+
" Add docstrings to all Python functions in file
|
119
|
+
:VimLM Add Google-style docstrings !include % !continue 4000
|
120
|
+
```
|
121
|
+
|
122
|
+
## Configuration
|
123
|
+
|
124
|
+
### 1. **Model Settings**
|
125
|
+
Edit `~/vimlm/cfg.json`:
|
126
|
+
```json
|
127
|
+
{
|
128
|
+
"LLM_MODEL": "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit",
|
129
|
+
"NUM_TOKEN": 32768
|
130
|
+
}
|
131
|
+
```
|
132
|
+
|
133
|
+
### 2. **Key Customization**
|
134
|
+
```json
|
135
|
+
{
|
136
|
+
"USE_LEADER": true,
|
137
|
+
"KEY_MAP": {
|
138
|
+
"l": "]",
|
139
|
+
"j": "[",
|
140
|
+
"p": "p"
|
141
|
+
}
|
142
|
+
}
|
143
|
+
```
|
144
|
+
|
145
|
+
## License
|
146
|
+
|
147
|
+
Apache 2.0 - See [LICENSE](LICENSE) for details.
|
@@ -0,0 +1,169 @@
|
|
1
|
+
Metadata-Version: 2.2
|
2
|
+
Name: vimlm
|
3
|
+
Version: 0.0.8
|
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 - AI-Powered Coding Assistant for Vim
|
25
|
+
|
26
|
+

|
27
|
+
|
28
|
+
VimLM brings the power of AI directly into your Vim workflow. Maintain focus with keyboard-driven interactions while leveraging AI for code generation, refactoring, and documentation.
|
29
|
+
|
30
|
+
Get started quickly with the [tutorial](tutorial.md).
|
31
|
+
|
32
|
+
## Features
|
33
|
+
- **Native Vim Integration** - Split-window responses & intuitive keybindings
|
34
|
+
- **Offline First** - 100% local execution with MLX-compatible models
|
35
|
+
- **Contextual Awareness** - Integrates seamlessly with your codebase and external resources
|
36
|
+
- **Conversational Workflow** - Iterate on responses with follow-up queries
|
37
|
+
- **Project Scaffolding** - Generate and deploy code blocks to directories
|
38
|
+
- **Extensible** - Create custom LLM workflows with command chains
|
39
|
+
|
40
|
+
## Requirements
|
41
|
+
- Apple Silicon (M-series)
|
42
|
+
- Python 3.12.8
|
43
|
+
- Vim 9.1
|
44
|
+
|
45
|
+
## Quick Start
|
46
|
+
```bash
|
47
|
+
pip install vimlm
|
48
|
+
vimlm
|
49
|
+
```
|
50
|
+
|
51
|
+
## Basic Usage
|
52
|
+
|
53
|
+
| Key Binding | Mode | Action |
|
54
|
+
|-------------|---------------|----------------------------------------|
|
55
|
+
| `Ctrl-l` | Normal/Visual | Prompt LLM |
|
56
|
+
| `Ctrl-j` | Normal | Continue conversation |
|
57
|
+
| `Ctrl-p` | Normal/Visual | Import generated code |
|
58
|
+
| `Esc` | Prompt | Cancel input |
|
59
|
+
|
60
|
+
### 1. **Contextual Prompting**
|
61
|
+
`Ctrl-l` to prompt LLM with context:
|
62
|
+
- Normal mode: Current file + line
|
63
|
+
- Visual mode: Current file + selected block
|
64
|
+
|
65
|
+
*Example Prompt*: `Create a Chrome extension`
|
66
|
+
|
67
|
+
### 2. **Conversational Refinement**
|
68
|
+
`Ctrl-j` to continue current thread.
|
69
|
+
|
70
|
+
*Example Prompt*: `Use manifest V3 instead`
|
71
|
+
|
72
|
+
### 3. **Code Substitution**
|
73
|
+
`Ctrl-p` to insert generated code block
|
74
|
+
- In Normal mode: Into last visual selection
|
75
|
+
- In Visual mode: Into current visual selection
|
76
|
+
|
77
|
+
*Example Workflow*:
|
78
|
+
1. Select a block of code in Visual mode
|
79
|
+
2. Prompt with `Ctrl-l`: `Use regex to remove html tags from item.content`
|
80
|
+
3. Press `Ctrl-p` to replace selection with generated code
|
81
|
+
|
82
|
+
## Inline Directives
|
83
|
+
```text
|
84
|
+
:VimLM [PROMPT] [!command1] [!command2]...
|
85
|
+
```
|
86
|
+
|
87
|
+
`!` prefix to embed inline directives in prompts:
|
88
|
+
|
89
|
+
| Directive | Description |
|
90
|
+
|------------------|------------------------------------------|
|
91
|
+
| `!include PATH` | Add file/directory/shell output to context |
|
92
|
+
| `!deploy DEST` | Save code blocks to directory |
|
93
|
+
| `!continue N` | Continue stopped response |
|
94
|
+
| `!followup` | Continue conversation |
|
95
|
+
|
96
|
+
### 1. **Context Layering**
|
97
|
+
```text
|
98
|
+
!include [PATH] # Add files/folders to context
|
99
|
+
```
|
100
|
+
- **`!include`** (no path): Current folder
|
101
|
+
- **`!include ~/projects/utils.py`**: Specific file
|
102
|
+
- **`!include ~/docs/api-specs/`**: Entire folder
|
103
|
+
- **`!include $(...)`**: Shell command output
|
104
|
+
|
105
|
+
*Example*: `Summarize recent changes !include $(git log --oneline -n 50)`
|
106
|
+
|
107
|
+
### 2. **Code Deployment**
|
108
|
+
```text
|
109
|
+
!deploy [DEST_DIR] # Extract code blocks to directory
|
110
|
+
```
|
111
|
+
- **`!deploy`** (no path): Current directory
|
112
|
+
- **`!deploy ./src`**: Specific directory
|
113
|
+
|
114
|
+
*Example:* `Create REST API endpoint !deploy ./api`
|
115
|
+
|
116
|
+
### 3. **Extending Response**
|
117
|
+
```text
|
118
|
+
!continue [MAX_TOKENS] # Continue stopped response
|
119
|
+
```
|
120
|
+
- **`!continue`**: Default 2000 tokens
|
121
|
+
- **`!continue 3000`**: Custom token limit
|
122
|
+
|
123
|
+
*Example:* `tl;dr !include large-file.txt !continue 5000`
|
124
|
+
|
125
|
+
## Command-Line Mode
|
126
|
+
```vim
|
127
|
+
:VimLM prompt [!command1] [!command2]...
|
128
|
+
```
|
129
|
+
|
130
|
+
Simplify complex tasks by chaining multiple commands together into a single, reusable Vim command.
|
131
|
+
|
132
|
+
*Examples*:
|
133
|
+
```vim
|
134
|
+
" Debug CI failures using error logs
|
135
|
+
:VimLM Fix Dockerfile !include .gitlab-ci.yml !include $(tail -n 20 ci.log)
|
136
|
+
|
137
|
+
" Generate unit tests for selected functions and save to test/
|
138
|
+
:VimLM Write pytest tests for this !include ./src !deploy ./test
|
139
|
+
|
140
|
+
" Add docstrings to all Python functions in file
|
141
|
+
:VimLM Add Google-style docstrings !include % !continue 4000
|
142
|
+
```
|
143
|
+
|
144
|
+
## Configuration
|
145
|
+
|
146
|
+
### 1. **Model Settings**
|
147
|
+
Edit `~/vimlm/cfg.json`:
|
148
|
+
```json
|
149
|
+
{
|
150
|
+
"LLM_MODEL": "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit",
|
151
|
+
"NUM_TOKEN": 32768
|
152
|
+
}
|
153
|
+
```
|
154
|
+
|
155
|
+
### 2. **Key Customization**
|
156
|
+
```json
|
157
|
+
{
|
158
|
+
"USE_LEADER": true,
|
159
|
+
"KEY_MAP": {
|
160
|
+
"l": "]",
|
161
|
+
"j": "[",
|
162
|
+
"p": "p"
|
163
|
+
}
|
164
|
+
}
|
165
|
+
```
|
166
|
+
|
167
|
+
## License
|
168
|
+
|
169
|
+
Apache 2.0 - See [LICENSE](LICENSE) for details.
|
@@ -18,7 +18,7 @@ import json
|
|
18
18
|
import os
|
19
19
|
from watchfiles import awatch
|
20
20
|
import shutil
|
21
|
-
import
|
21
|
+
from datetime import datetime
|
22
22
|
from itertools import accumulate
|
23
23
|
import argparse
|
24
24
|
import tempfile
|
@@ -26,13 +26,19 @@ from pathlib import Path
|
|
26
26
|
from string import Template
|
27
27
|
import re
|
28
28
|
|
29
|
-
|
30
|
-
LLM_MODEL = None # "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit"
|
31
|
-
NUM_TOKEN = 2000
|
32
|
-
|
33
|
-
|
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.8',
|
38
|
+
DEBUG = False,
|
39
|
+
)
|
40
|
+
|
41
|
+
DATE_FORM = "%Y_%m_%d_%H_%M_%S"
|
36
42
|
VIMLM_DIR = os.path.expanduser("~/vimlm")
|
37
43
|
WATCH_DIR = os.path.expanduser("~/vimlm/watch_dir")
|
38
44
|
CFG_FILE = 'cfg.json'
|
@@ -45,6 +51,36 @@ LOG_PATH = os.path.join(VIMLM_DIR, LOG_FILE)
|
|
45
51
|
LTM_PATH = os.path.join(VIMLM_DIR, LTM_FILE)
|
46
52
|
OUT_PATH = os.path.join(WATCH_DIR, OUT_FILE)
|
47
53
|
|
54
|
+
def is_old(config):
|
55
|
+
v_str = config.get('VERSION', 0)
|
56
|
+
for min_v, usr_v in zip(DEFAULTS['VERSION'].split('.'), v_str.split('.')):
|
57
|
+
if int(min_v) < int(usr_v):
|
58
|
+
return False
|
59
|
+
elif int(min_v) > int(usr_v):
|
60
|
+
return True
|
61
|
+
return False
|
62
|
+
|
63
|
+
if os.path.exists(WATCH_DIR):
|
64
|
+
shutil.rmtree(WATCH_DIR)
|
65
|
+
os.makedirs(WATCH_DIR)
|
66
|
+
|
67
|
+
try:
|
68
|
+
with open(CFG_PATH, "r") as f:
|
69
|
+
config = json.load(f)
|
70
|
+
if is_old(config):
|
71
|
+
for p in [CFG_PATH, LOG_PATH, LTM_PATH]:
|
72
|
+
if os.path.isfile(p):
|
73
|
+
os.remove(p)
|
74
|
+
raise ValueError(f'Updating config')
|
75
|
+
except Exception as e:
|
76
|
+
print(e)
|
77
|
+
config = DEFAULTS
|
78
|
+
with open(CFG_PATH, 'w') as f:
|
79
|
+
json.dump(DEFAULTS, f, indent=2)
|
80
|
+
|
81
|
+
for k, v in DEFAULTS.items():
|
82
|
+
globals()[k] = config.get(k, v)
|
83
|
+
|
48
84
|
def toout(s, key=None, mode=None):
|
49
85
|
key = '' if key is None else ':'+key
|
50
86
|
mode = 'w' if mode is None else mode
|
@@ -60,26 +96,21 @@ def tolog(log, key='debug'):
|
|
60
96
|
logs = json.load(log_f)
|
61
97
|
except:
|
62
98
|
logs = []
|
63
|
-
logs.append(dict(key=key, log=log, timestamp=
|
99
|
+
logs.append(dict(key=key, log=log, timestamp=datetime.now().strftime(DATE_FORM)))
|
64
100
|
with open(LOG_PATH, "w", encoding="utf-8") as log_f:
|
65
101
|
json.dump(logs, log_f, indent=2)
|
66
102
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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)
|
103
|
+
def print_log():
|
104
|
+
with open(LOG_PATH, 'r') as f:
|
105
|
+
logs = json.load(f)
|
106
|
+
for log in logs:
|
107
|
+
print(f'\033[37m{log["key"]} {log["timestamp"]}\033[0m')
|
108
|
+
if 'tovim' in log["key"]:
|
109
|
+
print('\033[33m')
|
110
|
+
elif 'tollm' in log["key"]:
|
111
|
+
print('\033[31m')
|
112
|
+
print(log["log"])
|
113
|
+
print('\033[0m')
|
83
114
|
|
84
115
|
toout('Loading LLM...')
|
85
116
|
if LLM_MODEL is None:
|
@@ -99,6 +130,7 @@ def deploy(dest=None, src=None, reformat=True):
|
|
99
130
|
with open(src, 'r') as f:
|
100
131
|
prompt_deploy = f.read().strip() + '\n\n---\n\n' + prompt_deploy
|
101
132
|
if reformat:
|
133
|
+
toout('Deploying...')
|
102
134
|
response = chat(prompt_deploy, max_new=NUM_TOKEN, verbose=False, stream=False)['text']
|
103
135
|
toout(response, 'deploy')
|
104
136
|
lines = response.splitlines()
|
@@ -326,19 +358,41 @@ def process_command(data):
|
|
326
358
|
data['include'] = ''
|
327
359
|
for cmd in cmds:
|
328
360
|
if cmd.startswith('include'):
|
329
|
-
arg = cmd.removeprefix('include').strip('(').strip(')').strip().strip('"').strip("'").strip()
|
361
|
+
arg = cmd.removeprefix('include').strip().strip('(').strip(')').strip().strip('"').strip("'").strip()
|
330
362
|
src = data['dir'] if len(arg) == 0 else arg
|
331
|
-
|
363
|
+
if arg == '%':
|
364
|
+
continue
|
365
|
+
if src.startswith('`') or src.startswith('$('):
|
366
|
+
shell_cmd = src.strip('`') if src.startswith('`') else src.strip('$()')
|
367
|
+
shell_cmd = shell_cmd.strip()
|
368
|
+
try:
|
369
|
+
result = subprocess.run(shell_cmd, shell=True, capture_output=True, text=True)
|
370
|
+
if result.returncode == 0:
|
371
|
+
data['include'] += f'--- **{shell_cmd}** ---\n```\n{result.stdout.strip()}\n```\n---\n\n'
|
372
|
+
else:
|
373
|
+
tolog(f'{shell_cmd} failed {result.stderr.strip()}')
|
374
|
+
except Exception as e:
|
375
|
+
tolog(f'Error executing {shell_cmd}: {e}')
|
376
|
+
else:
|
377
|
+
data['include'] += ingest(src)
|
332
378
|
|
333
379
|
for cmd in cmds:
|
334
380
|
if cmd.startswith('deploy'):
|
335
|
-
arg = cmd.removeprefix('deploy').strip('(').strip(')').strip().strip('"').strip("'").strip()
|
381
|
+
arg = cmd.removeprefix('deploy').strip().strip('(').strip(')').strip().strip('"').strip("'").strip()
|
336
382
|
if len(data['user_prompt']) == 0:
|
337
383
|
deploy(dest=arg)
|
338
384
|
data['user_prompt'] = ''
|
339
385
|
return data
|
340
386
|
data['user_prompt'] += "\n\nEnsure that each code block is preceded by a filename in **filename.ext** format. The filename should only contain alphanumeric characters, dots, underscores, or hyphens. Ensure that any extraneous characters are removed from the filenames."
|
341
387
|
data['deploy_dest'] = arg
|
388
|
+
for cmd in cmds:
|
389
|
+
if cmd.startswith('write'):
|
390
|
+
arg = cmd.removeprefix('write').strip().strip('(').strip(')').strip().strip('"').strip("'").strip()
|
391
|
+
if len(arg) == 0:
|
392
|
+
arg = 'response'
|
393
|
+
pass
|
394
|
+
timestamp = datetime.now().strftime(DATE_FORM)
|
395
|
+
data['write_dest'] = re.sub(r"[^a-zA-Z0-9_.-]", "", f'{arg}_{timestamp}.md')
|
342
396
|
return data
|
343
397
|
|
344
398
|
async def monitor_directory():
|
@@ -391,15 +445,57 @@ async def process_files(data):
|
|
391
445
|
toout(response['text'])
|
392
446
|
else:
|
393
447
|
toout(response['text'])
|
394
|
-
tolog(response
|
448
|
+
tolog(response)
|
449
|
+
if 'write_dest' in data:
|
450
|
+
with open(data['write_dest'], 'w') as f:
|
451
|
+
f.write(response['text'])
|
395
452
|
if 'deploy_dest' in data:
|
396
453
|
deploy(dest=data['deploy_dest'], reformat=False)
|
397
454
|
|
398
|
-
|
399
|
-
|
455
|
+
KEYL = KEY_MAP.get('l', 'l')
|
456
|
+
KEYJ = KEY_MAP.get('j', 'j')
|
457
|
+
KEYP = KEY_MAP.get('p', 'p')
|
458
|
+
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
459
|
VIMLMSCRIPT = Template(r"""
|
401
460
|
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
461
|
let s:watched_dir = expand('$WATCH_DIR')
|
462
|
+
let s:vimlm_enabled = 1
|
463
|
+
|
464
|
+
function! ToggleVimLM()
|
465
|
+
if s:vimlm_enabled
|
466
|
+
let s:vimlm_enabled = 0
|
467
|
+
let response_path = s:watched_dir . '/response.md'
|
468
|
+
let bufnum = bufnr(response_path)
|
469
|
+
let winid = bufwinnr(bufnum)
|
470
|
+
if winid != -1
|
471
|
+
execute winid . 'wincmd c'
|
472
|
+
endif
|
473
|
+
if exists('s:monitor_timer')
|
474
|
+
call timer_stop(s:monitor_timer)
|
475
|
+
unlet s:monitor_timer
|
476
|
+
endif
|
477
|
+
echohl WarningMsg | echom "VimLM disabled" | echohl None
|
478
|
+
else
|
479
|
+
let s:vimlm_enabled = 1
|
480
|
+
silent! call Monitor()
|
481
|
+
echohl WarningMsg | echom "VimLM enabled" | echohl None
|
482
|
+
endif
|
483
|
+
endfunction
|
484
|
+
|
485
|
+
function! CheckForUpdates(timer)
|
486
|
+
if !s:vimlm_enabled
|
487
|
+
return
|
488
|
+
endif
|
489
|
+
let bufnum = bufnr(s:watched_dir . '/response.md')
|
490
|
+
let winid = bufwinnr(bufnum)
|
491
|
+
if winid == -1
|
492
|
+
call timer_stop(s:monitor_timer)
|
493
|
+
unlet s:monitor_timer
|
494
|
+
call Monitor()
|
495
|
+
else
|
496
|
+
silent! checktime
|
497
|
+
endif
|
498
|
+
endfunction
|
403
499
|
|
404
500
|
function! Monitor()
|
405
501
|
if exists('s:monitor_timer')
|
@@ -422,13 +518,16 @@ function! Monitor()
|
|
422
518
|
let s:monitor_timer = timer_start(100, 'CheckForUpdates', {'repeat': -1})
|
423
519
|
endfunction
|
424
520
|
|
425
|
-
function!
|
521
|
+
function! ScrollToTop()
|
426
522
|
let bufnum = bufnr(s:watched_dir . '/response.md')
|
427
|
-
if bufnum
|
428
|
-
|
429
|
-
|
523
|
+
if bufnum != -1
|
524
|
+
let winid = bufwinnr(bufnum)
|
525
|
+
if winid > 0
|
526
|
+
execute winid . "wincmd w"
|
527
|
+
normal! gg
|
528
|
+
wincmd p
|
529
|
+
endif
|
430
530
|
endif
|
431
|
-
silent! checktime
|
432
531
|
endfunction
|
433
532
|
|
434
533
|
function! s:CustomInput(prompt) abort
|
@@ -452,14 +551,13 @@ function! SaveUserInput(prompt)
|
|
452
551
|
let current_file = expand('%:p')
|
453
552
|
let tree_file = s:watched_dir . '/tree'
|
454
553
|
call writefile([current_file], tree_file, 'w')
|
554
|
+
call ScrollToTop()
|
455
555
|
endfunction
|
456
556
|
|
457
557
|
function! VisualPrompt()
|
458
558
|
silent! execute "normal! \<ESC>"
|
459
559
|
silent execute "'<,'>w! " . s:watched_dir . "/yank"
|
460
560
|
silent execute "w! " . s:watched_dir . "/context"
|
461
|
-
" silent! execute "normal! `<V`>"
|
462
|
-
" silent! execute "normal! \<ESC>"
|
463
561
|
call SaveUserInput('VimLM: ')
|
464
562
|
endfunction
|
465
563
|
|
@@ -467,7 +565,6 @@ function! NormalPrompt()
|
|
467
565
|
silent! execute "normal! V\<ESC>"
|
468
566
|
silent execute "'<,'>w! " . s:watched_dir . "/yank"
|
469
567
|
silent execute "w! " . s:watched_dir . "/context"
|
470
|
-
" silent! execute "normal! \<ESC>"
|
471
568
|
call SaveUserInput('VimLM: ')
|
472
569
|
endfunction
|
473
570
|
|
@@ -515,10 +612,14 @@ function! ExtractAllCodeBlocks()
|
|
515
612
|
return len(code_blocks)
|
516
613
|
endfunction
|
517
614
|
|
518
|
-
function! PasteIntoLastVisualSelection()
|
615
|
+
function! PasteIntoLastVisualSelection(...)
|
519
616
|
let num_blocks = ExtractAllCodeBlocks()
|
520
|
-
|
521
|
-
|
617
|
+
if a:0 > 0
|
618
|
+
let register_name = a:1
|
619
|
+
else
|
620
|
+
echo "Extracted " . num_blocks . " blocks into registers @a-@" . s:register_names[num_blocks - 1] . ". Enter register name: "
|
621
|
+
let register_name = nr2char(getchar())
|
622
|
+
endif
|
522
623
|
if register_name !~ '^[a-z]$'
|
523
624
|
echoerr "Invalid register name. Please enter a single lowercase letter (e.g., a, b, c)."
|
524
625
|
return
|
@@ -537,6 +638,30 @@ function! PasteIntoLastVisualSelection()
|
|
537
638
|
endif
|
538
639
|
endfunction
|
539
640
|
|
641
|
+
function! VimLM(...) range
|
642
|
+
let tree_file = s:watched_dir . '/tree'
|
643
|
+
while filereadable(tree_file)
|
644
|
+
sleep 100m
|
645
|
+
endwhile
|
646
|
+
let user_input = join(a:000, ' ')
|
647
|
+
if empty(user_input)
|
648
|
+
echo "Usage: :VimLM <prompt> [!command1] [!command2] ..."
|
649
|
+
return
|
650
|
+
endif
|
651
|
+
if line("'<") == line("'>")
|
652
|
+
silent! execute "normal! V\<ESC>"
|
653
|
+
endif
|
654
|
+
silent execute "'<,'>w! " . s:watched_dir . "/yank"
|
655
|
+
silent execute "w! " . s:watched_dir . "/context"
|
656
|
+
let user_file = s:watched_dir . '/user'
|
657
|
+
call writefile([user_input], user_file, 'w')
|
658
|
+
let current_file = expand('%:p')
|
659
|
+
call writefile([current_file], tree_file, 'w')
|
660
|
+
call ScrollToTop()
|
661
|
+
endfunction
|
662
|
+
|
663
|
+
command! ToggleVimLM call ToggleVimLM()
|
664
|
+
command! -range -nargs=+ VimLM call VimLM(<f-args>)
|
540
665
|
nnoremap $mapp :call PasteIntoLastVisualSelection()<CR>
|
541
666
|
vnoremap $mapp <Cmd>:call PasteIntoLastVisualSelection()<CR>
|
542
667
|
vnoremap $mapl <Cmd>:call VisualPrompt()<CR>
|
@@ -551,7 +676,6 @@ async def main():
|
|
551
676
|
parser.add_argument("vim_args", nargs=argparse.REMAINDER, help="Vim arguments")
|
552
677
|
args = parser.parse_args()
|
553
678
|
if args.test:
|
554
|
-
test()
|
555
679
|
return
|
556
680
|
with tempfile.NamedTemporaryFile(mode='w', suffix='.vim', delete=False) as f:
|
557
681
|
f.write(VIMLMSCRIPT)
|
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
|
-

|
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
|
-

|
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
|
-

|
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
|
File without changes
|
File without changes
|
File without changes
|