Thực hiện hoàn thành tên tập tin với cmd là một chút khó khăn vì thư viện readline cơ bản giải thích ký tự đặc biệt như '/' và '-' (và những người khác) như dải phân cách, và điều này đặt ra mà chuỗi con trong dòng là được thay thế bằng các lần hoàn thành.
Ví dụ,
> load /hom<tab>
cuộc gọi complete_load() với
text='hom', line='load /hom', begidx=6, endidx=9
text is line[begidx:endidx]
'text' không phải là "/ hom" vì thư viện readline phân tích dòng và trả về chuỗi sau '/'dấu phân tách. Hàm complete_load() phải trả lại danh sách các chuỗi hoàn thành bắt đầu bằng "hom", không phải "/ hom", vì số lần hoàn thành sẽ thay thế chuỗi con bắt đầu từ begidx. Nếu hàm complete_load() trả về không chính xác ['/ home'], dòng trở thành,
> load //home
không tốt.
Các ký tự khác được coi là dấu phân cách bằng dòng đọc, không chỉ các dấu gạch chéo, do đó bạn không thể giả sử chuỗi con trước 'văn bản' là thư mục chính.Đối với dụ:
> load /home/mike/my-file<tab>
cuộc gọi complete_load() với
text='file', line='load /home/mike/my-file', begidx=19, endidx=23
Giả sử/home/mike chứa các tập tin my-file1 và my-file2, các lần hoàn thành nên [ 'file1', ' file2 '], không phải [' my-file1 ',' my-file2 '], cũng không phải ['/home/mike/my-file1 ','/home/mike/my-file2 ']. Nếu bạn trả lại đường dẫn đầy đủ, kết quả là:
> load /home/mike/my-file/home/mike/my-file1
Cách tiếp cận tôi lấy là sử dụng mô-đun glob để tìm đường dẫn đầy đủ. Glob hoạt động cho đường dẫn tuyệt đối và đường dẫn tương đối. Sau khi tìm thấy các đường dẫn, tôi xóa phần "cố định", là chuỗi con trước dấu ngã.
Đầu tiên, phân tích cú pháp đối số phần cố định, là chuỗi con giữa không gian và begidx.
index = line.rindex(' ', 0, begidx) # -1 if not found
fixed = line[index + 1: begidx]
Đối số nằm giữa khoảng trắng và cuối dòng. Nối một ngôi sao để tạo mẫu tìm kiếm toàn cục.
Tôi nối thêm '/' vào kết quả là thư mục, vì điều này giúp dễ dàng hơn để duyệt thư mục có hoàn thành tab (nếu không bạn cần nhấn phím tab hai lần cho mỗi thư mục). người dùng mục hoàn thành nào là các thư mục và đó là các tệp.
Cuối cùng, hãy xóa phần "cố định" của đường dẫn, vì vậy đường readline sẽ thay thế chỉ phần "văn bản".
import os
import glob
import cmd
def _append_slash_if_dir(p):
if p and os.path.isdir(p) and p[-1] != os.sep:
return p + os.sep
else:
return p
class MyShell(cmd.Cmd):
prompt = "> "
def do_quit(self, line):
return True
def do_load(self, line):
print("load " + line)
def complete_load(self, text, line, begidx, endidx):
before_arg = line.rfind(" ", 0, begidx)
if before_arg == -1:
return # arg not found
fixed = line[before_arg+1:begidx] # fixed portion of the arg
arg = line[before_arg+1:endidx]
pattern = arg + '*'
completions = []
for path in glob.glob(pattern):
path = _append_slash_if_dir(path)
completions.append(path.replace(fixed, "", 1))
return completions
MyShell().cmdloop()
Tôi thấy khó tin rằng không ai trả lời câu hỏi này –