Sublime Text插件必须用Python编写,ST3基于Python 3.3、ST4基于Python 3.8,不支持第三方包和部分新语法;插件需继承sublime_plugin类并遵循命名规则才能在Command Palette中显示。

Sublime Text 插件用 Python 写,不是 JS 或 TypeScript
很多人以为 Sublime 插件像 VS Code 那样用 JavaScript 开发,其实它底层是 Python 3.8(Sublime Text 4)运行时,所有插件必须写成 .py 文件,放在 Packages/User/ 或独立包目录下。不支持 npm、import 外部 PyPI 包,也不能用 async/await(除非走 sublime.set_timeout_async)。
常见错误现象:ImportError: No module named 'requests'、插件保存后没反应、控制台报 invalid syntax(用了 f-string 但 ST3 是 Python 3.3)。
- Sublime Text 3 对应 Python 3.3,不支持
yield from、pathlib.Path等新语法 - Sublime Text 4 升级到 Python 3.8,支持
:=海象运算符,但依然不能装第三方包 - 插件入口必须继承
sublime_plugin.TextCommand或sublime_plugin.EventListener,名字要带Command后缀才能被识别
怎么让一个最简插件在 Command Palette 里出现
插件文件名决定命令 ID,比如 toggle_comment.py → 命令 ID 是 toggle_comment;类名决定显示名,ToggleCommentCommand → 显示为 “Toggle Comment”。不满足这个命名规则,ctrl+shift+p 里根本搜不到。
实操建议:
- 新建
Packages/User/hello_world.py - 内容只写三行:
import sublime_plugin,然后定义class HelloWorldCommand(sublime_plugin.TextCommand):,再写一个def run(self, edit): self.view.insert(edit, 0, "Hello") - 重启 Sublime 或按
ctrl+shift+p→Developer: Reload Plugin,再打开 Command Palette 搜 “hello”,就能看到 “Hello World”
edit 对象不能跨函数传,也不能缓存
edit 是 Sublime 的编辑上下文令牌,只在 run() 方法内有效,且一次 run() 只能用一次。拿它当全局变量、塞进 threading.Thread、或者在回调里重用,都会触发 RuntimeError: Invalid edit object。
典型错误场景:想异步读文件再插入内容,结果在 set_timeout_async 回调里直接用上一个 edit。
- 正确做法:把需要插入的文本先算好,再用
sublime.set_timeout(lambda: self.view.insert(edit, pt, text), 0)—— 但注意,这仍然错,因为edit已失效 - 真正可行的是:改用
self.view.run_command('insert', {'characters': text}),或重新获取edit = self.view.begin_edit()(仅限 ST3,ST4 不允许) - ST4 推荐方案:用
view.run_command('insert', ...)或自定义一个新 command 来封装插入逻辑
监听文件保存但不想重复触发
on_post_save 是最常用事件,但它在每次保存都触发,包括自动保存、格式化后保存、甚至 Git 插件覆盖写入。如果插件里做了耗时操作(比如调用外部 CLI),很容易卡住 UI 或重复执行。
关键判断点在于区分“用户主动保存”和“后台静默保存”:
- 检查
view.is_dirty()—— 保存后通常为False,但不可靠,因为有些插件会立刻改写 - 更稳的方式:记录上次保存时间戳 + 文件大小,两次变化都一致才跳过
- 或者加开关:用
view.settings().set('skip_on_post_save', True)在格式化前设,保存后清,配合on_post_save_async避免阻塞主线程
别忽略 _async 版本事件 —— 它们在子线程跑,不能直接调用 view.insert,但适合做 IO 或计算。











