vimlm 0.0.1__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/__init__.py ADDED
File without changes
vimlm/main.py ADDED
@@ -0,0 +1,72 @@
1
+ import argparse
2
+ import subprocess
3
+ import tempfile
4
+ import os
5
+ from pathlib import Path
6
+
7
+ VIM_CONFIG = """
8
+ let s:watched_dir = expand('~/watched_dir')
9
+
10
+ function! Monitor()
11
+ write
12
+ let response_path = s:watched_dir . '/response.md'
13
+ rightbelow vsplit | execute 'view ' . response_path
14
+ setlocal autoread
15
+ setlocal readonly
16
+ setlocal nobuflisted
17
+ filetype detect
18
+ syntax on
19
+ wincmd h
20
+ let s:monitor_timer = timer_start(1000, 'CheckForUpdates', {'repeat': -1})
21
+ endfunction
22
+
23
+ function! CheckForUpdates(timer)
24
+ let bufnum = bufnr(s:watched_dir . '/response.md')
25
+ if bufnum == -1
26
+ call timer_stop(s:monitor_timer)
27
+ return
28
+ endif
29
+ silent! checktime
30
+ endfunction
31
+
32
+ function! SaveUserInput()
33
+ let user_input = input('Ask LLM: ')
34
+ let user_file = s:watched_dir . '/user'
35
+ call writefile([user_input], user_file, 'w')
36
+ let current_file = expand('%:t')
37
+ let tree_file = s:watched_dir . '/tree'
38
+ call writefile([current_file], tree_file, 'w')
39
+ endfunction
40
+
41
+ vnoremap <c-l> :w! ~/watched_dir/yank<CR>:w! ~/watched_dir/context<CR>:call SaveUserInput()<CR>
42
+ nnoremap <c-l> V:w! ~/watched_dir/yank<CR>:w! ~/watched_dir/context<CR>:call SaveUserInput()<CR>
43
+
44
+ call Monitor()
45
+ """
46
+
47
+ def main():
48
+ parser = argparse.ArgumentParser(description="VimLM - LLM-powered Vim assistant")
49
+ parser.add_argument("vim_args", nargs=argparse.REMAINDER, help="Additional Vim arguments")
50
+ args = parser.parse_args()
51
+ watch_dir = Path.home() / "watched_dir"
52
+ watch_dir.mkdir(exist_ok=True)
53
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.vim', delete=False) as f:
54
+ f.write(VIM_CONFIG)
55
+ vim_script = f.name
56
+ try:
57
+ watcher = subprocess.Popen(
58
+ ["python", "-m", "vimlm.watcher"],
59
+ stdout=(watch_dir / "response.md").open("w"),
60
+ stderr=subprocess.STDOUT,
61
+ )
62
+ vim_command = ["vim", "-c", f"source {vim_script}"]
63
+ if args.vim_args:
64
+ vim_command.extend(args.vim_args)
65
+ subprocess.run(vim_command)
66
+ finally:
67
+ watcher.terminate()
68
+ watcher.wait()
69
+ os.unlink(vim_script)
70
+
71
+ if __name__ == "__main__":
72
+ main()
vimlm/watcher.py ADDED
@@ -0,0 +1,59 @@
1
+ import asyncio
2
+ import subprocess
3
+ import json
4
+ import os
5
+ from watchfiles import awatch
6
+ from nanollama32 import Chat
7
+
8
+ DEBUG = False
9
+ NUM_TOKEN = 1000
10
+ DIRECTORY = os.path.expanduser("~/watched_dir")
11
+ OUT_FILE = "response.md"
12
+ LOG_FILE = "log.json"
13
+ FILES = ["context", "yank", "user", "tree"]
14
+
15
+ out_path = os.path.join(DIRECTORY, OUT_FILE)
16
+ log_path = os.path.join(DIRECTORY, LOG_FILE)
17
+ os.makedirs(DIRECTORY, exist_ok=True)
18
+ chat = Chat(variant='uncn_llama_32_3b_it')
19
+
20
+ with open(out_path, "w", encoding="utf-8") as f:
21
+ f.write('LLM is ready')
22
+
23
+ async def monitor_directory():
24
+ async for changes in awatch(DIRECTORY):
25
+ found_files = {os.path.basename(f) for _, f in changes}
26
+ if FILES[-1] in found_files and set(FILES).issubset(set(os.listdir(DIRECTORY))):
27
+ await process_files()
28
+
29
+ async def process_files():
30
+ data = {}
31
+ for file in FILES:
32
+ path = os.path.join(DIRECTORY, file)
33
+ with open(path, "r", encoding="utf-8") as f:
34
+ data[file] = f.read().strip()
35
+ os.remove(path)
36
+ data['ext'] = data['tree'].split('.')[-1]
37
+ if len(data['yank']) > 0:
38
+ str_template = "**{tree}**\n```{ext}\n{context}\n```\n\n```{ext}\n{yank}\n```\n\n{user}" if '\n' in data['yank'] else "**{tree}**\n```{ext}\n{context}\n```\n\n`{yank}` {user}"
39
+ else:
40
+ str_template = "**{tree}**\n```{ext}\n{context}\n\n```\n\n{user}"
41
+ prompt = str_template.format(**data)
42
+ with open(out_path, "w", encoding="utf-8") as f:
43
+ f.write('')
44
+ response = chat(prompt, max_new=NUM_TOKEN, verbose=DEBUG, stream=out_path)[0][:-10].strip()
45
+ with open(out_path, "w", encoding="utf-8") as f:
46
+ f.write(response)
47
+ chat.reset()
48
+ if DEBUG:
49
+ if os.path.exists(log_path):
50
+ with open(log_path, "r", encoding="utf-8") as log_f:
51
+ logs = json.load(log_f)
52
+ else:
53
+ logs = []
54
+ logs.append({'prompt':prompt, 'respone':response})
55
+ with open(log_path, "w", encoding="utf-8") as log_f:
56
+ json.dump(logs, log_f, indent=2)
57
+
58
+ asyncio.run(monitor_directory())
59
+
@@ -0,0 +1,55 @@
1
+ Metadata-Version: 2.2
2
+ Name: vimlm
3
+ Version: 0.0.1
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.13.1
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: nanollama==0.0.3
11
+ Requires-Dist: watchfiles==1.0.4
12
+ Dynamic: author
13
+ Dynamic: author-email
14
+ Dynamic: description
15
+ Dynamic: description-content-type
16
+ Dynamic: home-page
17
+ Dynamic: requires-dist
18
+ Dynamic: requires-python
19
+ Dynamic: summary
20
+
21
+ # VimLM - LLM-powered Vim assistant
22
+
23
+ ## Features
24
+
25
+ - Real-time code assistance using local LLMs
26
+ - Context-aware suggestions based on your current file
27
+ - Split-window interface showing LLM responses
28
+ - Simple keybinding integration with Vim
29
+ - Works completely offline with local models
30
+
31
+ ## Installation
32
+
33
+ ```zsh
34
+ pip install vimlm
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ 1. Start Vim with VimLM:
40
+
41
+ ```zsh
42
+ vimlm your_file.js
43
+ ```
44
+
45
+ 2. Use the key bindings in Vim:
46
+ - `Ctrl-L` in normal mode: Get suggestions for current line
47
+ - `Ctrl-L` in visual mode: Get suggestions for selected code
48
+
49
+ The LLM response will appear in a split window on the right side of your Vim interface.
50
+
51
+ ## Demo
52
+
53
+ ![vimlm](https://github.com/user-attachments/assets/4aa39efe-aa6d-4363-8fe1-cf964d7f849c)
54
+
55
+
@@ -0,0 +1,8 @@
1
+ vimlm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ vimlm/main.py,sha256=oquliLkQSdPgPBf0sUBBSu7ZZAeerLMkms3H8kXBmIw,2164
3
+ vimlm/watcher.py,sha256=4xI6LE-IhtgvLU8ho_pXCBL5vx8xRkkgQq9Iwr8-jeQ,2075
4
+ vimlm-0.0.1.dist-info/METADATA,sha256=-4HQ3JOHYnfnCmVJ1Yej_7DKGOVzYrwJeQ9vjkV3Dzw,1246
5
+ vimlm-0.0.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
6
+ vimlm-0.0.1.dist-info/entry_points.txt,sha256=s1QPno-YPS74cjm8JI_FeZqYpKO-QrTThGXUwl9shqk,42
7
+ vimlm-0.0.1.dist-info/top_level.txt,sha256=I8GjqoiP--scYsO3AfLhha-6Ax9ci3IvbWvVbPv8g94,6
8
+ vimlm-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.8.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ vimlm = vimlm.main:main
@@ -0,0 +1 @@
1
+ vimlm