我在插件的 Default (Windows).sublime-keymap
中有以下几行文件:
...
{ "keys": ["ctrl+shift+a"], "command": "table_editor_align", "context":
[
{ "key": "setting.enable_table_editor", "operator": "equal", "operand": true, "match_all": true },
{ "key": "preceding_text", "operator": "regex_contains", "operand": "^\\s*\\|", "match_all": true },
{ "key": "following_text", "operator": "regex_contains", "operand": "$", "match_all": true }
]
},
...
与其仅在 ctrl+shift+a 时触发此命令,我想触发此命令 在每个字母数字按键之后 (A-Z、a-z、0-9,为什么不也重音 é、à、ç 等,即我们在写作时使用的所有字符)?
"keys": ["[a-zA-Z0-9_]"]
似乎不起作用。
注意:该插件目前是 sublime_plugin.TextCommand 的子类,我认为保留它是它工作的必要条件。我要修改的插件是 https://github.com/vkocubinsky/SublimeTableEditor ,我希望在每次按键后自动重新对齐,而不是像这样在每次 CTRL+SHIFT+A 之后自动重新对齐:
最佳答案
据我所知,无法一次将一个键绑定(bind)到一大类键,因此为了执行您想要的操作,您必须一次为每个键创建一个单独的映射,即相当笨重,很可能不是一个好主意。
[编辑]
实际上有一种方法可以做到这一点;我在答案的末尾添加了更多信息
[/编辑]
从一些简单的测试来看,您感兴趣的键(输入文本)似乎是由 Sublime 核心直接处理的,除非您为它们提供映射。也就是说,它们颠覆了正常的命令机制,这意味着您不能在插入文本并重新格式化时就捕获它。
解决此问题的一种方法是,正如 MattDMO 所建议的,使用 on_modified
处理程序来跟踪缓冲区何时被修改,然后以这种方式触发重新对齐。
可以执行类似操作的示例插件如下:
import sublime
import sublime_plugin
import re
class TableFormatEventListener(sublime_plugin.EventListener):
def __init__(self):
self._views = dict()
self.regex = re.compile(r"\s*\|")
def on_modified(self, view):
# Only for views with table editing enabled that are not already being
# modified
if (view.settings().get("enable_table_editor", False) and
self._views.get(view.id(), False) is False):
for s in view.sel():
line = view.substr(view.line(s.begin()))
prior = view.substr(s.begin() - 1) if s.begin() > 0 else ""
# Only if all cursors are inside of a table row and the
# character prior to the cursor is not a space
if self.regex.match(line) is None or prior == " ":
return
# Perform the realignment
self._views[view.id()] = True
view.run_command("table_editor_align")
self._views[view.id()] = False
def on_text_command(self, view, cmd, args):
# Don't trigger reformatting while an undo is happening
if cmd == "undo":
self._views[view.id()] = True
def on_post_text_command(self, view, cmd, args):
# Undo is complete; resume reformat handling
if cmd == "undo":
self._views[view.id()] = False
这实现了每次修改 View 时触发的事件监听器。这意味着添加了文本 或 删除,还涵盖了诸如粘贴之类的内容(实际上是任何修改缓冲区的内容;稍后会详细介绍)。
该插件执行与键绑定(bind)相同的上下文检查,以确保所有可用的插入符当前都在表行内,就像调用命令来重新对齐表一样,否则会引发错误。
此外,还会进行检查以查看添加的最后一个字符是否为空格。这是因为重新格式化似乎删除了尾随空格,这有效地阻止了您能够在表中的任何位置输入空格。
假设所有光标都在表格行中并且不只是插入一个空格,则在当前 View 上执行重新对齐表格的命令。
这里要注意的是,重新对齐表会导致缓冲区的内容被修改,然后再次触发插件监听器,再次重新对齐表,一遍又一遍地循环,直到插件主机崩溃。
为了阻止这种情况的发生,我们会跟踪应该具有
on_modified
的 View 。事件被忽略,在修改表之前将当前 View 添加到列表中,然后在我们完成后将其删除。该插件所做的一个副作用是,您在表中所做的任何更改都会导致两次修改;您所做的更改,以及重新对齐表格的更改(即使它没有更改)。这意味着为了撤消表中的更改,有时您必须按比您想象的更多次撤消。
这会导致潜在的问题。例如,如果您要在表格行的开头退格,则该行和前一行将在同一行上。修改调用重新对齐函数,正式将两行合二为一。
现在你有点不高兴了,因为你无法撤消更改;当您按一次撤消键时,它会撤消重新对齐,但这样做会修改缓冲区,从而触发重新对齐立即再次发生。
为了解决这个问题,事件监听器还会监听
undo
命令即将发生,并确保在撤消发生时,修改处理程序不会重新对齐表。由于我不使用此特定插件,因此其他需要以这种方式处理的场景可能存在类似的边缘情况。
性能可能会或可能不会受到影响,这取决于您碰巧正在编辑的表格有多大。在我的(极其简单的)测试中,对小表的性能影响在我的机器上可以忽略不计。您的里程可能会有所不同,因此如果当前文件超过某个行阈值或沿着这些行的某些内容,则在代码中进行额外检查可能是一个好主意,以阻止它触发。
[编辑]
碰巧的是,实际上有一种方法可以执行类似于您最初要求的操作。可以分配一个键绑定(bind)来触发任何插入的字符,尽管您仍然需要一些胶水插件代码来将所有内容绑定(bind)在一起(并且一些可用性问题仍然与表格插件如何进行重新格式化有关)。
所需的插件代码是一个命令,它将接受一个字符并像往常一样插入文本,但同时也会触发表格对齐命令。
import sublime
import sublime_plugin
class TextAndAlignTableCommand(sublime_plugin.TextCommand):
def run(self, edit, character):
self.view.run_command("insert", {"characters": character})
if character != " ":
self.view.run_command("table_editor_align")
这定义了一个命令,它接受一个参数
character
,它将以通常输入字符的方式插入缓冲区。然后,如果字符不是空格,它还会调用命令来重新对齐表格。有了这个,要创建的键绑定(bind)是:
{ "keys": ["<character>"], "command": "text_and_align_table", "context":
[
{ "key": "setting.enable_table_editor", "operator": "equal", "operand": true, "match_all": true },
{ "key": "preceding_text", "operator": "regex_contains", "operand": "^\\s*\\|", "match_all": true },
{ "key": "following_text", "operator": "regex_match", "operand": "\\s*\\|.*$", "match_all": true }
]
},
这基本上是您上面提到的键绑定(bind)(这是底层表插件触发重新格式化的默认值),并稍作修改。
首先, key 绑定(bind)到 key
<character>
,这使得它可能会触发任何本来会插入缓冲区的字符。其次,它使用我们上面的自定义命令,首先插入文本,然后重新格式化表格。
三、
following_text
修改context,使其仅在表中列的末尾时才触发,这样就可以将文本插入到列的中间,而不会使光标位置跳到该列的末尾。当以这种方式绑定(bind)时,绑定(bind)将针对任何单个字符触发,并将调用提供的命令,该命令提供一个参数,告诉您该字符是什么。绑定(bind)本身不能有修饰符(例如
ctrl
、 shift
等),但您获得的字符是本来可以输入的字符。这更清晰,并且没有与上面关于撤消的代码相同的问题,因为所采取的所有操作都是同一编辑操作的一部分。
此外,在列主体内部时不触发绑定(bind)消除了能够在列中间插入文本的问题,因为表重新对齐会移动光标位置。这确实会使表格未对齐,但在这种情况下可以使用现有的键绑定(bind)来纠正问题。
另一方面,在列值的末尾(重新格式化后)仍然不可能有空格,因为表重新格式化要删除它们。为了阻止这种情况发生,必须修改底层插件才能不这样做,但这似乎会在某种程度上损害表格格式。
关于sublimetext2 - 为每个字母数字按键触发一个 Action ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41662429/