sublime Text 3 以下简称ST3是一个非常性感的文本编辑器,很多前端开发者在使用它。无插件,不神器,插件的使用可以使开发更方便快捷。目前社区里提供了各种各样的插件,在搜索里一搜就是各类插件的使用推荐,即使有这么多的插件,有时也不能满足我们的开发需要,今天就跟大家聊一下前段时间实现的(QcmsAux)插件的开发过程,希望给打算写插件的小伙伴们提供参考。
前期知识了解
1.了解Python
ST3是通过C++开发的,它的插件系统是通过Python来编写的,所以你一定要会Python,不一定非常精通,但是一定要了解,用到哪块儿知道去哪儿查。
推荐:Python基础教程 做为入门了解。
2. Python控制台
Sublime Text中内嵌了Python解释器。ST3中的Python和系统中的python是相互独立的。
我使用的是OSX系统,系统中的pythone版本是
python -V // Python2.7.10
打开Python控制台
- 快捷键:Ctrl + `
- 菜单: View -> Show Console
在这个控制台中查看,当前ST3中sublime的信息
sublime.version() // '3126'
sublime.platform() // 'osx'
查看ST3中python的版本
platform.python_version() //'3.3.6'
3. 重要的几个目录
Data目录
ST3几乎所有需要的文件都保存在Data目录下,不同的操作系统路径不同:
- Windows: %APPDATA%Sublime Text 3
- OS X: ~/Library/Application Support/Sublime Text 3
- Linux: ~/.config/sublime-text-3
删除这个目录之前使用的插件和自定义的一些配置都会被同时删除,再次打开ST3,这个目录会被自动创建。
Packages目录
Data目录下的Packages目录是一个非常重要的目录,关于编程和标记语言的所有支持都保存在这里。
通过Sublime Text -> Preferences -> Browse Packages…可以打开该目录。
User 目录
User目录在Packages目录下,用于保存自定义plugins,snippets, macros(宏)。插件配置等都存在这个目录下。插件更新时,这个目录里的内容不会被修改。
准备工作
一个简单的插件示例
Tools -> Developer -> New Plugin, 使用这个命令可以创建一个插件示例,保存该文件,默认会保存在User目录下,默认文件名是 untitled.py
插件保存的位置
通过Package Control 安装的插件有的以源码的形式存入Packages目录,有的则以.sublime-package
结尾的压缩包存在在上层目录的Installed Packages
文件夹下。
ST3将会3个地方依次加载插件:
- Installed Pacages(only .sublime-package files)
- Packages
- Packages/User
根据约定,不会加载更深层次嵌套的文件,也就是说如果把 untitled.py
放在packages目录下会生效,但是如果放在User/new/下就不会生效。下面我直接放Packages/Example/
下,文件名称改为Example.py
,这里建议文件名和目录名保持一致。
我本机的目录/Users/rongl/Library/Application Support/Sublime Text 3/Packages/Example/
打开控制台,看到reloading plugin example.Example
,说明插件已经被自动加载了,然后运行view.run_command('example')
,如下会在第一行插入Hello, World!
,这样这个简单的插件就执行成功了。
Hello, World!import sublime
import sublime_plugin
class ExampleCommand(sublime_plugin.TextCommand):
def run(self, edit):
self.view.insert(edit, 0, "Hello, World!")
到目前为止已经完成了简单的插件的编写执行。在上面的示例中:
- sublime_plugin.TextCommand:这是文本编辑相关的基类,文本编辑相关的命令都继承于这个基类。
- ExampleCommand: 类名以
Command
结尾,之前的部分为命令名,其中首字母要大写。执行命令时则采用下划线风格的拼写,view.run_command
中传入example
,如果为MyExampleCommand
,则传入my_example
。 - run(self,edit): 执行命令时会执行这个函数,这是固定格式。edit为API中提供的edit对象,在编辑时会用到。self,代表类ExampleCommand的实例。
- self.view.insert(edit,point,content): point是init类型,指定编辑器中的一个坐标。所有插入,删除,选取等操作都通过self.view调用。
示例的效果就是在point位置插入content.
QcmsAux的开发过程
插件的主要功能
- 获取当前文件的路径,分析文件路径和文件名后缀,判断是否符合配置中指定的条件
- 如果未在qcms创建,调用qcms接口,在qcms创建文件,并返回新建文件的pid
- 已提交git,已在qcms创建,调用OBQ接口,发布到测试或上线
- 已提交git,调用OBQ接口,查看当前文件操作信息
- 调用验证接口,进行代码验证
- 跳转到OBQ平台,查看当前模板对应的query
- 跳转到OBQ平台,解锁当前模板
- 支持在SideBar中文件上右键弹出菜单上传到测试或上线
核心功能的实现
- QCMS创建页面查看QCMSAPI
sublime.load_settins
加载插件的配置文件,配置文件内容格式为jsop,分User和default两种,分别位于Packages/User/<setting-name>
和Packages/<package-name>/<setting-name>
中,前者覆盖后者。
# 获取配置信息
settings = sublime.load_settins("QcmsAux.sublime-settings")
settings.get('key')
# 获取页面内容
content = view.substr(sublime.Region(0, view.size()))
# 往接口post信息,urllib发送数据和header伪代码
import urllib.parse
import urllib.request
url = 'http://localhost/login.php'
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
values = {
'act' : 'login',
'login[email]' : xx@xx.com',
'login[password]' : '123456'
}
headers = { 'User-Agent' : user_agent }
data = urllib.parse.urlencode(values)
req = urllib.request.Request(url, data, headers)
response = urllib.request.urlopen(req)
the_page = response.read()
print(the_page.decode("utf8"))
2.指定浏览器打开url
# MacOS
CHROME_PATH = 'open -a /Applications/Google\ Chrome.app %s'
# Windows
# chrome_path = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe %s'
#
# Windows
# chrome_path = 'C:\Program Files (x86)\Google\Chrome\Application\chrome.exe %s'
url = "http://www.so.com"
webbrowser.get(CHROME_PATH).open(url,new=1)
耗时任务阻塞主线程
ST3已经提供了非常方便的异步执行耗时任务的方法set_timeout_async
快捷键
sublime大部分的配置都可以通过json文件来完成,键盘绑定也一样。不过它的键盘绑定是区分系统的,所以基本上要建立3个文件,而且命名为Default (Windows).sublime-keymap
, Default (Linux).sublime-keymap
和 Default (OSX).sublime-keymap
菜单项
- Main.sublime-menu 控制了程序的主菜单
- Side Bar.sublime-menu 控制侧边栏文件或者目录的右键菜单
- Context.sublime-menu 控制处于编辑状态的文件右键菜单
通过console打印
print xxxx
弹出式的窗口
sublime.error_message("hello world")
几个常见概念
Window:
打开的 sublime text 窗口
View
表示一个文本缓冲的视图,可以认为是打开的一个 tab。
Edit
继承自 sublime_plugin.TextCommand 的命令, Edit 为第一个参数。 打开一个 view 以后必须要指定 Edit 才能真正的 insert 字符。需要 view.begin_edit 开始使用编辑区,使用完要 end_edit 。根据 sublime 3 API 的说法,只能继承,不能被创建。
Region
表示缓冲区的一个区域。有两个init类型的属性a和b。Region.a表示区域开始的点,Region.b表示区域结束的点。
view 的 find_all 等可以匹配一系列的 region 出来
Selection(RegionSet)
表示选择的区域。函数sublime.View.sel()返回的类型就是Selection,表示目前选中的所有区域。Selection.add(Region)方法可以添加选择区域。
Point概念
int类型,代表缓冲区的一个位置。可以通过sublime.View.rowcol(point)将point转化为行列信息(int,int)。或通过sublime.View.text_point(row,col)将行列信息转化为point。
- Point 是跟文本开头位置的偏移量
- 获得当前光标位置的 point: view.sel()[0].a
- 一个 region 的属性 a b 为起始的俩个 point
line:
这里看到 line 返回的是鼠标所在行的起始字符数,从文件头开始,算 UTF8 字符,一个中文也是一个字符,无论光标在何处,都是这样的结构(行开始字符数, 行结束字符)
mark = self.view.sel()[0]
line = self.view.line(mark.a)
sublime.status_message("hickdebug " + time.strftime("%Y-%m-%d %X - ") + str(line))
内置命令
expand_selection
用内置的expand_selection命令,to参数设置为brackets 每个css规则区域内容就可以选中了
self.view.run_command("expand_selection", {"to": "brackets"})
python中执行shell命令的四种方式
- os.system()
这个方法得不到shell命令的输出
import os
os.system('ls')
# 执行ls命令
- popen()
这个方法能得到命令执行后的结果是一个字符串,要自行处理才能得到想要的信息
import os
str = os.popen("ls").read()
a = str.split('\n')
for b in a:
print b
- commands模块
可以很方便的取得命令的输出(包括标准和错误输出)和执行状态位
commands.getstatusoutput(cmd) 返回(status,output)
import commands
a,b = commands.getstatusoutput('ls')
print a
# a是退出的状态
# 0
print b
# b是输出结果
# 执行ls命令
commands.getoutput(cmd) 只返回输出结果
import commands
b = commands.getoutput('ls')
# 执行ls命令
commands.getstatus(file) 待补充
- subprocess模块
使用subprocess模块可以创建新的进程,可以与新建进程的输入/输出/错误管道连通,并可以获得新建进程执行的返回状态。使用subprocess模块的目的是替代os.system(),os.popen(),commands*等旧的函数和模块。
subprocess.call(command,shell=True)
import subprocess
subprocess.call('ls',shell=True)
# 执行ls命令
subprocess.Popen(command,shell=True)
import subprocess
subprocess.Popen('ls',shell=True)
# 执行ls命令
subprocess.Popen(command,stdout=subprocess.PIPE,shell=True)待补充
如果command不是一个可执行文件,shell=True是不可省略的。
shell=True表示在shell下执行command
常用语句功能
view.settings().get('syntax')
返回当前文件格式,常见的有
- [tpl,inc,html] : Packages/HTML/HTML.sublime-syntax
- css: Packages/CSS/CSS.sublime-syntax
- php: Packages/PHP/PHP.sublime-syntax
- js:Packages/JavaScript/JavaScript.sublime-syntax
- py:Packages/Python/Python.sublime-syntax
if int(sublime.version()) > 3000
print("sublime3")
判断sublime的版本信息
命令的拼写
[‘node’, ‘/Users/guopeipei/Library/Application Support/Sublime Text 3/Packages/JSLint/linter.js’, ‘–bitwise’, ‘–browser’, ‘–es6’, ‘–eval’, ‘–for’, ‘–fudge’, ‘–node’, ‘–this’, ‘/Users/guopeipei/project/M_so_com/m_so/resource/js/result/scrollTab.js’]
Running node /Users/guopeipei/Library/Application Support/Sublime Text 3/Packages/JSLint/linter.js –bitwise –browser –es6 –eval –for –fudge –node –this /Users/guopeipei/project/M_so_com/m_so/resource/js/result/scrollTab.js
sublime.View类重要方法
sublime.View.find_by_class(point, forward, classes, <separators>)
通过Class查找,sublime提供的Class
- sublime.CLASS_WORD_START
- sublime.CLASS_WORD_END
- sublime.CLASS_PUNCTUATION_START
- sublime.CLASS_PUNCTUATION_END
- sublime.CLASS_SUB_WORD_START
- sublime.CLASS_SUB_WORD_END
- sublime.CLASS_LINE_START
- sublime.CLASS_LINE_END
- sublime.CLASS_EMPTY_LINE
sublime.View.find_by_selector(selector)
根据语法选择器查找 ,selector是一个字符串。Scope Naming
sublime.py文件位置
/Applications/Sublime Text.app/Contents/MacOS/sublime.py