新聞中心
在這個(gè)分為兩篇的關(guān)于具有絕佳命令行界面的終端程序的系列文章的第二篇教程中,我們將討論 Prompt、Toolkit、Click、Pygments 和 Fuzzy Finder 。
這是我的一個(gè)分為兩篇的關(guān)于具有絕佳命令行界面的終端程序的系列文章的第二篇教程。在第一篇文章中,我們討論了一些能夠使命令行應(yīng)用用起來(lái)令人感到愉悅的特性。在第二篇文章中,我們來(lái)看看如何用 Python 的一些庫(kù)來(lái)實(shí)現(xiàn)這些特性。
我打算用少于 20 行 Python 代碼來(lái)實(shí)現(xiàn)。讓我們開(kāi)始吧。
Python Prompt Toolkit
我習(xí)慣于把這個(gè)庫(kù)稱為命令行應(yīng)用的瑞士軍刀,它可以作為readline、curses等的替代品。讓我們首先安裝這個(gè)庫(kù),然后開(kāi)始該教程:
pip install prompt_toolkit
我們以一個(gè)簡(jiǎn)單的 REPL (LCTT 譯注:REPL —— Read-Eval-Print Loop,交互式開(kāi)發(fā)環(huán)境)開(kāi)始。一個(gè)典型的 REPL 會(huì)接收用戶的輸入,進(jìn)行一個(gè)操作,然后輸出結(jié)果。比如在我們的例子中,我們將要實(shí)現(xiàn)一個(gè)具有 “回顯” 功能的 REPL 。它僅僅是原樣打印出用戶的輸入:
REPL
from prompt_toolkit import prompt
while 1:
user_input = prompt('>')
print(user_input)
這就是實(shí)現(xiàn) REPL 的全部代碼。它可以讀取用戶的輸入,然后打印出用戶的輸入內(nèi)容。在這段代碼中使用的prompt函數(shù)來(lái)自 prompt_toolkit庫(kù),它是readline庫(kù)的一個(gè)替代品。
命令歷史
為了增強(qiáng)我們的 REPL 的功能,我們可以添加命令歷史:
from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
while 1:
user_input = prompt('>',
history=FileHistory('history.txt'),
)
print(user_input)
我們剛剛給 REPL 添加了持久的命令歷史?,F(xiàn)在,我們可以使用上/下箭頭來(lái)瀏覽命令歷史,并使用Ctrl-R來(lái)搜索命令歷史。它滿足了命令行的基本準(zhǔn)則。
自動(dòng)推薦
在第一篇教程中,我講到的一個(gè)可發(fā)現(xiàn)性技巧是自動(dòng)推薦歷史命令。(我是首先在 fish shell 中看到的這一特性)讓我們把這一特性加入到我們的 REPL 中:
from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
while 1:
user_input = prompt('>',
history=FileHistory('history.txt'),
auto_suggest=AutoSuggestFromHistory(),
)
print(user_input)
我們只需要給prompt() API 調(diào)用添加一個(gè)新的參數(shù)?,F(xiàn)在,我們有了一個(gè)具有fish shell風(fēng)格的 REPL,它可以自動(dòng)推薦歷史命令。
自動(dòng)補(bǔ)全
現(xiàn)在,讓我們通過(guò)自動(dòng)補(bǔ)全來(lái)加強(qiáng) Tab 補(bǔ)全。它能夠在用戶開(kāi)始輸入的時(shí)候彈出可能的命令推薦。
REPL 如何來(lái)進(jìn)行推薦呢?我們使用一個(gè)字典來(lái)進(jìn)行可能項(xiàng)的推薦。
比如說(shuō)我們實(shí)現(xiàn)一個(gè)針對(duì) SQL 的 REPL 。我們可以把 SQL 關(guān)鍵字存到自動(dòng)補(bǔ)全字典里面。讓我們看一看這是如何實(shí)現(xiàn)的:
from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.contrib.completers import WordCompleter
SQLCompleter = WordCompleter(['select', 'from', 'insert', 'update', 'delete', 'drop'],
ignore_case=True)
while 1:
user_input = prompt('SQL>',
history=FileHistory('history.txt'),
auto_suggest=AutoSuggestFromHistory(),
completer=SQLCompleter,
)
print(user_input)
再次說(shuō)明,我們只是簡(jiǎn)單的使用了 prompt-toolkit 內(nèi)建的一個(gè)叫做 WordCompleter 的補(bǔ)全特性,它能夠把用戶輸入和可能推薦的字典進(jìn)行匹配,然后提供一個(gè)列表。
現(xiàn)在,我們有了一個(gè)能夠自動(dòng)補(bǔ)全、fish shell 風(fēng)格的歷史命令推薦以及上/下瀏覽歷史的 REPL 。實(shí)現(xiàn)這些特性只用了不到 10 行的實(shí)際代碼。
Click
Click是一個(gè)命令行創(chuàng)建工具包,使用它能夠更容易的為程序解析命令行選項(xiàng)的參數(shù)和常量。在這兒我們不討論如何使用Click來(lái)作為參數(shù)解析器。相反,我們將會(huì)看看Click帶有的一些功能。
安裝Click:
pip install click
分頁(yè)器是 Unix 系統(tǒng)上的實(shí)用工具,它們能夠一次一頁(yè)地顯示很長(zhǎng)的輸出。分頁(yè)器的一些例子包括less、more、most等。通過(guò)分頁(yè)器來(lái)顯示一個(gè)命令的輸出不僅僅是一個(gè)友好的設(shè)計(jì),同時(shí)也是必要的。
讓我們進(jìn)一步改進(jìn)前面的例子。我們不再使用默認(rèn)print()語(yǔ)句,取而代之的是click.echo_via_pager()。它將會(huì)把輸出通過(guò)分頁(yè)器發(fā)送到標(biāo)準(zhǔn)輸出。這是平臺(tái)無(wú)關(guān)的,因此在 Unix 系統(tǒng)或 Windows 系統(tǒng)上均能工作。如果必要的話,click_via_pager 會(huì)嘗試使用一個(gè)合適的默認(rèn)分頁(yè)器來(lái)輸出,從而能夠顯示代碼高亮。
from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.contrib.completers import WordCompleter
import click
SQLCompleter = WordCompleter(['select', 'from', 'insert', 'update', 'delete', 'drop'],
ignore_case=True)
while 1:
user_input = prompt(u'SQL>',
history=FileHistory('history.txt'),
auto_suggest=AutoSuggestFromHistory(),
completer=SQLCompleter,
)
click.echo_via_pager(user_input)
編輯器
在我前面的文章中一個(gè)值得一提的細(xì)節(jié)是,當(dāng)命令過(guò)于復(fù)雜的時(shí)候進(jìn)入編輯器來(lái)編輯。Click 有一個(gè)簡(jiǎn)單的 API 能夠打開(kāi)編輯器,然后把在編輯器中輸入的文本返回給應(yīng)用。
import click
message = click.edit()
Fuzzy Finder
Fuzzy Finder 是一種通過(guò)少量輸入來(lái)為用戶減少推薦的方法。幸運(yùn)的是,有一個(gè)庫(kù)可以實(shí)現(xiàn) Fuzzy Finder 。讓我們首先安裝這個(gè)庫(kù):
pip install fuzzyfinder
Fuzzy Finder的 API 很簡(jiǎn)單。用戶向它傳遞部分字符串和一系列可能的選擇,然后,F(xiàn)uzzy Finder將會(huì)返回一個(gè)與部分字符串匹配的列表,這一列表是通過(guò)模糊算法根據(jù)相關(guān)性排序得出的。比如:
>>> from fuzzyfinder import fuzzyfinder
>>> suggestions = fuzzyfinder('abc', ['abcd', 'defabca', 'aagbec', 'xyz', 'qux'])
>>> list(suggestions)
['abcd', 'defabca', 'aagbec']
現(xiàn)在我們有了fuzzyfinder>,讓我們把它加入到我們的 SQL REPL 中。方法是我們自定義一個(gè)completer而不是使用來(lái)自prompt-toolkit庫(kù)的WordCompleter。比如:
from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.completion import Completer, Completion
import click
from fuzzyfinder import fuzzyfinder
SQLKeywords = ['select', 'from', 'insert', 'update', 'delete', 'drop']
class SQLCompleter(Completer):
def get_completions(self, document, complete_event):
word_before_cursor = document.get_word_before_cursor(WORD=True)
matches = fuzzyfinder(word_before_cursor, SQLKeywords)
for m in matches:
yield Completion(m, start_position=-len(word_before_cursor))
while 1:
user_input = prompt(u'SQL>',
history=FileHistory('history.txt'),
auto_suggest=AutoSuggestFromHistory(),
completer=SQLCompleter(),
)
click.echo_via_pager(user_input)
Pygments
現(xiàn)在,讓我們給用戶輸入添加語(yǔ)法高亮。我們正在搭建一個(gè) SQL REPL,如果具有彩色高亮的 SQL 語(yǔ)句,這會(huì)很棒。
Pygments是一個(gè)提供語(yǔ)法高亮的庫(kù),內(nèi)建支持超過(guò) 300 種語(yǔ)言。添加語(yǔ)法高亮能夠使應(yīng)用變得彩色化,從而能夠幫助用戶在執(zhí)行程序前發(fā)現(xiàn) SQL 中存在的錯(cuò)誤,比如拼寫(xiě)錯(cuò)誤、引號(hào)不匹配或括號(hào)不匹配。
首先,安裝Pygments:
pip install pygments
讓我們使用Pygments來(lái)為 SQL REPL 添加顏色:
from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.completion import Completer, Completion
import click
from fuzzyfinder import fuzzyfinder
from pygments.lexers.sql import SqlLexer
SQLKeywords = ['select', 'from', 'insert', 'update', 'delete', 'drop']
class SQLCompleter(Completer):
def get_completions(self, document, complete_event):
word_before_cursor = document.get_word_before_cursor(WORD=True)
matches = fuzzyfinder(word_before_cursor, SQLKeywords)
for m in matches:
yield Completion(m, start_position=-len(word_before_cursor))
while 1:
user_input = prompt(u'SQL>',
history=FileHistory('history.txt'),
auto_suggest=AutoSuggestFromHistory(),
completer=SQLCompleter(),
lexer=SqlLexer,
)
click.echo_via_pager(user_input)
Prompt Toolkit能夠和Pygments一同很好的工作。我們把Pygments提供的SqlLexer加入到來(lái)自prompt-toolkit的prompt中。現(xiàn)在,所有的用戶輸入都會(huì)被當(dāng)作 SQL 語(yǔ)句,并進(jìn)行適當(dāng)著色。
網(wǎng)站名稱:快速構(gòu)建命令行用戶界面的 Python 庫(kù)
文章轉(zhuǎn)載:http://www.dlmjj.cn/article/dhcjgce.html


咨詢
建站咨詢

