输入处理程序
输入处理程序是一种通过命令面板查询用户一个或多个输入参数的机制。它们取代了旧的输入和快速面板方法(Window.show_input_panel
和 Window.show_quick_panel
),在单个组件中提供统一的用户体验。
输入处理程序已在构建 3154 中添加,并在 3.1 版本的稳定通道中首次提供。
示例
Sublime Text 的 Default
包提供的以下命令使用输入处理程序(命令名称用于命令面板)
命令名称 | 文件 | 描述 |
---|---|---|
算术 | Default/arithmetic.py | 计算给定的 Python 表达式(通常是数字)。 |
查看包文件 | Default/ui.py | 提供 Packages 文件夹中所有资源文件的列表以供打开。 |
重命名文件 | Default/rename.py | 查询用户以获取活动视图的新文件名。 |
您可以使用上面的查看包文件命令查看这些文件的源代码。
输入处理程序种类
目前有两种类型的输入处理程序
- 文本输入处理程序接受任意文本输入,
- 列表输入处理程序为用户提供一个选项列表供选择。
文本输入处理程序始终将输入的文本转发到命令,而列表输入处理程序可以处理任何可 JSON 序列化的值,并附带其各自列表项的标题。
实现输入处理程序
由于输入处理程序使用的是相当通用的接口,因此向您的命令添加一个可能需要仔细考虑,并且可能不是最直观的流程。
我们将实现一个示例输入处理程序,并解释您可以调整更多齿轮以进行高级配置。
重要
要将输入处理程序用于命令,该命令必须在 命令面板 中有条目。这很容易忘记,所以一定要记住!
让我们从一个非常简单的命令开始,该命令将给定的文本插入视图中。以下两个文件可以放置在任何包文件夹中,包括“用户”。
simple_command.py
:
import sublime_plugin
class SimpleCommand(sublime_plugin.TextCommand):
def run(self, edit, text):
for region in self.view.sel():
self.view.replace(edit, region, text)
Simple.sublime-commands
:
[
{ "caption": "Simple Command", "command": "simple" },
]
*Command.input
方法
在执行命令时,命令会接收传递给其 `run` 方法的键值参数。当签名中的参数没有默认值时,只有在为所有此类参数提供参数的情况下才能调用该命令。使用过少的参数调用命令将失败,并导致异常打印到控制台。
>>> window.run_command("simple")
Traceback (most recent call last):
File "/opt/sublime_text/Lib/python38/sublime_plugin.py", line 1270, in run_
return self.run()
TypeError: run() missing 1 required positional argument: 'text'
在这种情况下,命令可以实现 `input` 方法 并返回一个输入处理程序实例,该实例为 Sublime Text 提供显示输入处理程序所需的信息。
import sublime_plugin
class SimpleCommand(sublime_plugin.TextCommand):
def run(self, edit, text):
for region in self.view.sel():
self.view.replace(edit, region, text)
def input(self, args):
return MyTextInputHandler()
`input` 函数接受一个 `args` 参数,该参数是命令所有当前已知参数的字典。由于我们知道我们唯一的必需参数(`text`)此时缺失,因此我们不会使用该参数。
我们还没有定义 `MyTextInputHandler`,所以让我们来做一下。
子类化 `TextInputHandler`
要为文本创建一个简单的输入处理程序,我们创建 `sublime_plugin.TextInputHandler` 的子类。在我们的子类中,我们可以覆盖特定方法。对于最基本的功能,我们需要 `name`。此外,为了方便起见,我们定义了 `placeholder`。
class MyTextInputHandler(sublime_plugin.TextInputHandler):
def name(self):
return "text"
def placeholder(self):
return "Text to insert"
就是这样。以下是它的样子
提示
当然,您仍然可以像以前一样从键绑定或通过控制台调用命令。当提供所有必需参数时,将跳过输入处理程序,并立即运行命令。
渲染预览
`preview` 方法在每次修改输入文本时都会被调用,并允许在命令面板下方显示一个小预览。预览可以是纯文本,也可以使用 minihtml 来实现支持标记的格式。
以下代码片段扩展了我们之前的输入处理程序,以显示将要插入的字符数量
class MyTextInputHandler(sublime_plugin.TextInputHandler):
def name(self):
return "text"
def placeholder(self):
return "Text to insert"
def preview(self, text):
return "Characters: {}".format(len(text))
还有其他可以覆盖的方法。这些方法在 文档中 有描述。
使用动态数据
您可能已经注意到,我们的 `MyTextInputHandler` 类与我们的 `SampleCommand` 完全分离。如果我们希望输入处理程序依赖于一些动态数据,例如当前视图的选择,则必须将这些值提供给输入处理程序的构造函数。
以下代码片段将文本命令的 `View` 实例传递给输入处理程序的构造函数。构造函数本身将实例存储在一个实例属性中,并在以后从 `preview` 中访问它。
import sublime_plugin
class SimpleCommand(sublime_plugin.TextCommand):
def run(self, edit, text):
for region in self.view.sel():
self.view.replace(edit, region, text)
def input(self, args):
return MyTextInputHandler(self.view)
class MyTextInputHandler(sublime_plugin.TextInputHandler):
def __init__(self, view):
self.view = view
def name(self):
return "text"
def placeholder(self):
return "Text to insert"
def preview(self, text):
return ("Selections: {}, Characters: {}"
.format(len(self.view.sel()), len(text)))
使用 `ListInputHandler` 提供选项列表
您可以为用户提供一个选项列表供他们选择,而不是自由形式的输入。这可以通过子类化 `sublime_plugin.ListInputHandler` 并提供一个 `list_items` 方法来实现,该方法返回一个要从中选择的列表。该列表可以是字符串列表,也可以是元组列表,其中第一个元素表示要显示的文本,第二个元素表示要插入为命令参数的值。
以下是一个小型示例命令,它使用内置的 `html.entities` 模块提供 命名 HTML 实体 列表
from html.entities import html5
import sublime_plugin
class InsertHtmlEntityCommand(sublime_plugin.TextCommand):
def run(self, edit, entity):
for region in self.view.sel():
self.view.replace(edit, region, "&" + entity)
def input(self, args):
return EntityInputHandler()
class EntityInputHandler(sublime_plugin.ListInputHandler):
def list_items(self):
return sorted(html5.keys())
def preview(self, value):
return "Character: {}".format(html5.get(value))
提示
请注意,我们在这里没有实现 `name`,因为 Sublime Text 可以从类名自动推断出输入处理程序的目标参数名称,使用与命令名称相同的逻辑,但删除 "InputHandler" 而不是。
提醒
请记住,您需要通过在 `。sublime-commands` 文件中指定它来使上述命令可用于命令面板。
[
{ "caption": "Insert Html Entity", "command": "insert_html_entity" },
]
以下是它的实际运行情况
实现多个输入处理程序
当命令需要用户提供多个参数时,情况会略有不同。值得注意的是,您必须在input
中添加逻辑,根据哪些参数仍然缺失返回相应的输入处理程序。这些处理程序返回的顺序很重要,因为接收了输入的输入处理程序将保留在命令面板中,以面包屑样式可视化当前的输入步骤。最后,输入处理程序的description
方法将用于渲染这些面包屑的文本。(由于默认行为是显示插入的值,因此这很少使用。)
让我们编写一个将两个操作数相乘的命令。
import sublime_plugin
class SimpleMultiplyCommand(sublime_plugin.TextCommand):
def run(self, edit, operand1, operand2):
result = float(operand1) * float(operand2)
for region in self.view.sel():
self.view.replace(edit, region, str(result))
def input(self, args):
for name in ['operand1', 'operand2']:
if name not in args:
return NumberInputHandler(name)
class NumberInputHandler(sublime_plugin.TextInputHandler):
def __init__(self, name):
self._name = name
def name(self):
return self._name
def placeholder(self):
return "Number"
def validate(self, text):
try:
float(text)
except ValueError:
return False
else:
return True
提示
在这个命令中,我们只使用了一个输入处理程序类来处理两个参数,方法是在name
函数中返回一个实例变量。
该命令按预期工作。它在从命令面板连续调用时会要求输入两个数字。但是,在确认第一个操作数后,它不会显示第一个操作数的面包屑。这是因为在第一个参数之后,input
命令会重新运行,因为我们需要两个参数,并且关于先前输入处理程序的信息会丢失。
提示
运行此命令时遇到问题?您是否为它添加了.sublime-commands
条目?
next_input
方法
为了显示前面提到的面包屑,第一个输入处理程序需要知道下一个输入处理程序是什么,并在next_input
方法中返回它。
您可以以静态方式执行此操作,但让我们尝试一种动态方法。请记住,如果第二个参数已经提供,则无需询问它。
import sublime_plugin
class MultiplyCommand(sublime_plugin.TextCommand):
def run(self, edit, operand1, operand2):
result = float(operand1) * float(operand2)
for region in self.view.sel():
self.view.replace(edit, region, str(result))
def input(self, args):
names = [name for name in ['operand1', 'operand2']
if name not in args]
if names:
return MultiNumberInputHandler(names)
class MultiNumberInputHandler(sublime_plugin.TextInputHandler):
def __init__(self, names):
self._name, *self.next_names = names
def name(self):
return self._name
def placeholder(self):
return "Number"
def next_input(self, args):
if self.next_names:
return MultiNumberInputHandler(self.next_names)
def validate(self, text):
try:
float(text)
except ValueError:
return False
else:
return True
在这个命令中,我们从第一次调用中收集所有需要的参数,并将NumberInputHandler
更改为MultiNumberInputHandler
,它接受一个要查询的参数名称列表。第 19 行的解构赋值将列表拆分为“first”和“rest”,以便可以在next_input
方法中返回其余需要的参数。
让我们看看它在调用时的样子
提示
NumberInputHandler
和MultiNumberInputHandler
都实现了一个validate
方法,如果传递的文本可以解析为浮点数,则返回一个布尔值。效果是,对于非数字文本,输入将被拒绝,并且在按下⏎时不会发生任何事情。自己试试吧!
代码存档
本页上展示的最终代码示例 包含在源代码 Git 存储库中。您可以下载它的 [zip][](通过 DownGit)并将其解压缩到您的 Packages 文件夹中以进行实验。
使用输入处理程序调用命令
当从插件或键绑定调用带有输入处理程序且没有所有必需参数的命令时,建议使用show_overlay
命令。以这种方式调用的命令将在 ST 尝试调用run
之前调用其input
方法,从而产生更可预测的行为。否则,Sublime Text 将尝试像往常一样运行命令(运行其run
方法),并且只有在由于参数不足导致调用失败时才会检查命令的input
方法。
示例:
view.run_command(
'show_overlay',
{'overlay': 'command_palette', 'command': 'multiply', 'args': {'operand1': 12}},
)
{
"command": "show_overlay",
"args": {
"overlay": "command_palette",
"command": "multiply",
"args": {"operand1": 12}
},
}
注意事项
如前所述,命令面板必须有一个条目才能使用输入处理程序。
命令的
input
方法可能会被多次调用,直到用户可以访问它为止。is_visible
和is_enabled
无法根据给定的参数确定其返回值,因为涉及输入处理程序。(#3249)