Python 的 raw_input() 中的 Tab 补全

发布于 2024-10-31 19:29:09 字数 539 浏览 1 评论 0原文

我知道我可以这样做,以确保在Python中获得制表符完成的效果。

import readline
COMMANDS = ['extra', 'extension', 'stuff', 'errors',
            'email', 'foobar', 'foo']

def complete(text, state):
    for cmd in COMMANDS:
        if cmd.startswith(text):
            if not state:
                return cmd
            else:
                state -= 1

readline.parse_and_bind("tab: complete")
readline.set_completer(complete)
raw_input('Enter section name: ')

我现在对使用目录进行制表符补全感兴趣。 (/home/user/doc >tab)

我将如何去做这样的任务?

i know i can do this to get the effect of tab completion in python sure.

import readline
COMMANDS = ['extra', 'extension', 'stuff', 'errors',
            'email', 'foobar', 'foo']

def complete(text, state):
    for cmd in COMMANDS:
        if cmd.startswith(text):
            if not state:
                return cmd
            else:
                state -= 1

readline.parse_and_bind("tab: complete")
readline.set_completer(complete)
raw_input('Enter section name: ')

I am now interested in doing tab completion with directories. (/home/user/doc >tab)

How would i go about doing such a task?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

旧瑾黎汐 2024-11-07 19:29:09

以下是如何执行文件系统路径增量补全的快速示例。我修改了您的示例,将其组织到一个类中,其中名为 complete_[name] 的方法指示顶级命令。

我已将完成函数切换为使用内部读取行缓冲区来确定整体完成的状态,这使得状态逻辑更简单一些。路径补全位于 _complete_path(path) 方法中,并且我已连接 extra 命令来对其参数执行路径补全。

我确信代码可以进一步简化,但它应该为您提供一个不错的起点:

import os
import re
import readline

COMMANDS = ['extra', 'extension', 'stuff', 'errors',
            'email', 'foobar', 'foo']
RE_SPACE = re.compile('.*\s+

用法:

% python complete.py 
Enter section name: ext<tab>
extension extra
Enter section name: extra foo<tab>
foo.py foo.txt foo/
Enter section name: extra foo/<tab>
foo/bar.txt foo/baz.txt
Enter section name: extra foo/bar.txt

更新如果用户输入/,它将完成从根开始的路径:

% python complete.py
Enter section name: extra /Use<tab>
/Users/.localized  /Users/Shared/  /Users/user1 /Users/user2
Enter section name: extra /Users/use<tab>
/Users/user1  /Users/user2
, re.M) class Completer(object): def _listdir(self, root): "List directory 'root' appending the path separator to subdirs." res = [] for name in os.listdir(root): path = os.path.join(root, name) if os.path.isdir(path): name += os.sep res.append(name) return res def _complete_path(self, path=None): "Perform completion of filesystem path." if not path: return self._listdir('.') dirname, rest = os.path.split(path) tmp = dirname if dirname else '.' res = [os.path.join(dirname, p) for p in self._listdir(tmp) if p.startswith(rest)] # more than one match, or single match which does not exist (typo) if len(res) > 1 or not os.path.exists(path): return res # resolved to a single directory, so return list of files below it if os.path.isdir(path): return [os.path.join(path, p) for p in self._listdir(path)] # exact file match terminates this completion return [path + ' '] def complete_extra(self, args): "Completions for the 'extra' command." if not args: return self._complete_path('.') # treat the last arg as a path and complete it return self._complete_path(args[-1]) def complete(self, text, state): "Generic readline completion entry point." buffer = readline.get_line_buffer() line = readline.get_line_buffer().split() # show all commands if not line: return [c + ' ' for c in COMMANDS][state] # account for last argument ending in a space if RE_SPACE.match(buffer): line.append('') # resolve command to the implementation function cmd = line[0].strip() if cmd in COMMANDS: impl = getattr(self, 'complete_%s' % cmd) args = line[1:] if args: return (impl(args) + [None])[state] return [cmd + ' '][state] results = [c + ' ' for c in COMMANDS if c.startswith(cmd)] + [None] return results[state] comp = Completer() # we want to treat '/' as part of a word, so override the delimiters readline.set_completer_delims(' \t\n;') readline.parse_and_bind("tab: complete") readline.set_completer(comp.complete) raw_input('Enter section name: ')

