这是我对于具备优良命令行用户界面的终端应用程序的两局部系列中的第二局部。在第一篇中,我探讨了使命令行应用程序成为一种纯正的应用乐趣的个性。在第二局部,我将看看如何在一些库的帮忙下在Python中实现这些性能。在本文完结时,读者应该对如何应用 Prompt Toolkit、Click (Command Line Interface Creation Kit)、Pygments 和 Fuzzy Finder 来实现一个易于应用的 REPL有了充沛的理解。
我打算在不到20行的Python代码中实现这一指标。让咱们开始吧。
Python Prompt Toolkit
我喜爱把这个库看作是命令行应用程序的瑞士军刀–它能够代替readline、curses,以及更多的货色。让咱们来装置这个库并开始应用。
<code class="shell">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日在俄勒冈州波特兰市举办。