我尝试创建一个插件,打开与我正在编辑的文件关联的.log文件。我能够打开文件但无法将光标移动到文件末尾,除非我在文件已经打开时再次运行代码。
import sublime
import sublime_plugin
class OpenlogCommand(sublime_plugin.TextCommand):
def run(self, edit):
if os.path.isfile(self.view.file_name()[:-3]+"log"):
a=sublime.active_window().open_file(self.view.file_name()[:-3]+"log")
a.run_command("move_to", {"to": "eof"})
有人知道怎么做吗?
答案 0 :(得分:1)
除非文件已经打开,否则这不起作用的原因是因为加载文件是异步的;打开文件的命令立即返回,如果文件尚未打开,则文件将在后台加载。
因此,第一次运行该命令时,move_to
命令不执行任何操作,因为它已经在空缓冲区的末尾,但是当文件已经加载时,它会按预期执行。
要解决此问题,您需要检测文件是否仍在加载并将调用推迟到文件末尾,直到文件结束。这方面的一个例子如下:
import sublime
import sublime_plugin
import os
class OpenLogCommand(sublime_plugin.TextCommand):
def run(self, edit):
log_name = self.view.file_name()[:-3] + "log"
log_view = self.view.window().open_file(log_name)
if log_view.is_loading():
log_view.settings().set("_goto_eol", True)
else:
log_view.run_command("move_to", {"to": "eof"})
def is_enabled(self):
fname = self.view.file_name()
if fname is not None and not fname.endswith(".log"):
return os.path.isfile(fname[:-3] + "log")
return False
class OpenLogListener(sublime_plugin.EventListener):
def on_load(self, view):
if view.settings().get("_goto_eol", False):
view.settings().erase("_goto_eol")
view.run_command("move_to", {"to": "eof"})
现有版本的问题是,如果文件尚未保存到磁盘,file_name()
方法将返回None
。因此,如果您在未保存的文件上运行该命令,它将在控制台中生成错误。这是无害的,但是有点不干净,因为如果你有其他问题并碰巧在控制台中看到这些错误,它可能是一个红色的鲱鱼。
此处命令仅在保存文件时才启用自身以停止此类问题。如果它不是一个日志文件(因为那将是多余的),并且实际存在关联的日志文件,它也只会启用它自己。
禁用命令时,无法执行该命令。这意味着它也不会显示在命令调色板中,它将在菜单中显示为灰色(假设您已将其添加到其中任何一个)。
运行该命令时,它首先调用open_file
打开关联的日志文件,然后询问视图“您还在加载吗?”。当视图显示NO时,表示文件已经打开,因此我们可以立即跳转到文件的末尾。
如果视图对这个问题说“是”,那么我们在视图中设置一个临时设置,这样我们就知道当这个视图的内容加载完毕时,我们想跳到缓冲区的末尾。
如果设置了此设置,则事件侦听器会询问每个视图是否已完成加载,如果设置了该设置,则会删除该设置,然后跳转到文件的末尾。
[编辑]
正如下面的评论中所提到的,move_to
命令对于已经打开的文件与刚刚完成加载的文件的行为略有不同。
我不完全确定为什么会出现这种情况,但我怀疑在文件内容加载但尚未显示的情况下正在传递的on_load
通知之间存在微妙的相互作用或沿着这些行显示,虽然这只是猜测。
在任何情况下,最方便的修复方法是通过用以下代码替换上面代码的那部分来对事件监听器进行一些修改:
class OpenLogListener(sublime_plugin.EventListener):
def on_load(self, view):
if view.settings().get("_goto_eol", False):
view.settings().erase("_goto_eol")
sublime.set_timeout(lambda: view.run_command("move_to", {"to": "eof"}), 1)
这会稍微改变一下,以便在所有事件处理完成后有效地调用move_to
命令。这似乎解决了我的测试机器上的问题,至少。