vimlm 0.1.0__py3-none-any.whl → 0.1.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-0.1.0.dist-info → vimlm-0.1.1.dist-info}/METADATA +3 -25
- vimlm-0.1.1.dist-info/RECORD +7 -0
- vimlm.py +119 -15
- vimlm-0.1.0.dist-info/RECORD +0 -7
- {vimlm-0.1.0.dist-info → vimlm-0.1.1.dist-info}/LICENSE +0 -0
- {vimlm-0.1.0.dist-info → vimlm-0.1.1.dist-info}/WHEEL +0 -0
- {vimlm-0.1.0.dist-info → vimlm-0.1.1.dist-info}/entry_points.txt +0 -0
- {vimlm-0.1.0.dist-info → vimlm-0.1.1.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: vimlm
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.1
|
4
4
|
Summary: VimLM - LLM-powered Vim assistant
|
5
5
|
Home-page: https://github.com/JosefAlbers/vimlm
|
6
6
|
Author: Josef Albers
|
@@ -55,6 +55,7 @@ vimlm
|
|
55
55
|
|-------------|---------|-----------------------------------------|
|
56
56
|
| `Ctrl-l` | Insert | Generate code suggestion |
|
57
57
|
| `Ctrl-p` | Insert | Insert generated code |
|
58
|
+
| `Ctrl-j` | Insert | Generate and insert code |
|
58
59
|
|
59
60
|
*Example Workflow*:
|
60
61
|
1. Place cursor where you need code
|
@@ -69,7 +70,7 @@ def quicksort(arr):
|
|
69
70
|
return quicksort(left) + middle + quicksort(right)
|
70
71
|
```
|
71
72
|
|
72
|
-
2. `Ctrl-l` to trigger → `Ctrl-p` to insert
|
73
|
+
2. Use `Ctrl-j` to generate and insert the code (or `Ctrl-l` to trigger → `Ctrl-p` to insert)
|
73
74
|
|
74
75
|
### **Repository-Level Code Completion**
|
75
76
|
|
@@ -178,29 +179,6 @@ Simplify complex tasks by chaining multiple commands together into a single, reu
|
|
178
179
|
:VimLM Add Google-style docstrings !include % !continue 4000
|
179
180
|
```
|
180
181
|
|
181
|
-
## Smart Autocomplete
|
182
|
-
**Fill code gaps intelligently**
|
183
|
-
|
184
|
-
| Key Binding | Mode | Action |
|
185
|
-
|-------------|---------|-----------------------------------------|
|
186
|
-
| `Ctrl-l` | Insert | Generate code suggestion |
|
187
|
-
| `Ctrl-p` | Insert | Insert generated code |
|
188
|
-
|
189
|
-
*Example Workflow*:
|
190
|
-
1. Place cursor where you need code
|
191
|
-
```python
|
192
|
-
def quicksort(arr):
|
193
|
-
if len(arr) <= 1:
|
194
|
-
return arr
|
195
|
-
pivot = arr[len(arr) // 2]
|
196
|
-
# <Cursor here>
|
197
|
-
middle = [x for x in arr if x == pivot]
|
198
|
-
right = [x for x in arr if x > pivot]
|
199
|
-
return quicksort(left) + middle + quicksort(right)
|
200
|
-
```
|
201
|
-
|
202
|
-
2. `Ctrl-l` to trigger → `Ctrl-p` to insert
|
203
|
-
|
204
182
|
## Configuration
|
205
183
|
|
206
184
|
### 1. **Model Settings**
|
@@ -0,0 +1,7 @@
|
|
1
|
+
vimlm.py,sha256=C8b9W3HthJhSF5tU5YNK7E26R-7OZJwsezOINSzV_28,33956
|
2
|
+
vimlm-0.1.1.dist-info/LICENSE,sha256=f1xgK8fAXg_intwnbc9nLkHf7ODPLtgpHs7DetQHOro,11343
|
3
|
+
vimlm-0.1.1.dist-info/METADATA,sha256=jjtEcKF0tKJseHGLEQ83AOuz1UC72QG4JVTE3vUaGYM,6359
|
4
|
+
vimlm-0.1.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
5
|
+
vimlm-0.1.1.dist-info/entry_points.txt,sha256=mU5V4MYsuIzCc6YB-Ro-6USSHWN5vHw8UDnTEoq0isw,36
|
6
|
+
vimlm-0.1.1.dist-info/top_level.txt,sha256=I8GjqoiP--scYsO3AfLhha-6Ax9ci3IvbWvVbPv8g94,6
|
7
|
+
vimlm-0.1.1.dist-info/RECORD,,
|
vimlm.py
CHANGED
@@ -29,6 +29,10 @@ from pathlib import Path
|
|
29
29
|
from string import Template
|
30
30
|
import re
|
31
31
|
|
32
|
+
import sys
|
33
|
+
import tty
|
34
|
+
import termios
|
35
|
+
|
32
36
|
DEFAULTS = dict(
|
33
37
|
LLM_MODEL = "mlx-community/Qwen2.5-Coder-3B-Instruct-4bit", # None | "mlx-community/DeepSeek-R1-Distill-Qwen-7B-4bit" | "mlx-community/deepseek-r1-distill-qwen-1.5b" | "mlx-community/phi-4-4bit" (8.25gb) | "mlx-community/Qwen2.5-Coder-14B-Instruct-4bit" (8.31gb) | "mlx-community/Qwen2.5-Coder-3B-Instruct-4bit" (1.74gb)
|
34
38
|
FIM_MODEL = "mlx-community/Qwen2.5-Coder-0.5B-4bit", # None | "mlx-community/Qwen2.5-Coder-32B-4bit" | "mlx-community/Qwen2.5-Coder-0.5B-4bit" (278mb)
|
@@ -40,7 +44,7 @@ DEFAULTS = dict(
|
|
40
44
|
SEP_CMD = '!',
|
41
45
|
THINK = ('<think>', '</think>'),
|
42
46
|
VERSION = '0.1.0',
|
43
|
-
DEBUG =
|
47
|
+
DEBUG = False,
|
44
48
|
)
|
45
49
|
|
46
50
|
DATE_FORM = "%Y_%m_%d_%H_%M_%S"
|
@@ -94,7 +98,7 @@ def toout(s, key=None, mode=None):
|
|
94
98
|
tolog(s, key='tovim'+key+':'+mode)
|
95
99
|
|
96
100
|
def tolog(log, key='debug'):
|
97
|
-
if not DEBUG and
|
101
|
+
if not DEBUG and 'debug' in key:
|
98
102
|
return
|
99
103
|
try:
|
100
104
|
with open(LOG_PATH, "r", encoding="utf-8") as log_f:
|
@@ -692,6 +696,7 @@ function! SplitAtCursorInInsert()
|
|
692
696
|
let current_file = expand('%:p')
|
693
697
|
let tree_file = s:watched_dir . '/tree'
|
694
698
|
call writefile([current_file], tree_file, 'w')
|
699
|
+
call ScrollToTop()
|
695
700
|
endfunction
|
696
701
|
|
697
702
|
function! InsertResponse()
|
@@ -706,16 +711,27 @@ function! InsertResponse()
|
|
706
711
|
let col = col('.')
|
707
712
|
let line = getline('.')
|
708
713
|
if col == len(line) + 1
|
709
|
-
normal! "
|
714
|
+
normal! "zgp
|
710
715
|
else
|
711
|
-
normal! "
|
716
|
+
normal! "zgP
|
712
717
|
endif
|
713
718
|
endfunction
|
714
719
|
|
720
|
+
function! TabInInsert()
|
721
|
+
let wip_file = s:watched_dir . '/wip'
|
722
|
+
call writefile([], wip_file, 'w')
|
723
|
+
call SplitAtCursorInInsert()
|
724
|
+
while filereadable(wip_file)
|
725
|
+
sleep 10m
|
726
|
+
endwhile
|
727
|
+
call InsertResponse()
|
728
|
+
endfunction
|
729
|
+
|
715
730
|
command! ToggleVimLM call ToggleVimLM()
|
716
731
|
command! -range -nargs=+ VimLM call VimLM(<f-args>)
|
717
|
-
inoremap <silent>
|
718
|
-
inoremap <silent>
|
732
|
+
inoremap <silent> $mapl <C-\><C-o>:call SplitAtCursorInInsert()<CR>
|
733
|
+
inoremap <silent> $mapp <C-\><C-o>:call InsertResponse()<CR><Right>
|
734
|
+
inoremap <silent> $mapj <C-\><C-o>:call TabInInsert()<CR><Right>
|
719
735
|
nnoremap $mapp :call PasteIntoLastVisualSelection()<CR>
|
720
736
|
vnoremap $mapp <Cmd>:call PasteIntoLastVisualSelection()<CR>
|
721
737
|
vnoremap $mapl <Cmd>:call VisualPrompt()<CR>
|
@@ -759,6 +775,80 @@ def get_common_dir_and_children(file_paths):
|
|
759
775
|
repo_name = os.path.basename(os.path.dirname(parent_path))
|
760
776
|
return repo_name, parent_path, child_paths
|
761
777
|
|
778
|
+
def get_key():
|
779
|
+
fd = sys.stdin.fileno()
|
780
|
+
old_settings = termios.tcgetattr(fd)
|
781
|
+
try:
|
782
|
+
tty.setraw(sys.stdin.fileno())
|
783
|
+
ch = sys.stdin.read(1)
|
784
|
+
if ch == '\x1b':
|
785
|
+
ch = sys.stdin.read(2)
|
786
|
+
if ch == '[A':
|
787
|
+
return 'up'
|
788
|
+
elif ch == '[B':
|
789
|
+
return 'down'
|
790
|
+
elif ch == 'j':
|
791
|
+
return 'down'
|
792
|
+
elif ch == 'k':
|
793
|
+
return 'up'
|
794
|
+
elif ch in [' ', 'x']:
|
795
|
+
return 'space'
|
796
|
+
elif ch == '\r':
|
797
|
+
return 'enter'
|
798
|
+
elif ch == 'q':
|
799
|
+
return 'quit'
|
800
|
+
finally:
|
801
|
+
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
802
|
+
return None
|
803
|
+
|
804
|
+
def select_files_interactive(file_paths):
|
805
|
+
selected = [False] * len(file_paths)
|
806
|
+
current_row = 0
|
807
|
+
visible_start = 0
|
808
|
+
visible_end = 0
|
809
|
+
max_visible = 10
|
810
|
+
def display():
|
811
|
+
nonlocal visible_start, visible_end
|
812
|
+
visible_start = max(0, current_row - max_visible + 2)
|
813
|
+
visible_end = min(len(file_paths), visible_start + max_visible)
|
814
|
+
sys.stdout.write(f"\x1b[{max_visible + 2}A")
|
815
|
+
for i in range(visible_start, visible_end):
|
816
|
+
prefix = "> " if i == current_row else " "
|
817
|
+
check = "[X]" if selected[i] else "[ ]"
|
818
|
+
filename = os.path.basename(file_paths[i])[:40]
|
819
|
+
sys.stdout.write(f"\x1b[K{prefix}{check} {filename}\n")
|
820
|
+
scroll_indicator = f" [{visible_start+1}-{visible_end} of {len(file_paths)}] "
|
821
|
+
sys.stdout.write(f"\x1b[K{scroll_indicator}\nSpace:Toggle Enter:Confirm Arrows:Navigate\n")
|
822
|
+
sys.stdout.flush()
|
823
|
+
sys.stdout.write("\n" * (max_visible + 2))
|
824
|
+
display()
|
825
|
+
while True:
|
826
|
+
key = get_key()
|
827
|
+
if key == 'up' and current_row > 0:
|
828
|
+
current_row -= 1
|
829
|
+
if current_row < visible_start:
|
830
|
+
visible_start = max(0, visible_start - 1)
|
831
|
+
visible_end = visible_start + max_visible
|
832
|
+
display()
|
833
|
+
elif key == 'down' and current_row < len(file_paths) - 1:
|
834
|
+
current_row += 1
|
835
|
+
if current_row >= visible_end:
|
836
|
+
visible_start = min(len(file_paths) - max_visible, visible_start + 1)
|
837
|
+
visible_end = visible_start + max_visible
|
838
|
+
display()
|
839
|
+
elif key == 'space':
|
840
|
+
selected[current_row] = not selected[current_row]
|
841
|
+
display()
|
842
|
+
elif key == 'enter':
|
843
|
+
sys.stdout.write(f"\x1b[{max_visible + 2}B")
|
844
|
+
sys.stdout.write("\x1b[J")
|
845
|
+
break
|
846
|
+
elif key == 'quit':
|
847
|
+
# selected = []
|
848
|
+
# break
|
849
|
+
return None
|
850
|
+
return [file_paths[i] for i in range(len(file_paths)) if selected[i]]
|
851
|
+
|
762
852
|
def get_repo(args_repo, args_vim):
|
763
853
|
if not args_repo:
|
764
854
|
return None
|
@@ -767,18 +857,32 @@ def get_repo(args_repo, args_vim):
|
|
767
857
|
if not arg.startswith('-'):
|
768
858
|
if os.path.exists(arg):
|
769
859
|
vim_files.append(os.path.abspath(arg))
|
770
|
-
|
771
|
-
rest_files = []
|
860
|
+
repo_paths = []
|
772
861
|
for pattern in args_repo:
|
773
862
|
expanded_paths = glob.glob(pattern)
|
774
863
|
if expanded_paths:
|
775
864
|
for path in expanded_paths:
|
776
|
-
if not os.path.isfile(path) or path in vim_files+
|
865
|
+
if not os.path.isfile(path) or path in vim_files+repo_paths or os.path.basename(path).startswith('.') or is_binary(path):
|
777
866
|
continue
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
867
|
+
repo_paths.append(os.path.abspath(path))
|
868
|
+
if len(repo_paths) > 9:
|
869
|
+
try:
|
870
|
+
sys.stdout.write("\n")
|
871
|
+
selected_paths = select_files_interactive(repo_paths)
|
872
|
+
if not selected_paths:
|
873
|
+
return None
|
874
|
+
sys.stdout.write("\x1b[2A")
|
875
|
+
sys.stdout.write("\x1b[J")
|
876
|
+
repo_paths = selected_paths
|
877
|
+
except:
|
878
|
+
pass
|
879
|
+
repo_files = []
|
880
|
+
rest_files = []
|
881
|
+
for path in repo_paths:
|
882
|
+
if path in vim_files:
|
883
|
+
rest_files.append(os.path.abspath(path))
|
884
|
+
else:
|
885
|
+
repo_files.append(os.path.abspath(path))
|
782
886
|
repo_name, repo_path, child_paths = get_common_dir_and_children(repo_files+rest_files)
|
783
887
|
repo_names, rest_names = child_paths[:len(repo_files)], child_paths[len(repo_files):]
|
784
888
|
list_content = [f'<|repo_name|>{repo_name}\n']
|
@@ -789,7 +893,7 @@ def get_repo(args_repo, args_vim):
|
|
789
893
|
list_content.append(f'<|file_sep|>{n}\n{f.read()}\n')
|
790
894
|
list_mtime.append(int(os.path.getmtime(p)))
|
791
895
|
except Exception as e:
|
792
|
-
tolog(f'Skipped {p} d/t {e}', 'get_repo()')
|
896
|
+
tolog(f'Skipped {p} d/t {e}', 'debug:get_repo()')
|
793
897
|
return dict(repo_files=repo_files, rest_files=rest_files, rest_names=rest_names, vim_files=vim_files, list_mtime=list_mtime, list_content=list_content, repo_path=repo_path)
|
794
898
|
|
795
899
|
def run():
|
@@ -799,7 +903,7 @@ def run():
|
|
799
903
|
parser.add_argument('--repo', nargs='*', help="Paths to directories or files (e.g., assets/*, path/to/file)")
|
800
904
|
args = parser.parse_args()
|
801
905
|
dict_repo = get_repo(args.repo, args.args_vim)
|
802
|
-
tolog(dict_repo, 'get_repo()')
|
906
|
+
tolog(dict_repo, 'debug:get_repo()')
|
803
907
|
if args.test:
|
804
908
|
return
|
805
909
|
reset_dir(WATCH_DIR)
|
vimlm-0.1.0.dist-info/RECORD
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
vimlm.py,sha256=DHobmBa6aYYPUY0altPO2mrf_ZORfNnW2vDRl5Hpx8s,30436
|
2
|
-
vimlm-0.1.0.dist-info/LICENSE,sha256=f1xgK8fAXg_intwnbc9nLkHf7ODPLtgpHs7DetQHOro,11343
|
3
|
-
vimlm-0.1.0.dist-info/METADATA,sha256=H0-gRitfoH9U1MoiV8aEYQam8QYHceR4mSw3z5vbdPA,6959
|
4
|
-
vimlm-0.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
5
|
-
vimlm-0.1.0.dist-info/entry_points.txt,sha256=mU5V4MYsuIzCc6YB-Ro-6USSHWN5vHw8UDnTEoq0isw,36
|
6
|
-
vimlm-0.1.0.dist-info/top_level.txt,sha256=I8GjqoiP--scYsO3AfLhha-6Ax9ci3IvbWvVbPv8g94,6
|
7
|
-
vimlm-0.1.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|