sublimetext2 - 为每个字母数字按键触发一个 Action

标签 sublimetext2 sublimetext sublime-text-plugin

我在插件的 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 之后自动重新对齐:

enter image description here

最佳答案

据我所知,无法一次将一个键绑定(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)本身不能有修饰符(例如 ctrlshift 等),但您获得的字符是本来可以输入的字符。

这更清晰,并且没有与上面关于撤消的代码相同的问题,因为所采取的所有操作都是同一编辑操作的一部分。

此外,在列主体内部时不触发绑定(bind)消除了能够在列中间插入文本的问题,因为表重新对齐会移动光标位置。这确实会使表格未对齐,但在这种情况下可以使用现有的键绑定(bind)来纠正问题。

另一方面,在列值的末尾(重新格式化后)仍然不可能有空格,因为表重新格式化要删除它们。为了阻止这种情况发生,必须修改底层插件才能不这样做,但这似乎会在某种程度上损害表格格式。

关于sublimetext2 - 为每个字母数字按键触发一个 Action ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41662429/

相关文章:

sublimetext - 使用 CTRL+P ("goto anything"打开时,Sublime Text 导航到边栏中的文件)

python - 进行文本替换后如何准确设置新的光标位置

linux - 如何从 linux 中的命令行将 Sublime Text 2 文件打开到选项卡,而不是新窗口

git - Sublime Text -根据文件的修订状态为文件着色

console - 包控制 : Install Package File "<string>", 第 1 行 包控制:安装包 ^ SyntaxError:语法无效

ide - Sublime Text 缩进设置被文件覆盖

html - 在 HTML sublime text 2 中自动完成 css 类或 id

plugins - sublime text 3 是否支持 "find usages"("go to references"或 "list references")或任何插件支持?

linux - 将 Sublime Text 2 添加到 Ubuntu 12.04 中的右键单击上下文菜单

regex - HTML 标记中语法高亮属性的正则表达式