为sublime text 3开发插件

Published On December 06, 2016

category tool | tags sublime plugin


sublime text 3(以下简称ST3)是一个非常性感的文本编辑器,很多前端开发者用她作为IDE,经过配置也能将她打造成一个包括c、php等其他语言的IDE。ST3是用C++开发的,她的插件系统是由python3编写,所以只要你熟悉python,就可以很轻松的为ST3开发插件。下面是我记录的一个简单插件(GithubMarkdown)的开发过程,希望给入门的同学提供一定的参考。

准备工作

一个简单插件示例

在菜单中依次选择Tools->Developer->New Plugin 这是一个最简单的插件的示例,保存该文件,默认会保存到Sublime Text 3/Packages/User目录下,文件名为untitled。

import sublime
import sublime_plugin


class ExampleCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        self.view.insert(edit, 0, "Hello, World!")
ctrl+~打开控制台,看到reloading plugin User.untitled,说明插件已经被自动加载了。 然后在控制台的输入框里输入view.run_command('example'),可以看到当前编辑的文件开头插入了Hello, World!,说明这个简单插件生效了。是不是超级简单? view.run_command的参数是下划线风格的命令名,ST3在执行的时候将首字母大写并去掉下划线,如执行view.run_command('my_example')则ST3会执行MyExampleCommand类里的run方法

插件保存位置

选择preferences->Broswer pakages打开插件保存的目录,在我的mac os上是/Users/yxr/Library/Application Support/Sublime Text 3/Packages。通过package control安装的插件有的以源码的形式存放在该目录下,有的则以.sublime-package结尾的压缩包存放在上层目录的Installed Packages文件夹下。ST3将会从3个地方加载插件:

  • Installed Packages (only .sublime-package files)
  • Packages
  • Packages//

根据约定,不会加载更深层次嵌套的python文件,也就是说如果将前面的untitled.py放到Packages目录下会生效,而放到User/New/下面将不会生效。 下面我要开发的插件直接保存在Packages/GithubMarkdown/

插件开发文档和源码示例

  • 官方api文档
  • 非官方文档 由于ST3并没有提供详细的插件开发教程,因此更好的方式是直接阅读现有的插件源码。
  • a tutorial: how to create a sublime text 2 plugin
  • 官方api文档Packages/Default目录下有很多示例插件,但我没有找到Default文件夹。不过我在ST3的安装目录下找到了:/Applications/Sublime Text.app/Contents/MacOS/Packages/Default.sublime-package,将该压缩包解压到桌面,就可以看到里面的内容。py文件就是插件,对于插件开发,这些示例就是最好的学习资源。

GithubMarkdown的开发过程

GithubMarkdown的功能是调用github提供的api渲染markdown。主要是解决两个需求:

  1. 我很喜欢GFM这种风格的markdown
  2. 添加或修改github项目的README时在本地预览效果

    有关GFM请参考Mastering Markdown

插件工作原理

  1. 获取当前文件的路径(第5步会用到)
  2. 获取当前编辑的文件内容(包含没有写到磁盘的改动)
  3. 调用github api渲染 文档说github上的README.md使用markdown mode,而issues里的评论使用gfm mode。但是奇怪的是以markdown的模式并不能渲染task list,这在github的README里都能渲染。所以,为了支持高级功能这里使用gfm模式。
  4. 将返回作为body部分插入到html文件模版中,由于markdown渲染是不带样式的,所以需要添加额外的样式表来获得和github readme一致的样式,我使用的是sindresorhus/github-markdown-css项目提供的样式
  5. 将带有样式的html写入到原文件所在文件夹下,文件名相同,后缀为.html 如果每次转换后在默认浏览器中打开,那么多次渲染将会打开很多的标签页,这种方式并不友好,所以采用这种简单的方式,直接写到文件中,用户可以在浏览器中打开这个html文件,每次更新后刷新一下。

核心功能的实现

克隆代码到本地并切换到特定的tag

git clone https://github.com/yanxurui/GithubMarkdown
git checkout v1

  • 该插件使用的是TextCommand,每一个TextCommand对应一个view,可以通过self.view访问view对象。同理WindowCommand对应一个window对象,应该根据需要选择相应的command类型。
  • sublime.load_settings加载插件的配置文件,配置文件是json对象,分User和Default两种,分别位于Packages/User/<setting-name>Packages/<package-name>/<setting-name>中,前者覆盖后者。该方法返回Settings对象,类似dict
  • self.view.file_name获取当前文件的完整路径
  • self.view.substr(sublime.Region(0, self.view.size()))获取当前view的内容
  • sublime.status_message在sublime的状态栏上显示提示信息,第一条信息sublime.status_message('GithubMarkdown: request github api...')看不到,这是个bug有待解决
  • sublime.error_message弹窗提示信息
  • sublime.load_resource加载给定的资源,返回str,名字格式应该类似Packages/Default/Main.sublime-menu

耗时任务阻塞主线程

上面的插件在使用体验上很不好,网络请求是耗时任务,会把主线程阻塞,这是桌面应用开发的大忌。因此要把耗时任务放到子线程中执行,事实上ST3已经提供了非常方便的异步执行耗时任务的方法set_timeout_async。修改后的版本可以通过如下命令获取:

git checkout v2
当请求github api的时候ST3的状态栏会提示GithubMarkdown: request github api...,当请求返回的时候该提示消失。

命令面板

运行某个命令除了在console里执行view.run_command('<command_name>')还可以将命令加入到Command Pallete(命令面板)中,每次从命令面板搜索来执行,而且ST3会记住上次执行的命名,这就方便多了。新增Default.sublime-commands