用法:

更新如果用户输入/,它将完成从根开始的路径:

Here is a quick example of how to perform incremental completion of file system paths. I've modified your example, organizing it into a class where methods named complete_[name] indicate top-level commands.

I've switched the completion function to use the internal readline buffer to determine the state of the overall completion, which makes the state logic a bit simpler. The path completion is in the _complete_path(path) method, and I've hooked up the extra command to perform path completions on its arguments.

I'm sure the code could be further simplified but it should provide you a decent starting point:

import os
import re
import readline

COMMANDS = ['extra', 'extension', 'stuff', 'errors',
            'email', 'foobar', 'foo']
RE_SPACE = re.compile('.*\s+

Usage:

% python complete.py 
Enter section name: ext<tab>
extension extra
Enter section name: extra foo<tab>
foo.py foo.txt foo/
Enter section name: extra foo/<tab>
foo/bar.txt foo/baz.txt
Enter section name: extra foo/bar.txt

Update It will complete paths from the root if the user types /:

% python complete.py
Enter section name: extra /Use<tab>
/Users/.localized  /Users/Shared/  /Users/user1 /Users/user2
Enter section name: extra /Users/use<tab>
/Users/user1  /Users/user2
, re.M) class Completer(object): def _listdir(self, root): "List directory 'root' appending the path separator to subdirs." res = [] for name in os.listdir(root): path = os.path.join(root, name) if os.path.isdir(path): name += os.sep res.append(name) return res def _complete_path(self, path=None): "Perform completion of filesystem path." if not path: return self._listdir('.') dirname, rest = os.path.split(path) tmp = dirname if dirname else '.' res = [os.path.join(dirname, p) for p in self._listdir(tmp) if p.startswith(rest)] # more than one match, or single match which does not exist (typo) if len(res) > 1 or not os.path.exists(path): return res # resolved to a single directory, so return list of files below it if os.path.isdir(path): return [os.path.join(path, p) for p in self._listdir(path)] # exact file match terminates this completion return [path + ' '] def complete_extra(self, args): "Completions for the 'extra' command." if not args: return self._complete_path('.') # treat the last arg as a path and complete it return self._complete_path(args[-1]) def complete(self, text, state): "Generic readline completion entry point." buffer = readline.get_line_buffer() line = readline.get_line_buffer().split() # show all commands if not line: return [c + ' ' for c in COMMANDS][state] # account for last argument ending in a space if RE_SPACE.match(buffer): line.append('') # resolve command to the implementation function cmd = line[0].strip() if cmd in COMMANDS: impl = getattr(self, 'complete_%s' % cmd) args = line[1:] if args: return (impl(args) + [None])[state] return [cmd + ' '][state] results = [c + ' ' for c in COMMANDS if c.startswith(cmd)] + [None] return results[state] comp = Completer() # we want to treat '/' as part of a word, so override the delimiters readline.set_completer_delims(' \t\n;') readline.parse_and_bind("tab: complete") readline.set_completer(comp.complete) raw_input('Enter section name: ')

Usage:

Update It will complete paths from the root if the user types /:

深海夜未眠 2024-11-07 19:29:09

这足以使用 raw_input() 启用内置目录选项卡补全:

import readline
readline.parse_and_bind("tab: complete")

This is enough to enable built in directory tab completion with raw_input():

import readline
readline.parse_and_bind("tab: complete")
你与昨日 2024-11-07 19:29:09

该版本适用于python3,使用pathlib,并且是tab完成文件/目录的简约版本。它基于上面的一些答案,但仅适用于文件/目录。

#!/usr/bin/python

import pathlib
import readline


