Jak sprawić, by program wiersza poleceń w języku Python automatycznie uzupełniał dowolne rzeczy, NIE interpretując

98

Wiem, jak skonfigurować autouzupełnianie obiektów Pythona w interpreterach Pythona (na unixie).

  • Google pokazuje wiele trafień, aby wyjaśnić, jak to zrobić.
  • Niestety, jest tak wiele odniesień do tego, że trudno jest znaleźć to, co muszę zrobić, co jest nieco inne.

Muszę wiedzieć, jak włączyć tabulator / automatyczne uzupełnianie dowolnych elementów w programie wiersza poleceń napisanym w języku Python.

Moim konkretnym przypadkiem użycia jest program w języku Python z wiersza poleceń, który musi wysyłać e-maile. Chcę mieć możliwość autouzupełniania adresów e-mail (mam adresy na dysku), gdy użytkownik wpisze ich część (i opcjonalnie naciśnie klawisz TAB).

Nie potrzebuję go do pracy na Windowsie lub Macu, tylko na Linuksie.

Paul D. Eden
źródło
Ten blog powinien zrobić sztuczki z konfiguracją pliku .pythonrc.
Kris Roofe

Odpowiedzi:

65

Użyj readlinepowiązań Pythona . Na przykład,

import readline

def completer(text, state):
    options = [i for i in commands if i.startswith(text)]
    if state < len(options):
        return options[state]
    else:
        return None

readline.parse_and_bind("tab: complete")
readline.set_completer(completer)

Oficjalne dokumenty modułów nie są dużo bardziej szczegółowe, zobacz dokumentację readline, aby uzyskać więcej informacji.

ephemient
źródło
1
Zwróć uwagę, że jeśli napiszesz wiersz poleceń z modułem cmd, istnieją lepsze sposoby na zrobienie tego.
Florian Bösch
60

Postępuj zgodnie z dokumentacją cmd, a wszystko będzie dobrze

import cmd

addresses = [
    '[email protected]',
    '[email protected]',
    '[email protected]',
]

class MyCmd(cmd.Cmd):
    def do_send(self, line):
        pass

    def complete_send(self, text, line, start_index, end_index):
        if text:
            return [
                address for address in addresses
                if address.startswith(text)
            ]
        else:
            return addresses


if __name__ == '__main__':
    my_cmd = MyCmd()
    my_cmd.cmdloop()

Dane wyjściowe dla tab -> tab -> send -> tab -> tab -> f -> tab

(Cmd)
help  send
(Cmd) send
[email protected]            [email protected]         [email protected]
(Cmd) send [email protected]
(Cmd)
Florian Bösch
źródło
Czy istnieje sposób kontrolowania sposobu, w jaki readline kolumizuje swoje dane wyjściowe? Powiedzmy więc, że chciałbym, aby był on zbiorczy z dwiema spacjami między każdym elementem.
Fnord
Kiedy uruchamiam ten kod, zakładki są po prostu drukowane w wierszu poleceń. W rzeczywistości jest to prawdą niezależnie od tego, czy używam cmd, czy straight readline.
Hack Saw
38

Ponieważ w swoim pytaniu mówisz „NIE interpreter”, myślę, że nie chcesz odpowiedzi obejmujących python readline i tym podobne. ( edytuj : z perspektywy czasu, oczywiście tak nie jest. Hej. Myślę, że ta informacja i tak jest interesująca, więc zostawię ją tutaj ).

Myślę, że możesz być po tym .

Chodzi o dodanie uzupełniania na poziomie powłoki do dowolnych poleceń, rozszerzając własne uzupełnianie tabulatorami basha.

W skrócie, utworzysz plik zawierający funkcję powłoki, która wygeneruje możliwe uzupełnienia, zapiszesz ją /etc/bash_completion.d/i zarejestrujesz za pomocą polecenia complete. Oto fragment z połączonej strony:

_foo() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="--help --verbose --version"

    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
}
complete -F _foo foo

W tym przypadku, wpisując foo --[TAB]daje wartości w zmiennej opts, to znaczy --help, --verbosei --version. Do swoich celów zasadniczo będziesz chciał dostosować wartości, które są wstawiane opts.

Spójrz na przykład na połączonej stronie, wszystko jest dość proste.

