vimlm 0.0.3__py3-none-any.whl → 0.0.4__py3-none-any.whl
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.3.dist-info → vimlm-0.0.4.dist-info}/METADATA +8 -10
- vimlm-0.0.4.dist-info/RECORD +7 -0
- vimlm.py +30 -17
- vimlm-0.0.3.dist-info/RECORD +0 -7
- {vimlm-0.0.3.dist-info → vimlm-0.0.4.dist-info}/LICENSE +0 -0
- {vimlm-0.0.3.dist-info → vimlm-0.0.4.dist-info}/WHEEL +0 -0
- {vimlm-0.0.3.dist-info → vimlm-0.0.4.dist-info}/entry_points.txt +0 -0
- {vimlm-0.0.3.dist-info → vimlm-0.0.4.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,14 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: vimlm
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.4
|
4
4
|
Summary: VimLM - LLM-powered Vim assistant
|
5
5
|
Home-page: https://github.com/JosefAlbers/vimlm
|
6
6
|
Author: Josef Albers
|
7
7
|
Author-email: albersj66@gmail.com
|
8
|
-
Requires-Python: >=3.
|
8
|
+
Requires-Python: >=3.12.8
|
9
9
|
Description-Content-Type: text/markdown
|
10
10
|
License-File: LICENSE
|
11
|
-
Requires-Dist: nanollama==0.0.
|
11
|
+
Requires-Dist: nanollama==0.0.3b0
|
12
12
|
Requires-Dist: watchfiles==1.0.4
|
13
13
|
Dynamic: author
|
14
14
|
Dynamic: author-email
|
@@ -21,11 +21,9 @@ Dynamic: summary
|
|
21
21
|
|
22
22
|
# VimLM - Vim Language Model Assistant for privacy-conscious developers
|
23
23
|
|
24
|
-

|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
Unlike proprietary cloud-based AI models, VimLM runs entirely offline, ensuring complete privacy, data security, and control. You’re not just using a tool—you own it. Fine-tune, modify, or extend it as needed, without reliance on big tech platforms.
|
26
|
+
An 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
27
|
|
30
28
|
## Features
|
31
29
|
|
@@ -70,15 +68,15 @@ vimlm your_file.js
|
|
70
68
|
- Example prompt: "AJAX-ify this app !@#$ ~/scrap/jph00/hypermedia-applications.summ.md"
|
71
69
|
|
72
70
|
5. **Follow-Up**: After initial response:
|
73
|
-
- `Ctrl-
|
71
|
+
- `Ctrl-r`: Continue thread
|
74
72
|
- Example follow-up: "In Manifest V3"
|
75
73
|
|
76
74
|
## Key Bindings
|
77
75
|
|
78
76
|
| Binding | Mode | Action |
|
79
77
|
|------------|---------------|----------------------------------------|
|
80
|
-
| `Ctrl-
|
81
|
-
| `Ctrl-
|
78
|
+
| `Ctrl-l` | Normal/Visual | Send current file + selection to LLM |
|
79
|
+
| `Ctrl-r` | Normal | Continue conversation |
|
82
80
|
| `Esc` | Prompt | Cancel input |
|
83
81
|
|
84
82
|
|
@@ -0,0 +1,7 @@
|
|
1
|
+
vimlm.py,sha256=kCJphqs6B-ZUGzeikiW3u629Nw5Ih3DlDJV1rsKGXAY,13410
|
2
|
+
vimlm-0.0.4.dist-info/LICENSE,sha256=f1xgK8fAXg_intwnbc9nLkHf7ODPLtgpHs7DetQHOro,11343
|
3
|
+
vimlm-0.0.4.dist-info/METADATA,sha256=EdZyb9SyLpy0qyK_jILHa7nrd5G8lPxOm6Xfy7NMfiQ,2832
|
4
|
+
vimlm-0.0.4.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
5
|
+
vimlm-0.0.4.dist-info/entry_points.txt,sha256=mU5V4MYsuIzCc6YB-Ro-6USSHWN5vHw8UDnTEoq0isw,36
|
6
|
+
vimlm-0.0.4.dist-info/top_level.txt,sha256=I8GjqoiP--scYsO3AfLhha-6Ax9ci3IvbWvVbPv8g94,6
|
7
|
+
vimlm-0.0.4.dist-info/RECORD,,
|
vimlm.py
CHANGED
@@ -26,23 +26,35 @@ import tempfile
|
|
26
26
|
from pathlib import Path
|
27
27
|
from string import Template
|
28
28
|
|
29
|
-
DEBUG =
|
29
|
+
DEBUG = True
|
30
30
|
NUM_TOKEN = 2000
|
31
31
|
SEP_CMD = '!@#$'
|
32
|
-
|
32
|
+
VIMLM_DIR = os.path.expanduser("~/vimlm")
|
33
33
|
WATCH_DIR = os.path.expanduser("~/vimlm/watch_dir")
|
34
|
+
CFG_FILE = "cfg.json"
|
34
35
|
LOG_FILE = "log.json"
|
35
|
-
|
36
|
+
LTM_FILE = "cache.json"
|
36
37
|
OUT_FILE = "response.md"
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
IN_FILES = ["context", "yank", "user", "tree"]
|
39
|
+
CFG_PATH = os.path.join(VIMLM_DIR, CFG_FILE)
|
40
|
+
LOG_PATH = os.path.join(VIMLM_DIR, LOG_FILE)
|
41
|
+
LTM_PATH = os.path.join(VIMLM_DIR, LTM_FILE)
|
40
42
|
OUT_PATH = os.path.join(WATCH_DIR, OUT_FILE)
|
41
43
|
|
42
44
|
if os.path.exists(WATCH_DIR):
|
43
45
|
shutil.rmtree(WATCH_DIR)
|
44
46
|
os.makedirs(WATCH_DIR)
|
45
47
|
|
48
|
+
try:
|
49
|
+
with open(CFG_PATH, "r") as f:
|
50
|
+
cfg = cfg.load(f)
|
51
|
+
DEBUG = config.get("DEBUG", DEBUG)
|
52
|
+
NUM_TOKEN = config.get("NUM_TOKEN", NUM_TOKEN)
|
53
|
+
SEP_CMD = config.get("SEP_CMD", SEP_CMD)
|
54
|
+
except:
|
55
|
+
with open(CFG_PATH, 'w') as f:
|
56
|
+
json.dump(dict(DEBUG=DEBUG, NUM_TOKEN=NUM_TOKEN, SEP_CMD=SEP_CMD), f, indent=2)
|
57
|
+
|
46
58
|
def toout(s, key='tovim'):
|
47
59
|
with open(OUT_PATH, 'w', encoding='utf-8') as f:
|
48
60
|
f.write(s)
|
@@ -102,11 +114,11 @@ def split_str(doc, max_len=2000, get_len=len):
|
|
102
114
|
chunks.append("".join(current_chunk))
|
103
115
|
return chunks
|
104
116
|
|
105
|
-
def
|
117
|
+
def retrieve(src_path, max_len=2000, get_len=len):
|
106
118
|
src_path = os.path.expanduser(src_path)
|
107
119
|
result = {}
|
108
120
|
if not os.path.exists(src_path):
|
109
|
-
tolog(f"The path {src_path} does not exist.", '
|
121
|
+
tolog(f"The path {src_path} does not exist.", 'retrieve')
|
110
122
|
return result
|
111
123
|
if os.path.isfile(src_path):
|
112
124
|
try:
|
@@ -114,7 +126,7 @@ def get_context(src_path, max_len=2000, get_len=len):
|
|
114
126
|
content = f.read()
|
115
127
|
result = {src_path:dict(timestamp=os.path.getmtime(src_path), list_str=split_str(content, max_len=max_len, get_len=get_len))}
|
116
128
|
except Exception as e:
|
117
|
-
tolog(f'Skipped {filename} due to {e}', '
|
129
|
+
tolog(f'Skipped {filename} due to {e}', 'retrieve')
|
118
130
|
return result
|
119
131
|
for filename in os.listdir(src_path):
|
120
132
|
try:
|
@@ -126,7 +138,7 @@ def get_context(src_path, max_len=2000, get_len=len):
|
|
126
138
|
content = f.read()
|
127
139
|
result[file_path] = dict(timestamp=os.path.getmtime(file_path), list_str=split_str(content, max_len=max_len, get_len=get_len))
|
128
140
|
except Exception as e:
|
129
|
-
tolog(f'Skipped {filename} due to {e}', '
|
141
|
+
tolog(f'Skipped {filename} due to {e}', 'retrieve')
|
130
142
|
continue
|
131
143
|
return result
|
132
144
|
|
@@ -134,12 +146,12 @@ def get_ntok(s):
|
|
134
146
|
return len(chat.tokenizer.encode(s)[0])
|
135
147
|
|
136
148
|
def ingest(src):
|
137
|
-
def load_cache(cache_path=
|
149
|
+
def load_cache(cache_path=LTM_PATH):
|
138
150
|
if os.path.exists(cache_path):
|
139
151
|
with open(cache_path, 'r', encoding='utf-8') as f:
|
140
152
|
return json.load(f)
|
141
153
|
return {}
|
142
|
-
def dump_cache(new_data, cache_path=
|
154
|
+
def dump_cache(new_data, cache_path=LTM_PATH):
|
143
155
|
current_data = load_cache(cache_path)
|
144
156
|
for k, v in new_data.items():
|
145
157
|
if k not in current_data or v['timestamp'] > current_data[k]['timestamp']:
|
@@ -149,7 +161,7 @@ def ingest(src):
|
|
149
161
|
toout('Ingesting...')
|
150
162
|
format_ingest = '{volat}{incoming}\n\n---\n\nPlease provide a succint bullet point summary for above:'
|
151
163
|
format_volat = 'Here is a summary of part 1 of **{k}**:\n\n---\n\n{newsum}\n\n---\n\nHere is the next part:\n\n---\n\n'
|
152
|
-
dict_doc =
|
164
|
+
dict_doc = retrieve(src, get_len=get_ntok)
|
153
165
|
dict_sum = {}
|
154
166
|
cache = load_cache()
|
155
167
|
for k, v in dict_doc.items():
|
@@ -197,10 +209,10 @@ async def monitor_directory():
|
|
197
209
|
async for changes in awatch(WATCH_DIR):
|
198
210
|
found_files = {os.path.basename(f) for _, f in changes}
|
199
211
|
tolog(f'{found_files=}') # DEBUG
|
200
|
-
if
|
212
|
+
if IN_FILES[-1] in found_files and set(IN_FILES).issubset(set(os.listdir(WATCH_DIR))):
|
201
213
|
tolog(f'listdir()={os.listdir(WATCH_DIR)}') # DEBUG
|
202
214
|
data = {}
|
203
|
-
for file in
|
215
|
+
for file in IN_FILES:
|
204
216
|
path = os.path.join(WATCH_DIR, file)
|
205
217
|
with open(path, 'r', encoding='utf-8') as f:
|
206
218
|
data[file] = f.read().strip()
|
@@ -241,8 +253,9 @@ async def process_files(data):
|
|
241
253
|
prompt = str_template.format(**data)
|
242
254
|
tolog(prompt, 'tollm')
|
243
255
|
toout('')
|
244
|
-
response = chat(prompt, max_new=NUM_TOKEN - get_ntok(prompt), verbose=False, stream=OUT_PATH)
|
245
|
-
toout(response)
|
256
|
+
response = chat(prompt, max_new=NUM_TOKEN - get_ntok(prompt), verbose=False, stream=OUT_PATH)
|
257
|
+
toout(response[0][:-10].strip())
|
258
|
+
tolog(response[-1], 'tps')
|
246
259
|
|
247
260
|
VIMLMSCRIPT = Template(r"""
|
248
261
|
let s:watched_dir = expand('$WATCH_DIR')
|
vimlm-0.0.3.dist-info/RECORD
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
vimlm.py,sha256=ku7NOIrcCNHzRYP9_8qp1NX8w5uCiZAlf0ijMKJXTlw,12996
|
2
|
-
vimlm-0.0.3.dist-info/LICENSE,sha256=f1xgK8fAXg_intwnbc9nLkHf7ODPLtgpHs7DetQHOro,11343
|
3
|
-
vimlm-0.0.3.dist-info/METADATA,sha256=i4W8tmpaMH1m86vzEwNpwo9BUfYcLzr3nksEU_iGW6Y,3178
|
4
|
-
vimlm-0.0.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
5
|
-
vimlm-0.0.3.dist-info/entry_points.txt,sha256=mU5V4MYsuIzCc6YB-Ro-6USSHWN5vHw8UDnTEoq0isw,36
|
6
|
-
vimlm-0.0.3.dist-info/top_level.txt,sha256=I8GjqoiP--scYsO3AfLhha-6Ax9ci3IvbWvVbPv8g94,6
|
7
|
-
vimlm-0.0.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|