def complete_path(text, state):
    incomplete_path = pathlib.Path(text)
    if incomplete_path.is_dir():
        completions = [p.as_posix() for p in incomplete_path.iterdir()]
    elif incomplete_path.exists():
        completions = [incomplete_path]
    else:
        exists_parts = pathlib.Path('.')
        for part in incomplete_path.parts:
            test_next_part = exists_parts / part
            if test_next_part.exists():
                exists_parts = test_next_part

        completions = []
        for p in exists_parts.iterdir():
            p_str = p.as_posix()
            if p_str.startswith(text):
                completions.append(p_str)
    return completions[state]


# we want to treat '/' as part of a word, so override the delimiters
readline.set_completer_delims(' \t\n;')
readline.parse_and_bind("tab: complete")
readline.set_completer(complete_path)
print(input('tab complete a filename: '))

This version is for python3, uses pathlib, and a minimalistic version that tab completes files/dirs. It is based on some of the above answers, but only works for files/dirs.

#!/usr/bin/python

import pathlib
import readline


def complete_path(text, state):
    incomplete_path = pathlib.Path(text)
    if incomplete_path.is_dir():
        completions = [p.as_posix() for p in incomplete_path.iterdir()]
    elif incomplete_path.exists():
        completions = [incomplete_path]
    else:
        exists_parts = pathlib.Path('.')
        for part in incomplete_path.parts:
            test_next_part = exists_parts / part
            if test_next_part.exists():
                exists_parts = test_next_part

        completions = []
        for p in exists_parts.iterdir():
            p_str = p.as_posix()
            if p_str.startswith(text):
                completions.append(p_str)
    return completions[state]


# we want to treat '/' as part of a word, so override the delimiters
readline.set_completer_delims(' \t\n;')
readline.parse_and_bind("tab: complete")
readline.set_completer(complete_path)
print(input('tab complete a filename: '))
魄砕の薆 2024-11-07 19:29:09

对于路径完成

import os
import sys 
import readline
import glob

def path_completer(text, state):
    """ 
    This is the tab completer for systems paths.
    Only tested on *nix systems
    """
    line = readline.get_line_buffer().split()

    if '~' in text:
        text = os.path.expanduser('~')

    return [x for x in glob.glob(text+'*')][state]
    
if __name__=="__main__":

    readline.set_completer_delims('\t')
    readline.parse_and_bind("tab: complete")

    readline.set_completer(path_completer)
    ans = input("What file do you want? ")
    print(ans)

请注意,我已经改进了 https://gist.github.com/iamatypeofwalrus 中找到的代码/5637895

For path completion

import os
import sys 
import readline
import glob

def path_completer(text, state):
    """ 
    This is the tab completer for systems paths.
    Only tested on *nix systems
    """
    line = readline.get_line_buffer().split()

    if '~' in text:
        text = os.path.expanduser('~')

    return [x for x in glob.glob(text+'*')][state]
    
if __name__=="__main__":

    readline.set_completer_delims('\t')
    readline.parse_and_bind("tab: complete")

    readline.set_completer(path_completer)
    ans = input("What file do you want? ")
    print(ans)

Note that I've refined the code found at https://gist.github.com/iamatypeofwalrus/5637895

み零 2024-11-07 19:29:09

在某些系统上,您需要使用不同的绑定。例如,我没有 GNU readline,所以我需要使用不同的 parse_and_bind 文本:

if 'libedit' in readline.__doc__:
    readline.parse_and_bind("bind ^I rl_complete")
else:
    readline.parse_and_bind("tab: complete")

On Some Systems™ you need to use different bindings. For example, I don't have GNU readline, so I need to use a different parse_and_bind text:

if 'libedit' in readline.__doc__:
    readline.parse_and_bind("bind ^I rl_complete")
else:
    readline.parse_and_bind("tab: complete")
神经暖 2024-11-07 19:29:09

在 Python 3.11 中,以下代码适用于目录和文件选择。

import readline

readline.set_completer_delims(" \t\n;")
readline.parse_and_bind("tab: complete")
ip = input("Enter some text or hit tab for directory/filename: ")
print("You entered: ", ip)

In Python 3.11, the below code works for both directory and file selection.

import readline

readline.set_completer_delims(" \t\n;")
readline.parse_and_bind("tab: complete")
ip = input("Enter some text or hit tab for directory/filename: ")
print("You entered: ", ip)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文