【问题标题】:sublime capture event before closing window关闭窗口之前的崇高捕获事件
【发布时间】:2017-11-02 12:46:04
【问题描述】:

我试图在关闭 sublime 窗口时捕获事件。我一直在尝试使用plugin_unloaded,但是关闭窗口时似乎没有调用此方法

def plugin_unloaded():
    with open('/home/user/aaaaaa.txt', 'w') as fp:
        fp.write("test\n")

我希望在关闭窗口时创建文件,但事实并非如此,那么是否有一种方法被触发并且我可以在窗口关闭时执行一些操作?

【问题讨论】:

    标签: python plugins sublimetext


    【解决方案1】:

    Sublime 中的插件本质上是全局的,因为它们只加载一次(通常,见下文)。因此,不会为每个创建的窗口加载新副本。

    尤其是 Sublime 加载插件:

    • 最初启动时
    • 当它们首次出现在包中时(对于新添加的插件)
    • 当他们所在的源文件在磁盘上发生更改时
    • 当存储它们的包从ignored_packages 设置中删除时,会再次激活包。

    同样,插件只会被卸载:

    • 当 Sublime 即将重新加载它时,因为它在磁盘上发生了变化
    • 当存储它们的包被添加到ignored_packages 设置时,使包不再活动

    也就是说,没有万无一失的方法可以检测窗口何时实际关闭,尽管根据您想知道窗口正在关闭的原因,可能有一种“足够好”的解决方法。

    一种方法是使用EventListener 来检测close_window 命令何时即将执行或刚刚完成执行。

    这种方法的问题是,如果你使用窗口镶边关闭窗口,命令不会被执行,所以如果用户使用键绑定或菜单项关闭窗口,你只能检测到这种方式关闭的窗口窗口。

    此外,即使窗口实际上没有关闭(即如果有一个未保存的文件并且您取消),该命令也始终完全执行,并且它在窗口仍然存在时完成执行,需要您在检查之前稍等片刻查看窗口是否仍然存在:

    import sublime
    import sublime_plugin
    
    
    class WindowCloseListener(sublime_plugin.EventListener):
        def check_closed(self, w_id):
            for window in sublime.windows():
                if window.id() == w_id:
                    return print("Window %d cancelled close" % w_id)
    
            print("Window %d has closed" % w_id)
    
        def on_window_command(self, window, cmd, args):
            if cmd == "close_window":
                print("window with id %d is about to close" % window.id())
    
        def on_post_window_command(self, window, cmd, args):
            if cmd == "close_window":
                sublime.set_timeout(lambda: self.check_closed(window.id()), 250)
    

    另一种方法是继续轮询并查看窗口列表是否以曾经存在的窗口正在消失的方式发生变化。但是,进行这种检查会降低一些性能,这可能是可接受的,也可能是不可接受的。

    如果您不需要立即知道窗口正在关闭,您可以权衡轮询时间(低于 5 秒)以减少对性能的影响。

    但是,如果间隔越大,有人可以创建一个新窗口并在您不知道它存在的情况下关闭它的机会就会增加(尽管理论上您也可以捕获new_window 命令来尝试缓解这种情况)。

    它也不会告诉你最后一个窗口何时关闭,因为无法确定 Sublime 何时退出。

    import sublime
    import sublime_plugin
    import random
    
    random.seed()
    g_sentinel = random.random()
    
    def check(sentinel, old_w):
        new_w = {w.id() for w in sublime.windows()}
        closed = old_w - new_w
        if closed:
            print("Windows closed: %s" % closed)
    
        if sentinel == g_sentinel:
            sublime.set_timeout_async(lambda: check(sentinel, new_w), 5000)
    
    def plugin_loaded():
        w_list = {w.id() for w in sublime.windows()}
        sublime.set_timeout_async(lambda: check(g_sentinel, w_list), 5000)
    
    def plugin_unloaded():
        global g_sentinel
        g_sentinel = 0
    

    这通过使用set_timeout_async 每五秒轮询一次,以调用另一个超时调用自身的方法。为了安全起见,它还使用了一个全局标记值,以便运行中的轮询可以检测到插件何时重新加载或完全卸载并自行停止。

    如果没有这样的检查,如果插件重新加载发生,例如当您正在积极处理插件时,您很快就会进行多次投票。

    【讨论】:

      猜你喜欢
      • 2010-11-25
      • 1970-01-01
      • 2018-09-02
      • 1970-01-01
      • 2023-03-29
      • 2015-12-15
      相关资源
      最近更新 更多