关闭窗口前的sublime捕获事件

时间:2017-11-02 12:46:04

标签: python plugins sublimetext

我正在尝试在关闭一个崇高的窗口时捕获该事件。我一直在尝试使用plugin_unloaded但是在关闭窗口时似乎没有调用此方法

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

我希望在关闭窗口时创建文件,但事实并非如此,因此是否有一个触发的方法,我可以在窗口关闭时用它来执行某些操作?

1 个答案:

答案 0 :(得分: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调用一个自动调用另一个超时的方法,每五秒轮询一次。为了安全起见,它还使用全局sentinel值,以便正在运行的轮询可以检测插件何时完全重新加载或卸载并自行停止。

如果没有这样的检查,如果您正在重新加载插件,那么您很快就会进行多次民意调查,例如当您正在积极处理插件时。