Імя файла закладкі завяршэнне ў Cmd.cmd пітона

Я паўплываюць на стварэнне інструмента каманднага радка з дапамогай Cmd.cmd з Python, і я хачу, каб дадаць каманду «Load» з імем файла аргумент, які падтрымлівае ўкладкі-завяршэння.

Спасылаючыся гэтай і гэта , я вар'ят кодам накшталт гэтага:

import os, cmd, sys, yaml
import os.path as op
import glob as gb

def _complete_path(path):
    if op.isdir(path):
        return gb.glob(op.join(path, '*'))
    else:
        return gb.glob(path+'*')

class CmdHandler(cmd.Cmd):

    def do_load(self, filename):
        try:
            with open(filename, 'r') as f:
                self.cfg = yaml.load(f)
        except:
            print 'fail to load the file "{:}"'.format(filename)

    def complete_load(self, text, line, start_idx, end_idx):
        return _complete_path(text)

Гэта добра працуе для Д, аднак, калі я хачу пайсці ў падкаталог, пасля таго, як падкаталог/тады «тэкст» функцыя complete_load становіцца пустым, таму _complete_path FUNC зноў вяртае вуха.

Я не ведаю, як атрымаць змесціва падкаталог з ўкладкі-завяршэння. Калі ласка, дапамажыце!

