这是我对于具备优良命令行用户界面的终端应用程序的两局部系列中的第二局部。在第一篇中,我探讨了使命令行应用程序成为一种纯正的应用乐趣的个性。在第二局部,我将看看如何在一些库的帮忙下在 Python 中实现这些性能。在本文完结时,读者应该对如何应用 Prompt Toolkit、Click (Command Line Interface Creation Kit)、Pygments 和 Fuzzy Finder 来实现一个易于应用的 REPL 有了充沛的理解。
我打算在不到 20 行的 Python 代码中实现这一指标。让咱们开始吧。
Python Prompt Toolkit
我喜爱把这个库看作是命令行应用程序的瑞士军刀 – 它能够代替readline、curses,以及更多的货色。让咱们来装置这个库并开始应用。
pip install prompt_toolkit
咱们将从一个简略的 REPL 开始。一般来说,REPL 会承受用户输出,进行操作,并打印后果。在咱们的例子中,咱们将建设一个 “echo “ 的 REPL。它只是打印回用户输出的内容。
REPL
from prompt_toolkit import prompt
while 1:
user_input = prompt('>')
print(user_input)
这就是实现一个 REPL 的全部内容。它能够读取用户的输出并打印出他们所输出的内容。这个代码片段中应用的 prompt 函数来自 prompt_toolkit 库;它是 readline 库的替代品。
历史
为了增强咱们的 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 中增加了长久化历史。当初咱们能够应用上 / 下箭头来浏览历史,并应用 Ctrl+R 来搜寻历史。这满足了命令行的根本礼节。
主动倡议
我在第一局部中谈到的可发现性技巧之一是主动倡议历史上的命令。(咱们在 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 调用中增加一个新参数。当初咱们有了一个 REPL,它具备 鱼式的从历史中主动倡议的性能。
主动实现
当初让咱们通过主动实现来实现对 Tab 键的加强,当用户开始输出时,它将弹出可能的倡议。
咱们的 REPL 如何晓得该倡议什么?咱们提供一个可能倡议的我的项目的字典。
比方说,咱们正在实现一个 SQL 的 REPL。咱们能够在咱们的主动实现字典中贮存 SQL 关键字。让咱们看看如何做到这一点。
from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.completion 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)
再一次,咱们能够简略地应用 prompt-toolkit 的内置实现程序,称为WordCompleter,它将用户输出与可能的倡议字典相匹配,并提供一个列表。
咱们当初有了一个 REPL,它能够进行主动补全,从历史中获取鱼式倡议,并对历史进行上 / 下遍历。所有这些都在不到 10 行的理论代码中实现。
Click
Click 是一个命令行创立工具包,它能够很容易地解析命令行选项参数和程序参数。本节不谈如何将 Click 作为参数解析器应用;相同,我将看一下 Click 附带的一些实用程序。
装置 Click 很简略。
pip install click
寻呼机
寻呼机是 Unix 的实用工具,每次显示一页长的输入。呼叫器的例子有:less, more, most, 等等。通过寻呼机显示命令的输入,不仅是敌对的设计,而且也是体面的做法。
让咱们进一步看看后面的例子。咱们能够应用 click.echo_via_pager(),而不是应用默认的print() 语句。这将负责通过一个分页器将输入发送到 stdout。它是与平台无关的,所以它能够在 Unix 或 Windows 中工作。click.echo_via_pager()将尝试应用适合的默认值,以便在必要时可能显示颜色代码。
from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.completion import WordCompleter
import click
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,
)
click.echo_via_pager(user_input)
编辑
我在上一篇文章中提到的一个益处是,当命令变得太简单时,能够返回到编辑器。click再次提供了一个简略的 API 来启动一个编辑器,并将在编辑器中输出的文本返回给应用程序。
输出 click
message = click.edit()
Fuzzy Finder
Fuzzy Finder 是一种让用户用起码的输出来放大倡议范畴的办法。再一次,有一个库实现了 Fuzzy Finder。让咱们来装置这个库。
pip install fuzzyfinder
Fuzzy Finder 的 API 很简略。你传入局部字符串和一个可能的抉择列表,Fuzzy Finder 将返回一个新的列表,该列表应用含糊算法按相关性排序与局部字符串相匹配。比如说
>>> from fuzzyfinder.main import fuzzyfinder
>> suggestions = fuzzyfinder('abc', ['abcd', 'defabca', 'aagbec', 'xyz', 'qux'] )
>> list(sustips)
['abcd', 'defabca', 'aagbec']
当初咱们有了咱们的 fuzzyfinder,让咱们把它增加到咱们的 SQL REPL 中。咱们这样做的办法是定义一个自定义的实现器,而不是prompt-toolkit 附带的 **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.main 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
当初让咱们为用户的输出增加语法高亮。咱们正在建设一个 SQL REPL,有黑白的 SQL 语句会很好。
Pygments 是一个语法高亮库,内置反对超过 300 种语言。增加语法高亮使应用程序变得丰富多彩,这有助于用户在执行 SQL 之前发现错误 – 如错别字、不匹配的引号或括号。
首先装置 Pygments。
pip install pygments
让咱们应用 Pygments 为咱们的 SQL REPL 增加色彩。
from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
从 prompt_toolkit.auto_suggest 导入 AutoSuggestFromHistory
从 prompt_toolkit.completion 导入 Completer, Completion
导入点击
从 fuzzyfinder 导入 fuzzyfinder
from pygments.lexers.sql import SqlLexer
SQLKeywords = ['抉择', '来自', '插入', '更新', '删除', '放弃']
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:
产量实现(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,并将其传入prompt-toolkit 的prompt** API。当初,所有的用户输出都被视为 SQL 语句,并被适当地着色。
结语
这就完结了咱们创立一个弱小的 REPL 的旅程,它具备一般 shell 的所有性能,如历史、键绑定,以及用户敌对的性能,如主动补全、含糊查找、呼叫器反对、编辑器反对和语法突出显示。咱们在不到 20 条 Python 语句中实现了所有这些。
这不是很容易吗?当初你没有借口不写一个杰出的命令行应用程序了。这些资源可能会有所帮忙。
- Click (命令行界面创立工具包)
- Fuzzy Finder
- Prompt Toolkit
- 参见 prompt-toolkit 资源库中的 Prompt Toolkit tutorial 教程和实例。
- Pygments
* 在 Amjith Ramanujam 的 PyCon US 2017 讲座中理解更多信息,Awesome Commandline Tools,5 月 20 日在俄勒冈州波特兰市举办。