autocoder-nano 0.1.33__py3-none-any.whl → 0.1.34__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.
- autocoder_nano/auto_coder_nano.py +26 -621
- autocoder_nano/llm_types.py +19 -2
- autocoder_nano/utils/completer_utils.py +616 -0
- autocoder_nano/version.py +1 -1
- {autocoder_nano-0.1.33.dist-info → autocoder_nano-0.1.34.dist-info}/METADATA +1 -1
- {autocoder_nano-0.1.33.dist-info → autocoder_nano-0.1.34.dist-info}/RECORD +10 -9
- {autocoder_nano-0.1.33.dist-info → autocoder_nano-0.1.34.dist-info}/LICENSE +0 -0
- {autocoder_nano-0.1.33.dist-info → autocoder_nano-0.1.34.dist-info}/WHEEL +0 -0
- {autocoder_nano-0.1.33.dist-info → autocoder_nano-0.1.34.dist-info}/entry_points.txt +0 -0
- {autocoder_nano-0.1.33.dist-info → autocoder_nano-0.1.34.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,6 @@ import os
|
|
5
5
|
import json
|
6
6
|
import shutil
|
7
7
|
import subprocess
|
8
|
-
import textwrap
|
9
8
|
import time
|
10
9
|
import uuid
|
11
10
|
|
@@ -18,6 +17,7 @@ from autocoder_nano.index.index_manager import IndexManager
|
|
18
17
|
from autocoder_nano.index.symbols_utils import extract_symbols
|
19
18
|
from autocoder_nano.llm_client import AutoLLM
|
20
19
|
from autocoder_nano.rules.rules_learn import AutoRulesLearn
|
20
|
+
from autocoder_nano.utils.completer_utils import CommandCompleter
|
21
21
|
from autocoder_nano.version import __version__
|
22
22
|
from autocoder_nano.llm_types import *
|
23
23
|
from autocoder_nano.llm_prompt import prompt, extract_code
|
@@ -29,23 +29,20 @@ from autocoder_nano.project import PyProject, SuffixProject
|
|
29
29
|
from autocoder_nano.utils.printer_utils import Printer
|
30
30
|
|
31
31
|
import yaml
|
32
|
-
# import tabulate
|
33
32
|
from jinja2 import Template
|
34
|
-
# from loguru import logger
|
35
33
|
from prompt_toolkit import prompt as _toolkit_prompt, PromptSession
|
36
|
-
from prompt_toolkit.completion import Completer, Completion
|
37
34
|
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
38
35
|
from prompt_toolkit.formatted_text import FormattedText
|
39
36
|
from prompt_toolkit.history import InMemoryHistory
|
40
37
|
from prompt_toolkit.key_binding import KeyBindings
|
41
38
|
from prompt_toolkit.shortcuts import confirm
|
42
39
|
from prompt_toolkit.styles import Style
|
43
|
-
from rich.console import Console
|
40
|
+
# from rich.console import Console
|
44
41
|
from rich.live import Live
|
45
42
|
from rich.markdown import Markdown
|
46
43
|
from rich.panel import Panel
|
47
44
|
from rich.syntax import Syntax
|
48
|
-
from rich.table import Table
|
45
|
+
# from rich.table import Table
|
49
46
|
from rich.text import Text
|
50
47
|
|
51
48
|
|
@@ -181,604 +178,6 @@ def find_files_in_project(patterns: List[str]) -> List[str]:
|
|
181
178
|
return list(set(matched_files))
|
182
179
|
|
183
180
|
|
184
|
-
COMMANDS = {
|
185
|
-
"/add_files": {
|
186
|
-
"/group": {"/add": "", "/drop": "", "/reset": ""},
|
187
|
-
"/refresh": "",
|
188
|
-
},
|
189
|
-
"/remove_files": {"/all": ""},
|
190
|
-
"/coding": {"/apply": ""},
|
191
|
-
"/chat": {"/history": "", "/new": "", "/review": ""},
|
192
|
-
"/models": {"/add_model": "", "/remove": "", "/list": "", "/check": ""},
|
193
|
-
"/help": {
|
194
|
-
"/add_files": "",
|
195
|
-
"/remove_files": "",
|
196
|
-
"/chat": "",
|
197
|
-
"/coding": "",
|
198
|
-
"/commit": "",
|
199
|
-
"/conf": "",
|
200
|
-
"/mode": "",
|
201
|
-
"/models": ""
|
202
|
-
},
|
203
|
-
"/exclude_files": {"/list": "", "/drop": ""},
|
204
|
-
"/exclude_dirs": {},
|
205
|
-
"/rules": {"/list": "", "/show": "", "/remove": "", "/analyze": "", "/commit": ""}
|
206
|
-
}
|
207
|
-
|
208
|
-
|
209
|
-
class CommandTextParser:
|
210
|
-
def __init__(self, text: str, command: str):
|
211
|
-
self.text = text
|
212
|
-
self.pos = -1
|
213
|
-
self.len = len(text)
|
214
|
-
self.is_extracted = False
|
215
|
-
self.current_word_start_pos = 0
|
216
|
-
self.current_word_end_pos = 0
|
217
|
-
self.in_current_sub_command = ""
|
218
|
-
self.completions = []
|
219
|
-
self.command = command
|
220
|
-
self.current_hiararchy = COMMANDS[command]
|
221
|
-
self.sub_commands = []
|
222
|
-
self.tags = []
|
223
|
-
|
224
|
-
def first_sub_command(self):
|
225
|
-
if len(self.sub_commands) == 0:
|
226
|
-
return None
|
227
|
-
return self.sub_commands[0]
|
228
|
-
|
229
|
-
def last_sub_command(self):
|
230
|
-
if len(self.sub_commands) == 0:
|
231
|
-
return None
|
232
|
-
return self.sub_commands[-1]
|
233
|
-
|
234
|
-
def peek(self):
|
235
|
-
if self.pos + 1 < self.len:
|
236
|
-
return self.text[self.pos + 1]
|
237
|
-
return None
|
238
|
-
|
239
|
-
def peek2(self):
|
240
|
-
if self.pos + 2 < self.len:
|
241
|
-
return self.text[self.pos + 2]
|
242
|
-
return None
|
243
|
-
|
244
|
-
def peek3(self):
|
245
|
-
if self.pos + 3 < self.len:
|
246
|
-
return self.text[self.pos + 3]
|
247
|
-
return None
|
248
|
-
|
249
|
-
def next(self):
|
250
|
-
if self.pos < self.len - 1:
|
251
|
-
self.pos += 1
|
252
|
-
char = self.text[self.pos]
|
253
|
-
return char
|
254
|
-
return None
|
255
|
-
|
256
|
-
def consume_blank(self):
|
257
|
-
while self.peek() == "\n" or self.peek() == " " or self.peek() == "\t" or self.peek() == "\r":
|
258
|
-
self.next()
|
259
|
-
|
260
|
-
def is_blank(self) -> bool:
|
261
|
-
return self.peek() == "\n" or self.peek() == " " or self.peek() == "\t" or self.peek() == "\r"
|
262
|
-
|
263
|
-
def is_sub_command(self) -> bool | None:
|
264
|
-
backup_pos = self.pos
|
265
|
-
self.consume_blank()
|
266
|
-
try:
|
267
|
-
if self.peek() == "/":
|
268
|
-
current_sub_command = ""
|
269
|
-
while self.peek() is not None and self.peek() != " " and self.peek() != "\n":
|
270
|
-
current_sub_command += self.next()
|
271
|
-
|
272
|
-
if current_sub_command.count("/") > 1:
|
273
|
-
self.pos = backup_pos
|
274
|
-
return False
|
275
|
-
return True
|
276
|
-
return False
|
277
|
-
finally:
|
278
|
-
self.pos = backup_pos
|
279
|
-
|
280
|
-
def consume_sub_command(self) -> str:
|
281
|
-
# backup_pos = self.pos
|
282
|
-
self.consume_blank()
|
283
|
-
current_sub_command = ""
|
284
|
-
while self.peek() is not None and self.peek() != " " and self.peek() != "\n":
|
285
|
-
current_sub_command += self.next()
|
286
|
-
|
287
|
-
if self.peek() is None:
|
288
|
-
self.is_extracted = True
|
289
|
-
self.current_word_end_pos = self.pos + 1
|
290
|
-
self.current_word_start_pos = self.current_word_end_pos - len(
|
291
|
-
current_sub_command
|
292
|
-
)
|
293
|
-
self.in_current_sub_command = current_sub_command
|
294
|
-
else:
|
295
|
-
if current_sub_command in self.current_hiararchy:
|
296
|
-
self.current_hiararchy = self.current_hiararchy[current_sub_command]
|
297
|
-
self.sub_commands.append(current_sub_command)
|
298
|
-
|
299
|
-
return current_sub_command
|
300
|
-
|
301
|
-
def consume_command_value(self):
|
302
|
-
current_word = ""
|
303
|
-
while self.peek() is not None:
|
304
|
-
v = self.next()
|
305
|
-
if v == " ":
|
306
|
-
current_word = ""
|
307
|
-
else:
|
308
|
-
current_word += v
|
309
|
-
self.is_extracted = True
|
310
|
-
self.current_word_end_pos = self.pos + 1
|
311
|
-
self.current_word_start_pos = self.current_word_end_pos - len(current_word)
|
312
|
-
|
313
|
-
def previous(self):
|
314
|
-
if self.pos > 1:
|
315
|
-
return self.text[self.pos - 1]
|
316
|
-
return None
|
317
|
-
|
318
|
-
def is_start_tag(self) -> bool | None:
|
319
|
-
backup_pos = self.pos
|
320
|
-
tag = ""
|
321
|
-
try:
|
322
|
-
if self.peek() == "<" and self.peek2() != "/":
|
323
|
-
while (
|
324
|
-
self.peek() is not None
|
325
|
-
and self.peek() != ">"
|
326
|
-
and not self.is_blank()
|
327
|
-
):
|
328
|
-
tag += self.next()
|
329
|
-
if self.peek() == ">":
|
330
|
-
tag += self.next()
|
331
|
-
return True
|
332
|
-
else:
|
333
|
-
return False
|
334
|
-
return False
|
335
|
-
finally:
|
336
|
-
self.pos = backup_pos
|
337
|
-
|
338
|
-
def consume_tag(self):
|
339
|
-
start_tag = ""
|
340
|
-
content = ""
|
341
|
-
end_tag = ""
|
342
|
-
|
343
|
-
# consume start tag
|
344
|
-
self.current_word_start_pos = self.pos + 1
|
345
|
-
while self.peek() is not None and self.peek() != ">" and not self.is_blank():
|
346
|
-
start_tag += self.next()
|
347
|
-
if self.peek() == ">":
|
348
|
-
start_tag += self.next()
|
349
|
-
self.current_word_end_pos = self.pos + 1
|
350
|
-
tag = Tag(start_tag=start_tag, content=content, end_tag=end_tag)
|
351
|
-
self.tags.append(tag)
|
352
|
-
|
353
|
-
# consume content
|
354
|
-
self.current_word_start_pos = self.pos + 1
|
355
|
-
while self.peek() is not None and not (
|
356
|
-
self.peek() == "<" and self.peek2() == "/"
|
357
|
-
):
|
358
|
-
content += self.next()
|
359
|
-
|
360
|
-
tag.content = content
|
361
|
-
self.current_word_end_pos = self.pos + 1
|
362
|
-
|
363
|
-
# consume end tag
|
364
|
-
self.current_word_start_pos = self.pos + 1
|
365
|
-
if self.peek() == "<" and self.peek2() == "/":
|
366
|
-
while (
|
367
|
-
self.peek() is not None and self.peek() != ">" and not self.is_blank()
|
368
|
-
):
|
369
|
-
end_tag += self.next()
|
370
|
-
if self.peek() == ">":
|
371
|
-
end_tag += self.next()
|
372
|
-
tag.end_tag = end_tag
|
373
|
-
self.current_word_end_pos = self.pos + 1
|
374
|
-
|
375
|
-
# check is finished
|
376
|
-
if self.peek() is None:
|
377
|
-
self.is_extracted = True
|
378
|
-
|
379
|
-
def consume_coding_value(self):
|
380
|
-
current_word = ""
|
381
|
-
while self.peek() is not None and not self.is_start_tag():
|
382
|
-
v = self.next()
|
383
|
-
if v == " ":
|
384
|
-
current_word = ""
|
385
|
-
else:
|
386
|
-
current_word += v
|
387
|
-
if self.peek() is None:
|
388
|
-
self.is_extracted = True
|
389
|
-
|
390
|
-
self.current_word_end_pos = self.pos + 1
|
391
|
-
self.current_word_start_pos = self.current_word_end_pos - len(current_word)
|
392
|
-
|
393
|
-
def current_word(self) -> str:
|
394
|
-
return self.text[self.current_word_start_pos: self.current_word_end_pos]
|
395
|
-
|
396
|
-
def get_current_word(self) -> str:
|
397
|
-
return self.current_word()
|
398
|
-
|
399
|
-
def get_sub_commands(self) -> list[str]:
|
400
|
-
if self.get_current_word() and not self.get_current_word().startswith("/"):
|
401
|
-
return []
|
402
|
-
|
403
|
-
if isinstance(self.current_hiararchy, str):
|
404
|
-
return []
|
405
|
-
|
406
|
-
return [item for item in list(self.current_hiararchy.keys()) if item]
|
407
|
-
|
408
|
-
def add_files(self):
|
409
|
-
"""
|
410
|
-
for exmaple:
|
411
|
-
/add_files file1 file2 file3
|
412
|
-
/add_files /group/abc/cbd /group/abc/bc2
|
413
|
-
/add_files /group1 /add xxxxx
|
414
|
-
/add_files /group
|
415
|
-
/add_files /group /add <groupname>
|
416
|
-
/add_files /group /drop <groupname>
|
417
|
-
/add_files /group <groupname>,<groupname>
|
418
|
-
/add_files /refresh
|
419
|
-
"""
|
420
|
-
while True:
|
421
|
-
if self.pos == self.len - 1:
|
422
|
-
break
|
423
|
-
elif self.is_extracted:
|
424
|
-
break
|
425
|
-
elif self.is_sub_command():
|
426
|
-
self.consume_sub_command()
|
427
|
-
else:
|
428
|
-
self.consume_command_value()
|
429
|
-
return self
|
430
|
-
|
431
|
-
def coding(self):
|
432
|
-
while True:
|
433
|
-
if self.pos == self.len - 1:
|
434
|
-
break
|
435
|
-
elif self.is_extracted:
|
436
|
-
break
|
437
|
-
elif self.is_sub_command():
|
438
|
-
self.consume_sub_command()
|
439
|
-
elif self.is_start_tag():
|
440
|
-
self.consume_tag()
|
441
|
-
else:
|
442
|
-
self.consume_coding_value()
|
443
|
-
|
444
|
-
|
445
|
-
class CommandCompleter(Completer):
|
446
|
-
def __init__(self, _commands):
|
447
|
-
self.commands = _commands
|
448
|
-
self.all_file_names = get_all_file_names_in_project()
|
449
|
-
self.all_files = get_all_file_in_project()
|
450
|
-
self.all_dir_names = get_all_dir_names_in_project()
|
451
|
-
self.all_files_with_dot = get_all_file_in_project_with_dot()
|
452
|
-
self.symbol_list = get_symbol_list()
|
453
|
-
self.current_file_names = []
|
454
|
-
|
455
|
-
def get_completions(self, document, complete_event):
|
456
|
-
text = document.text_before_cursor
|
457
|
-
words = text.split()
|
458
|
-
|
459
|
-
if len(words) > 0:
|
460
|
-
if words[0] == "/mode":
|
461
|
-
left_word = text[len("/mode"):]
|
462
|
-
for mode in ["normal", "auto_detect"]:
|
463
|
-
if mode.startswith(left_word.strip()):
|
464
|
-
yield Completion(mode, start_position=-len(left_word.strip()))
|
465
|
-
|
466
|
-
if words[0] == "/add_files":
|
467
|
-
new_text = text[len("/add_files"):]
|
468
|
-
parser = CommandTextParser(new_text, words[0])
|
469
|
-
parser.add_files()
|
470
|
-
current_word = parser.current_word()
|
471
|
-
|
472
|
-
if parser.last_sub_command() == "/refresh":
|
473
|
-
return
|
474
|
-
|
475
|
-
for command in parser.get_sub_commands():
|
476
|
-
if command.startswith(current_word):
|
477
|
-
yield Completion(command, start_position=-len(current_word))
|
478
|
-
|
479
|
-
if parser.first_sub_command() == "/group" and (
|
480
|
-
parser.last_sub_command() == "/group"
|
481
|
-
or parser.last_sub_command() == "/drop"
|
482
|
-
):
|
483
|
-
group_names = memory["current_files"]["groups"].keys()
|
484
|
-
if "," in current_word:
|
485
|
-
current_word = current_word.split(",")[-1]
|
486
|
-
|
487
|
-
for group_name in group_names:
|
488
|
-
if group_name.startswith(current_word):
|
489
|
-
yield Completion(
|
490
|
-
group_name, start_position=-len(current_word)
|
491
|
-
)
|
492
|
-
|
493
|
-
if parser.first_sub_command() != "/group":
|
494
|
-
if current_word and current_word.startswith("."):
|
495
|
-
for file_name in self.all_files_with_dot:
|
496
|
-
if file_name.startswith(current_word):
|
497
|
-
yield Completion(file_name, start_position=-len(current_word))
|
498
|
-
else:
|
499
|
-
for file_name in self.all_file_names:
|
500
|
-
if file_name.startswith(current_word):
|
501
|
-
yield Completion(file_name, start_position=-len(current_word))
|
502
|
-
for file_name in self.all_files:
|
503
|
-
if current_word and current_word in file_name:
|
504
|
-
yield Completion(file_name, start_position=-len(current_word))
|
505
|
-
|
506
|
-
elif words[0] in ["/chat", "/coding"]:
|
507
|
-
image_extensions = (
|
508
|
-
".png", ".jpg", ".jpeg", ".gif", ".bmp", ".tiff", ".tif", ".webp", ".svg", ".ico",
|
509
|
-
".heic", ".heif", ".raw", ".cr2", ".nef", ".arw", ".dng", ".orf", ".rw2", ".pef",
|
510
|
-
".srw", ".eps", ".ai", ".psd", ".xcf",
|
511
|
-
)
|
512
|
-
new_text = text[len(words[0]):]
|
513
|
-
parser = CommandTextParser(new_text, words[0])
|
514
|
-
|
515
|
-
parser.coding()
|
516
|
-
current_word = parser.current_word()
|
517
|
-
|
518
|
-
if len(new_text.strip()) == 0 or new_text.strip() == "/":
|
519
|
-
for command in parser.get_sub_commands():
|
520
|
-
if command.startswith(current_word):
|
521
|
-
yield Completion(command, start_position=-len(current_word))
|
522
|
-
|
523
|
-
all_tags = parser.tags
|
524
|
-
|
525
|
-
if current_word.startswith("@"):
|
526
|
-
name = current_word[1:]
|
527
|
-
target_set = set()
|
528
|
-
|
529
|
-
for file_name in self.current_file_names:
|
530
|
-
base_file_name = os.path.basename(file_name)
|
531
|
-
if name in base_file_name:
|
532
|
-
target_set.add(base_file_name)
|
533
|
-
path_parts = file_name.split(os.sep)
|
534
|
-
display_name = (
|
535
|
-
os.sep.join(path_parts[-3:])
|
536
|
-
if len(path_parts) > 3
|
537
|
-
else file_name
|
538
|
-
)
|
539
|
-
relative_path = os.path.relpath(
|
540
|
-
file_name, project_root)
|
541
|
-
yield Completion(
|
542
|
-
relative_path,
|
543
|
-
start_position=-len(name),
|
544
|
-
display=f"{display_name} (in active files)",
|
545
|
-
)
|
546
|
-
|
547
|
-
for file_name in self.all_file_names:
|
548
|
-
if file_name.startswith(name) and file_name not in target_set:
|
549
|
-
target_set.add(file_name)
|
550
|
-
|
551
|
-
path_parts = file_name.split(os.sep)
|
552
|
-
display_name = (
|
553
|
-
os.sep.join(path_parts[-3:])
|
554
|
-
if len(path_parts) > 3
|
555
|
-
else file_name
|
556
|
-
)
|
557
|
-
relative_path = os.path.relpath(
|
558
|
-
file_name, project_root)
|
559
|
-
|
560
|
-
yield Completion(
|
561
|
-
relative_path,
|
562
|
-
start_position=-len(name),
|
563
|
-
display=f"{display_name}",
|
564
|
-
)
|
565
|
-
|
566
|
-
for file_name in self.all_files:
|
567
|
-
if name in file_name and file_name not in target_set:
|
568
|
-
path_parts = file_name.split(os.sep)
|
569
|
-
display_name = (
|
570
|
-
os.sep.join(path_parts[-3:])
|
571
|
-
if len(path_parts) > 3
|
572
|
-
else file_name
|
573
|
-
)
|
574
|
-
relative_path = os.path.relpath(
|
575
|
-
file_name, project_root)
|
576
|
-
yield Completion(
|
577
|
-
relative_path,
|
578
|
-
start_position=-len(name),
|
579
|
-
display=f"{display_name}",
|
580
|
-
)
|
581
|
-
|
582
|
-
if current_word.startswith("@@"):
|
583
|
-
name = current_word[2:]
|
584
|
-
for symbol in self.symbol_list:
|
585
|
-
if name in symbol.symbol_name:
|
586
|
-
file_name = symbol.file_name
|
587
|
-
path_parts = file_name.split(os.sep)
|
588
|
-
display_name = (
|
589
|
-
os.sep.join(path_parts[-3:])
|
590
|
-
if len(path_parts) > 3
|
591
|
-
else symbol.symbol_name
|
592
|
-
)
|
593
|
-
relative_path = os.path.relpath(
|
594
|
-
file_name, project_root)
|
595
|
-
yield Completion(
|
596
|
-
f"{symbol.symbol_name}(location: {relative_path})",
|
597
|
-
start_position=-len(name),
|
598
|
-
display=f"{symbol.symbol_name} ({display_name}/{symbol.symbol_type})",
|
599
|
-
)
|
600
|
-
|
601
|
-
tags = [tag for tag in parser.tags]
|
602
|
-
|
603
|
-
if current_word.startswith("<"):
|
604
|
-
name = current_word[1:]
|
605
|
-
for tag in ["<img>", "</img>"]:
|
606
|
-
if all_tags and all_tags[-1].start_tag == "<img>":
|
607
|
-
if tag.startswith(name):
|
608
|
-
yield Completion(
|
609
|
-
"</img>", start_position=-len(current_word)
|
610
|
-
)
|
611
|
-
elif tag.startswith(name):
|
612
|
-
yield Completion(tag, start_position=-len(current_word))
|
613
|
-
|
614
|
-
if tags and tags[-1].start_tag == "<img>" and tags[-1].end_tag == "":
|
615
|
-
raw_file_name = tags[0].content
|
616
|
-
file_name = raw_file_name.strip()
|
617
|
-
parent_dir = os.path.dirname(file_name)
|
618
|
-
file_basename = os.path.basename(file_name)
|
619
|
-
search_dir = parent_dir if parent_dir else "."
|
620
|
-
for root, dirs, files in os.walk(search_dir):
|
621
|
-
# 只处理直接子目录
|
622
|
-
if root != search_dir:
|
623
|
-
continue
|
624
|
-
|
625
|
-
# 补全子目录
|
626
|
-
for _dir in dirs:
|
627
|
-
full_path = os.path.join(root, _dir)
|
628
|
-
if full_path.startswith(file_name):
|
629
|
-
relative_path = os.path.relpath(full_path, search_dir)
|
630
|
-
yield Completion(relative_path, start_position=-len(file_basename))
|
631
|
-
|
632
|
-
# 补全文件
|
633
|
-
for file in files:
|
634
|
-
if file.lower().endswith(
|
635
|
-
image_extensions
|
636
|
-
) and file.startswith(file_basename):
|
637
|
-
full_path = os.path.join(root, file)
|
638
|
-
relative_path = os.path.relpath(full_path, search_dir)
|
639
|
-
yield Completion(
|
640
|
-
relative_path,
|
641
|
-
start_position=-len(file_basename),
|
642
|
-
)
|
643
|
-
|
644
|
-
# 只处理一层子目录,然后退出循环
|
645
|
-
break
|
646
|
-
|
647
|
-
elif words[0] == "/remove_files":
|
648
|
-
new_words = text[len("/remove_files"):].strip().split(",")
|
649
|
-
|
650
|
-
is_at_space = text[-1] == " "
|
651
|
-
last_word = new_words[-2] if len(new_words) > 1 else ""
|
652
|
-
current_word = new_words[-1] if new_words else ""
|
653
|
-
|
654
|
-
if is_at_space:
|
655
|
-
last_word = current_word
|
656
|
-
current_word = ""
|
657
|
-
|
658
|
-
# /remove_files /all [cursor] or /remove_files /all p[cursor]
|
659
|
-
if not last_word and not current_word:
|
660
|
-
if "/all".startswith(current_word):
|
661
|
-
yield Completion("/all", start_position=-len(current_word))
|
662
|
-
for file_name in self.current_file_names:
|
663
|
-
yield Completion(file_name, start_position=-len(current_word))
|
664
|
-
|
665
|
-
# /remove_files /a[cursor] or /remove_files p[cursor]
|
666
|
-
if current_word:
|
667
|
-
if "/all".startswith(current_word):
|
668
|
-
yield Completion("/all", start_position=-len(current_word))
|
669
|
-
for file_name in self.current_file_names:
|
670
|
-
if current_word and current_word in file_name:
|
671
|
-
yield Completion(
|
672
|
-
file_name, start_position=-len(current_word)
|
673
|
-
)
|
674
|
-
|
675
|
-
elif words[0] == "/exclude_dirs":
|
676
|
-
new_words = text[len("/exclude_dirs"):].strip().split(",")
|
677
|
-
current_word = new_words[-1]
|
678
|
-
|
679
|
-
for file_name in self.all_dir_names:
|
680
|
-
if current_word and current_word in file_name:
|
681
|
-
yield Completion(file_name, start_position=-len(current_word))
|
682
|
-
|
683
|
-
elif words[0] == "/exclude_files":
|
684
|
-
new_text = text[len("/exclude_files"):]
|
685
|
-
parser = CommandTextParser(new_text, words[0])
|
686
|
-
parser.add_files()
|
687
|
-
current_word = parser.current_word()
|
688
|
-
for command in parser.get_sub_commands():
|
689
|
-
if command.startswith(current_word):
|
690
|
-
yield Completion(command, start_position=-len(current_word))
|
691
|
-
|
692
|
-
elif words[0] == "/models":
|
693
|
-
new_text = text[len("/models"):]
|
694
|
-
parser = CommandTextParser(new_text, words[0])
|
695
|
-
parser.add_files()
|
696
|
-
current_word = parser.current_word()
|
697
|
-
for command in parser.get_sub_commands():
|
698
|
-
if command.startswith(current_word):
|
699
|
-
yield Completion(command, start_position=-len(current_word))
|
700
|
-
|
701
|
-
elif words[0] == "/help":
|
702
|
-
new_text = text[len("/help"):]
|
703
|
-
parser = CommandTextParser(new_text, words[0])
|
704
|
-
parser.add_files()
|
705
|
-
current_word = parser.current_word()
|
706
|
-
for command in parser.get_sub_commands():
|
707
|
-
if command.startswith(current_word):
|
708
|
-
yield Completion(command, start_position=-len(current_word))
|
709
|
-
|
710
|
-
elif words[0] == "/rules":
|
711
|
-
new_text = text[len("/rules"):]
|
712
|
-
parser = CommandTextParser(new_text, words[0])
|
713
|
-
parser.add_files()
|
714
|
-
current_word = parser.current_word()
|
715
|
-
for command in parser.get_sub_commands():
|
716
|
-
if command.startswith(current_word):
|
717
|
-
yield Completion(command, start_position=-len(current_word))
|
718
|
-
|
719
|
-
elif words[0] == "/conf":
|
720
|
-
new_words = text[len("/conf"):].strip().split()
|
721
|
-
is_at_space = text[-1] == " "
|
722
|
-
last_word = new_words[-2] if len(new_words) > 1 else ""
|
723
|
-
current_word = new_words[-1] if new_words else ""
|
724
|
-
completions = []
|
725
|
-
|
726
|
-
if is_at_space:
|
727
|
-
last_word = current_word
|
728
|
-
current_word = ""
|
729
|
-
|
730
|
-
# /conf /drop [curor] or /conf /drop p[cursor]
|
731
|
-
if last_word == "/drop":
|
732
|
-
completions = [
|
733
|
-
field_name
|
734
|
-
for field_name in memory["conf"].keys()
|
735
|
-
if field_name.startswith(current_word)
|
736
|
-
]
|
737
|
-
# /conf [curosr]
|
738
|
-
elif not last_word and not current_word:
|
739
|
-
completions = [
|
740
|
-
"/drop"] if "/drop".startswith(current_word) else []
|
741
|
-
completions += [
|
742
|
-
field_name + ":"
|
743
|
-
for field_name in AutoCoderArgs.model_fields.keys()
|
744
|
-
if field_name.startswith(current_word)
|
745
|
-
]
|
746
|
-
# /conf p[cursor]
|
747
|
-
elif not last_word and current_word:
|
748
|
-
completions = [
|
749
|
-
"/drop"] if "/drop".startswith(current_word) else []
|
750
|
-
completions += [
|
751
|
-
field_name + ":"
|
752
|
-
for field_name in AutoCoderArgs.model_fields.keys()
|
753
|
-
if field_name.startswith(current_word)
|
754
|
-
]
|
755
|
-
|
756
|
-
for completion in completions:
|
757
|
-
yield Completion(completion, start_position=-len(current_word))
|
758
|
-
|
759
|
-
else:
|
760
|
-
for command in self.commands:
|
761
|
-
if command.startswith(text):
|
762
|
-
yield Completion(command, start_position=-len(text))
|
763
|
-
else:
|
764
|
-
for command in self.commands:
|
765
|
-
if command.startswith(text):
|
766
|
-
yield Completion(command, start_position=-len(text))
|
767
|
-
|
768
|
-
def update_current_files(self, files):
|
769
|
-
self.current_file_names = [f for f in files]
|
770
|
-
|
771
|
-
def refresh_files(self):
|
772
|
-
self.all_file_names = get_all_file_names_in_project()
|
773
|
-
self.all_files = get_all_file_in_project()
|
774
|
-
self.all_dir_names = get_all_dir_names_in_project()
|
775
|
-
self.all_files_with_dot = get_all_file_in_project_with_dot()
|
776
|
-
self.symbol_list = get_symbol_list()
|
777
|
-
|
778
|
-
|
779
|
-
completer = CommandCompleter(commands)
|
780
|
-
|
781
|
-
|
782
181
|
def save_memory():
|
783
182
|
with open(os.path.join(base_persist_dir, "nano-memory.json"), "w") as fp:
|
784
183
|
json_str = json.dumps(memory, indent=2, ensure_ascii=False)
|
@@ -792,7 +191,28 @@ def load_memory():
|
|
792
191
|
if os.path.exists(memory_path):
|
793
192
|
with open(memory_path, "r") as f:
|
794
193
|
memory = json.load(f)
|
795
|
-
|
194
|
+
|
195
|
+
|
196
|
+
def get_memory():
|
197
|
+
load_memory()
|
198
|
+
return memory
|
199
|
+
|
200
|
+
|
201
|
+
completer = CommandCompleter(
|
202
|
+
commands=commands,
|
203
|
+
file_system_model=FileSystemModel(
|
204
|
+
project_root=project_root,
|
205
|
+
get_all_file_names_in_project=get_all_file_names_in_project,
|
206
|
+
get_all_file_in_project=get_all_file_in_project,
|
207
|
+
get_all_dir_names_in_project=get_all_dir_names_in_project,
|
208
|
+
get_all_file_in_project_with_dot=get_all_file_in_project_with_dot,
|
209
|
+
get_symbol_list=get_symbol_list
|
210
|
+
),
|
211
|
+
memory_model=MemoryConfig(
|
212
|
+
get_memory_func=get_memory,
|
213
|
+
save_memory_func=save_memory
|
214
|
+
)
|
215
|
+
)
|
796
216
|
|
797
217
|
|
798
218
|
def exclude_dirs(dir_names: List[str]):
|
@@ -938,22 +358,6 @@ def index_import(import_path: str):
|
|
938
358
|
return False
|
939
359
|
|
940
360
|
|
941
|
-
def wrap_text_in_table(data, max_width=60):
|
942
|
-
"""
|
943
|
-
Wraps text in each cell of the table to a specified width.
|
944
|
-
|
945
|
-
:param data: A list of lists, where each inner list represents a row in the table.
|
946
|
-
:param max_width: The maximum width of text in each cell.
|
947
|
-
:return: A new table data with wrapped text.
|
948
|
-
"""
|
949
|
-
wrapped_data = []
|
950
|
-
for row in data:
|
951
|
-
wrapped_row = [textwrap.fill(str(cell), width=max_width) for cell in row]
|
952
|
-
wrapped_data.append(wrapped_row)
|
953
|
-
|
954
|
-
return wrapped_data
|
955
|
-
|
956
|
-
|
957
361
|
def index_query_command(query: str, llm: AutoLLM):
|
958
362
|
update_config_to_args(query=query, delete_execute_file=True)
|
959
363
|
|
@@ -2349,6 +1753,7 @@ def main():
|
|
2349
1753
|
|
2350
1754
|
load_memory()
|
2351
1755
|
is_old_version()
|
1756
|
+
completer.update_current_files(memory["current_files"]["files"])
|
2352
1757
|
|
2353
1758
|
if len(memory["models"]) == 0:
|
2354
1759
|
_model_pass = input(f" 是否跳过模型配置(y/n): ").strip().lower()
|