6
Я лічу, што цяжка паверыць, што ніхто не адказаў на гэтае пытанне
дададзена аўтар l--'''''&#, крыніца

7 адказы

Ваша галоўная праблема заключаецца ў тым, што Readline бібліятэка размежавання рэчаў заснавана на гэта па змаўчанні набор падзельнікаў:

import readline
readline.get_completer_delims()
# yields ' \t\n`[email protected]#$%^&*()-=+[{]}\\|;:\'",<>/?'

Пры закладцы завяршэння для імя файла я выдаліць усе з гэтага, але прабелы.

import readline
readline.set_completer_delims(' \t\n')

Пасля ўстаноўкі абмежавальнікаў, параметр «тэкст» да вашай функцыі завяршэння павінна быць больш таго, што вы чакаеце.

Гэта таксама ліквідуе часта сустракаемыя праблемы з завяршэннем ўкладкі дублюючы частку тэксту.

5
дададзена

Рэалізацыя завяршэння імя файла з ЦМДОМ крыху больш складана, таму што Асноўная Readline бібліятэка інтэрпрэтуе спецыяльныя сімвалы, такія як «/» і «-» (І іншыя) у якасці падзельнікаў, і гэта вызначае, якую падрадок ў межах радок павінна замяніць дапрацоўкі.

Напрыклад,

> load /hom

выклікае complete_load() з

text='hom', line='load /hom', begidx=6, endidx=9
text is line[begidx:endidx]

«Тэкст» не «/ рупар», таму што Readline бібліятэка разабралі радок і вяртае радок пасля падзельніка «/». Complete_load() павінен вяртаць спіс радкоў канчатка, якія пачынаюцца з «рупара», а не «/ Хом», так як папаўнення заменяць падрадок, якая пачынаецца з begidx. калі Функцыя complete_load() няправільна вяртае [ '/ дом'], лінія становіцца,

> load //home

што не вельмі добра.

Іншыя сімвалы лічацца падзельнікі па Readline, а не толькі касую рысу, так што вы не можаце выказаць здагадку, падрадок, перш чым «тэкст» з'яўляецца бацькоўскім каталогам. для прыклад:

> load /home/mike/my-file

выклікае complete_load() з

text='file', line='load /home/mike/my-file', begidx=19, endidx=23

Мяркуючы, што/дом/мікрафон ўтрымлівае файлы, мой-ФАЙЛ1 і мой-file2, папаўнення павінны быць [ 'file1', 'file2'], а не [ 'мой-file1', 'мой-file2'], ні [ '/ Дом/мікрафон/мой-file1', '/ дом/мікрафон/мой-file2']. Калі вы вяртаеце поўныя шляхі, вынік:

> load /home/mike/my-file/home/mike/my-file1

Падыход, які я ўзяў, каб выкарыстоўваць модуль Глоба, каб знайсці поўныя шляху. Glob працуе для абсалютных шляхоў і адносных шляхоў. Пасля знаходжання шляху, я выдаляю «Фіксаваныя» часткі, якая з'яўляецца падрадок да begidx.

Па-першае, разабраць фіксаванай часткі аргумент, які з'яўляецца падрадок паміж прасторай і begidx.

index = line.rindex(' ', 0, begidx)  # -1 if not found
fixed = line[index + 1: begidx]

Аргумент паміж прасторай і канцом радка. Append зорку зрабіць пошук Глоба шаблон.

Я дадаю сімвал «/» да вынікаў, каталогі, так як гэта робіць яго лягчэй для абыходу каталогаў з завяршэннем ўкладкі (у адваротным выпадку вы павінны ўдарыць Ўкладка ключ двойчы для кожнага каталога), і гэта робіць яго відавочным для карыстальніка якія элементы завяршальныя каталогі і якія файлы.

Нарэшце выдаліць «фіксаваны» частку шляху, так Readline заменіць проста «тэкст» частку.

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()
3
дададзена
Я паспрабаваў падобны падыход, на жаль, ён не апрацоўвае прабелы ў шляху. shlex.split (лінія) не можа дапамагчы Eather, як ён выдаляе прабелы паміж лінейнымі элементамі таму яго не ўдалося знайсці правільны элемент і становішча ў гэтым элеменце. Сапраўды няўдала.
дададзена аўтар Johannes Luong, крыніца
Я мяркую, зрэз будзе больш эфектыўным, чым выклік, каб замяніць (). Проста трэба разлічыць індэкс для зрэзу, нешта накшталт begidx - before_arg.
дададзена аўтар meffie, крыніца

Я не думаю, што гэта лепшы адказ, але я атрымаў функцыю, што я маю намер гэта падабаецца:

def _complete_path(text, line):
    arg = line.split()[1:]
    dir, base = '', ''
    try: 
        dir, base = op.split(arg[-1])
    except:
        pass
    cwd = os.getcwd()
    try: 
        os.chdir(dir)
    except:
        pass
    ret = [f+os.sep if op.isdir(f) else f for f in os.listdir('.') if f.startswith(base)]
    if base == '' or base == '.': 
        ret.extend(['./', '../'])
    elif base == '..':
        ret.append('../')
    os.chdir(cwd)
    return ret

    .............................

    def complete_load(self, text, line, start_idx, end_idx):
        return _complete_path(text, line)

Я не выкарыстоўваў «тэкст» ад complete_cmd (), але выкарыстаць сінтаксічны аналіз «радкі» аргумент непасрэдна. Калі ў вас ёсць якія-небудзь лепш ідэі, калі ласка, дайце мне ведаць.

1
дададзена

Я дасягнуў гэтага рабіць:

def complete_listFolder(self, text, line, begidx, endidx):
    path = os.path.relpath(os.path.normpath(line.split()[1]))
            if not os.path.isdir(path) and not os.path.isfile(path):
                baseName = os.path.basename(path)
                dirName = os.path.dirname(path)
                return fnmatch.filter(os.listdir(dirName), baseName + "*")

            completions = [completion for completion in os.listdir(path)]    
            return completions

Вядома ж ёсць шмат, каб палепшыць, але спадзяюся, што гэта дапамагае.

=)

0
дададзена

У мяне ёсць тая ж ідэя з jinserk, але па-іншаму. Вось мой код:

def complete_load(self, text, line, begidx, endidx):
    arg = line.split()[1:]

    if not arg:
        completions = os.listdir('./')
    else:
        dir, part, base = arg[-1].rpartition('/')
        if part == '':
            dir = './'
        elif dir == '':
            dir = '/'            

        completions = []
        for f in os.listdir(dir):
            if f.startswith(base):
                if os.path.isfile(os.path.join(dir,f)):
                    completions.append(f)
                else:
                    completions.append(f+'/')

    return completions

калі ласка, дайце мне ведаць, калі ў вас ёсць ідэя лепей. Заўвага: Я думаю, што гэты метад працуе толькі на АС сямейства Unix, таму што я ствараю гэты код на аснове структуры каталогаў Unix.

0
дададзена

Я выкарыстоўваю shlex для разбору радка. У адрозненні ад некаторых іншых рашэнняў Я падтрымліваю цытуе і ўцёк шляху (гэта значыць шляху з прабеламі) і завяршэнне работы любой пазіцыі курсора. Я не адчуваў шырока таму прабег можа вар'іравацца.

def path_completion(self, text, line, startidx, endidx):
    try:
        glob_prefix = line[:endidx]

        # add a closing quote if necessary
        quote = ['', '"', "'"]
        while len(quote) > 0:
            try:
                split = [s for s in shlex.split(glob_prefix + quote[0]) if s.strip()]
            except ValueError as ex:
                assert str(ex) == 'No closing quotation', 'Unexpected shlex error'
                quote = quote[1:]
            else:
                break
        assert len(quote) > 0, 'Could not find closing quotation'

        # select relevant line segment
        glob_prefix = split[-1] if len(split) > 1 else ''

        # expand tilde
        glob_prefix = os.path.expanduser(glob_prefix)

        # find matches
        matches = glob.glob(glob_prefix + '*')

        # append os.sep to directories
        matches = [match + os.sep if Path(match).is_dir() else match for match in matches]

        # cutoff prefixes
        cutoff_idx = len(glob_prefix) - len(text)
        matches = [match[cutoff_idx:] for match in matches]

        return matches
    except:
        traceback.print_exc()
0
дададзена

Гэта працуе для мяне. Выдаліце ​​"я", калі вы не выкарыстоўваеце ў класе.

def _complete_path(self, path):
    if os.path.isdir(path):
        return gb.glob(os.path.join(path, '*'))
    else:
        return gb.glob(path + '*')

def complete_load(self, text, line, start_idx, end_idx):
    mline = line.split(' ')[-1]
    offs = len(mline) - len(text)
    completions = []
    if line.split()[-2] == '-p':
        completions = self._complete_path(mline)
    return [s[offs:] for s in completions if s.startswith(mline)]
0
дададзена