vimlm 0.1.0__tar.gz → 0.1.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: vimlm
3
- Version: 0.1.0
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**
@@ -33,6 +33,7 @@ vimlm
33
33
  |-------------|---------|-----------------------------------------|
34
34
  | `Ctrl-l` | Insert | Generate code suggestion |
35
35
  | `Ctrl-p` | Insert | Insert generated code |
36
+ | `Ctrl-j` | Insert | Generate and insert code |
36
37
 
37
38
  *Example Workflow*:
38
39
  1. Place cursor where you need code
@@ -47,7 +48,7 @@ def quicksort(arr):
47
48
  return quicksort(left) + middle + quicksort(right)
48
49
  ```
49
50
 
50
- 2. `Ctrl-l` to trigger → `Ctrl-p` to insert
51
+ 2. Use `Ctrl-j` to generate and insert the code (or `Ctrl-l` to trigger → `Ctrl-p` to insert)
51
52
 
52
53
  ### **Repository-Level Code Completion**
53
54
 
@@ -156,29 +157,6 @@ Simplify complex tasks by chaining multiple commands together into a single, reu
156
157
  :VimLM Add Google-style docstrings !include % !continue 4000
157
158
  ```
158
159
 
159
- ## Smart Autocomplete
160
- **Fill code gaps intelligently**
161
-
162
- | Key Binding | Mode | Action |
163
- |-------------|---------|-----------------------------------------|
164
- | `Ctrl-l` | Insert | Generate code suggestion |
165
- | `Ctrl-p` | Insert | Insert generated code |
166
-
167
- *Example Workflow*:
168
- 1. Place cursor where you need code
169
- ```python
170
- def quicksort(arr):
171
- if len(arr) <= 1:
172
- return arr
173
- pivot = arr[len(arr) // 2]
174
- # <Cursor here>
175
- middle = [x for x in arr if x == pivot]
176
- right = [x for x in arr if x > pivot]
177
- return quicksort(left) + middle + quicksort(right)
178
- ```
179
-
180
- 2. `Ctrl-l` to trigger → `Ctrl-p` to insert
181
-
182
160
  ## Configuration
183
161
 
184
162
  ### 1. **Model Settings**
@@ -5,7 +5,7 @@ with open("requirements.txt") as f:
5
5
 
6
6
  setup(
7
7
  name="vimlm",
8
- version="0.1.0",
8
+ version="0.1.1",
9
9
  author="Josef Albers",
10
10
  author_email="albersj66@gmail.com",
11
11
  readme='README.md',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: vimlm
3
- Version: 0.1.0
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**
@@ -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 = True,
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 key == 'debug':
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! "zgpa
714
+ normal! "zgp
710
715
  else
711
- normal! "zgPa
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> <C-l> <C-\><C-o>:call SplitAtCursorInInsert()<CR>
718
- inoremap <silent> <C-p> <C-\><C-o>:call InsertResponse()<CR>
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
- repo_files = []
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+repo_files or os.path.basename(path).startswith('.') or is_binary(path):
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
- if path in vim_files:
779
- rest_files.append(os.path.abspath(path))
780
- else:
781
- repo_files.append(os.path.abspath(path))
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)
File without changes
File without changes
File without changes
File without changes