piekarnik
źródło
11
Właściwie to przyszedłem tutaj z tego powodu
user1767754
Dzięki, właśnie tego szukałem!
Teekeks
30

Dziwię się, że nikt nie wspomniał o argcomplete, oto przykład z dokumentacji:

from argcomplete.completers import ChoicesCompleter

parser.add_argument("--protocol", choices=('http', 'https', 'ssh', 'rsync', 'wss'))
parser.add_argument("--proto").completer=ChoicesCompleter(('http', 'https', 'ssh', 'rsync', 'wss'))
co było do okazania
źródło
To stary post, może argcomplete wtedy nie istniał? Dziękuję za wspomnienie, myślę, że to jest dokładnie to, czego potrzebuje mój projekt!
FrustratedWithFormsDesigner
Bardzo ładne w połączeniu z argparse !
AstroFloyd
14

Oto w pełni działająca wersja kodu, który został bardzo dostarczony przez ephemient tutaj (dziękuję).

import readline

addrs = ['[email protected]', '[email protected]', '[email protected]']

def completer(text, state):
    options = [x for x in addrs if x.startswith(text)]
    try:
        return options[state]
    except IndexError:
        return None

readline.set_completer(completer)
readline.parse_and_bind("tab: complete")

while 1:
    a = raw_input("> ")
    print "You entered", a
Paul D. Eden
źródło
10
# ~/.pythonrc
import rlcompleter, readline
readline.parse_and_bind('tab:complete')

# ~/.bashrc
export PYTHONSTARTUP=~/.pythonrc
user178047
źródło
1
W systemie Mac OS, należy wymienić readline.parse_and_bind('tab:complete') zreadline.parse_and_bind ("bind ^I rl_complete")
Mani
To jest niesamowite. Pracował dla mnie. Dzięki za udostępnienie.
Ajay Ahuja
@Mani Utknąłem w tym przez długi czas. Dziękuję bardzo
AnaS Kayed
5

Możesz spróbować użyć Python Prompt Toolkit , biblioteki do tworzenia interaktywnych aplikacji wiersza poleceń w Pythonie.

Biblioteka ułatwia dodawanie interaktywnej funkcji autouzupełniania, umożliwiając użytkownikowi użycie Tabklawisza do wizualnego przechodzenia między dostępnymi opcjami. Biblioteka jest wieloplatformowa (Linux, OS X, FreeBSD, OpenBSD, Windows). Przykład:

pgcli - Python Prompt Toolkit

(Źródło obrazu: pcgli )

Strumień
źródło
1

Opublikowane odpowiedzi działają poprawnie, ale mam otwartą bibliotekę autouzupełniania, którą napisałem w pracy. Używamy go od jakiegoś czasu w produkcji, jest szybki, stabilny i łatwy w użyciu. Ma nawet tryb demonstracyjny, dzięki czemu możesz szybko przetestować, co otrzymasz podczas wpisywania słów.

Aby go zainstalować, po prostu uruchom: pip install fast-autocomplete

Oto przykład:

>>> from fast_autocomplete import AutoComplete
>>> words = {'book': {}, 'burrito': {}, 'pizza': {}, 'pasta':{}}
>>> autocomplete = AutoComplete(words=words)
>>> autocomplete.search(word='b', max_cost=3, size=3)
[['book'], ['burrito']]
>>> autocomplete.search(word='bu', max_cost=3, size=3)
[['burrito']]
>>> autocomplete.search(word='barrito', max_cost=3, size=3)  # mis-spelling
[['burrito']]

Do kasy: https://github.com/wearefair/fast-autocomplete dla kodu źródłowego.

A oto wyjaśnienie, jak to działa: http://zepworks.com/posts/you-autocomplete-me/

Zajmuje się błędami w pisowni i opcjonalnie sortowaniem według wagi słowa. (powiedzmy, że burritojest ważniejsze niż book, wtedy podajesz burritowyższą „liczbę” i pojawi się ona jako pierwsza bookw wynikach.

Słowa to słownik i każde słowo może mieć kontekst. Na przykład „licznik”, jak wyświetlić słowo, inny kontekst wokół słowa itp. W tym przykładzie słowa nie miały żadnego kontekstu.

Seperman
źródło