[
    {
        "caption": "Github Markdown: render a markdown document by github",
        "command": "github_markdown"
    }
]
通过快捷方式shift+cmd+p打开命令面板,输入github即可看到我们添加的命令,回车执行。下次打开命令面板还能看到该命令处于选中状态。

快捷键

很多时候通过Command Pallete来调用命令还是不够方便,幸好ST3能让我们轻松的设置快捷键。在不通的OS上快捷键是不同的,因此需要针对每种OS配置相应的快捷键。以OS X为例,在我们的插件目录下创建Default (OSX).sublime-keymap:

[
    {
        "keys": ["ctrl+alt+g"],
        "command": "github_markdown"
    }
]
这是一个包含json对象的数组,每个对象包含必选的keyscommand两个键,以及可选的args。 同理,为其他系统绑定快捷键只需要增加相应的配置文件即可,参考目录下的Default (Windows).sublime-keymapDefault (Linux).sublime-keymap。windows和linux的快捷键几本一致。

菜单项

能够定制菜单是ST3提供的另一项非常酷的事情,方法是创建.sublime-menu文件,最常用的文件名有三种:

  • Main.sublime-menu controls the main program menu
  • Side Bar.sublime-menu controls the right-click menu on a file or folder in the sidebar
  • Context.sublime-menu controls the right-click menu on a file being edited 本插件目录下的Main.sublime-menu

    “Side Bar” is when you right-click a document or folder on the left side of the application (not shown when opening individual files), and “Context” is the right-click menu over the text area.

上下文菜单

首先为这个插件增加一个上下文菜单,也就是在编辑器右键出现的菜单项。在该目录下创建Context.sublime-menu

[
    { "command": "github_markdown", "caption": "Render this markdown file" }
]
一开始我把command填错了,导致该选项在类型的文件的右键菜单中都会显示,并且是灰色的。 上面的设置还存在一个问题,对任何文件都会显示这个选项,为了限定只对markdown文件可见,就像ST3自带的open in browser菜单项一样,需要在类里增加一个方法:
def is_visible(self):
    return self.view.file_name() is not None and (
        self.view.file_name()[-3:] == ".md" or
        self.view.file_name()[-3:] == ".MD")

主菜单

然后再添加一个插件设置菜单,方便用户修改参数配置和重新绑定快捷键,新增Main.sublime-menu文件

[
    {
        "caption": "Preferences",
        "mnemonic": "n",
        "id": "preferences",
        "children": [
            {
                "caption": "Package Settings",
                "mnemonic": "P",
                "id": "package-settings",
                "children": [
                    {
                        "caption": "GithubMarkdown",
                        "children": [
                            {
                                "command": "open_file",
                                "args": {
                                    "file": "${packages}/GithubMarkdown/GithubMarkdown.sublime-settings"
                                },
                                "caption": "Settings – Default"
                            },
                            {
                                "command": "open_file",
                                "args": {
                                    "file": "${packages}/User/GithubMarkdown.sublime-settings"
                                },
                                "caption": "Settings – User"
                            },
                            {
                                "caption": "-"
                            },
                            {
                                "command": "open_file",
                                "args": {
                                    "file": "${packages}/GithubMarkdown/Default (OSX).sublime-keymap",
                                    "platform": "OSX"
                                },
                                "caption": "Key Bindings – Default"
                            },
                            {
                                "command": "open_file",
                                "args": {
                                    "file": "${packages}/User/Default (OSX).sublime-keymap",
                                    "platform": "OSX"
                                },
                                "caption": "Key Bindings – User"
                            },
                            {
                                "caption": "-"
                            },
                            {
                                "command": "open_file",
                                "args": {
                                    "file": "${packages}/GithubMarkdown/README.md"
                                },
                                "caption": "README"
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

  • mnemonic表示助记符,它的作用是在windows和linux系统上作为一种选择菜单的快捷方式。
  • PreferencesPackage Settings是已有的菜单项,可以不加caption和mnemonic,但是其他插件在主菜单的配置中都加上了,这也许是一种惯例。
  • 快捷键配置需要根据操作系统打开相应的文件,使用platform参数选择。

其他

调试技巧

ST3没有设置代理的功能,也不支持系统代理(在我的OS X上如此)。有时候为了调试需要抓取http请求的包就成了难题,简单的将charles设置成系统代理是抓不到ST3的包。还好,ST3支持http_proxyhttps_proxy这两个环境变量,因此调试的时候可以这样启动ST3

http_proxy=http://localhost:8888 https_proxy=http://localhost:8888 "/Applications/Sublime Text.app/Contents/MacOS/Sublime Text"
其中http://localhost:8888是chalse监听的地址。由于github的api都是通过https访问的,因此还需要在chalse中打开api.github.com的https解析。

另外,如果要通过Package control下载被墙的插件是可以通过package control的配置文件设置代理(在package control的默认配置文件中搜索proxy)。

提交到package control

ST官方没有提供插件中心,这一点我觉得做得不好。好在package control这个社区维护的插件给我们带来了福音,它支持我们检索、安装和更新插件。提交插件到package control的流程参见文档。由于该平台的作者不欢迎我们提交功能和已有插件类似的插件,因此我这个插件便没有提交。

开源协议&README

和其他github项目一样,加上开源协议和REAME,README很重要!!!


qq email facebook github
© 2018 - Xurui Yan. All rights reserved
Built using pelican