Sublime Text插件開發的高級例程

原文地址:http://code-tech.diandian.com/post/2012-11-16/40042306130php

Sublime插件的開發,能夠首先參考How to Create a Sublime Text 2 Pluginhtml

如何開發Sublime插件 還有Sublime中文手冊 ,還有個非官方的文檔,沒有翻譯完,但願有志之士發揚開源精神,繼續完成,地址https://github.com/yangweijie/sublime-text-unofficial-documentation--cnpython

雖然看了前面兩篇文章,可是對於沒有任何python基礎的人仍是有點困難,本人主攻語言php,看了2星期的python電子書。隔了幾個月又基本還回去了,推薦一個網站能夠將經常使用php函數找到對應python版,提及來還真的很像的: http://www.php2python.com     PS:Ruby和python都能跨界,何時出個php的就行了O(∩_∩)O~git

廢話很少說了,先說一下開發插件流程:github

1.按照上面的文章開發出Example插件web

2.在此插件上添加本身的功能thinkphp

3.完善菜單、快捷鍵和配置文件等json

注意點:善用調試面板 ctrl+~,多讀其餘插件的源碼,他山之石能夠攻玉,藉助度娘和谷姐的力量  sublime-text

先粘上本插件的源碼api

 

# -*- coding: utf-8 -*-
import sublime, sublime_plugin
import  os,httplib,urllib,urllib2,json,webbrowser,codecs
                                    
def fs_reader(path):
    return codecs.open(path, mode='r', encoding='utf8').read()
                                    
def fs_writer(path, raw):
    codecs.open(path, mode='w', encoding='utf8').write(raw)
                                    
def out_tpl(new,sub=''):
    if sub == '':
        return tpl.replace('{%s}',new)
    else:
        return tpl2.replace('{%s}',new)
                                    
def get_tpl_fullpath(filename,parent_dir=''):
    return packages_path + '\\manual\\' + parent_dir + filename+'.html'
                                    
def write_tpl(filename,content,parent_dir=''):
    if not os.path.isfile(get_tpl_fullpath(filename,parent_dir)):
        fs_writer(get_tpl_fullpath(filename,parent_dir),content)
                                    
def open_tab(url):
    webbrowser.open_new_tab(url)
                                    
def get_content(id,parent_dir=0):
    conn = httplib.HTTPConnection("doc.thinkphp.cn")
    conn.request("GET", "/api/view/"+id)
    r1 = conn.getresponse()
    data1 = r1.read()
    data1 = json.loads(data1)
    data = data1['data']
    content = ''
    for i in data:
        content= content + i['content']
    if parent_dir == 0:
        return out_tpl(content)
    else:
        return out_tpl(content,1)
settings = sublime.load_settings('Thinkphp.sublime-settings')
packages_path = sublime.packages_path() + '\\Thinkphp'
manual_dir = settings.get('manual_dir')
tpl = fs_reader(os.path.join(packages_path + '\\'+ manual_dir +'\\public', 'book.tpl'))
tpl2 = fs_reader(os.path.join(packages_path + '\\'+ manual_dir +'\\public', 'book_sub.tpl'))
                                    
class ThinkphpCommand(sublime_plugin.TextCommand):
                                    
    def see(self,id,name,parent_dir=''):
        #url = 'http://doc.thinkphp.cn/manual/' + self.data[arg]['name']
        content = get_content(id,parent_dir)
        write_tpl(name,content,parent_dir)
        url = 'file://'+get_tpl_fullpath(name,parent_dir)
        open_tab(url)
                                    
    def build(self,id,name,parent_dir=''):
        content = get_content(id,parent_dir)
        write_tpl(name,content,parent_dir)
                                    
    def run(self, edit):
        data = self._init()
        self.data = data
        chapter = []
        tree = []
        sort_data = []
        k = 0
        for i in data:
            chapter.insert(int(i['id']),i['title'])
            sort_data.insert(k,i['name'])
            state = i.get('_child', None)
            if state:
                tree.insert(k,i['_child'])
            else:
                tree.insert(k,None)
            k = k+1
        # print chapter
        self.chapter = chapter
        self.sort_data = sort_data
        self.tree = tree
        self.view.window().show_quick_panel(chapter, self.panel_done)
                                    
    def panel_done(self,arg):
        if arg == -1:
            pass
        else:
            self.tree_key = arg
            if self.tree[arg] == None:
                self.see(self.data[arg]['id'],self.data[arg]['name'])
            else:
                if not os.path.isdir(packages_path + '\\'+ manual_dir +'\\'+self.sort_data[arg]):
                    os.mkdir(packages_path + '\\'+ manual_dir +'\\'+self.sort_data[arg])
                child =[]
                k = 0
                for i in self.tree[arg]:
                    child.insert(k,i['title'])
                    k +=1
                                    
                self.view.window().show_quick_panel(child, self.child_done)
                                    
    def child_done(self,arg):
        if arg == -1:
            self.view.window().show_quick_panel(self.chapter, self.panel_done)
        else:
            self.see(self.tree[self.tree_key][arg]['id'],self.tree[self.tree_key][arg]['name'],self.sort_data[self.tree_key]+'\\')
                                    
    def _init(self):
        conn = httplib.HTTPConnection("doc.thinkphp.cn")
        conn.request("GET", "/api")
        r1 = conn.getresponse()
        data1 = r1.read()
        data1 = json.loads(data1)
        return data1['data']
                                    
    def update_manual(self):
        data = self._init()
        for j in data:
            if not j.get('_child', None):
                self.build(j['id'], j['name'])
            else:
                parent_dir = j['name']
                if not os.path.isdir(packages_path + '\\'+ manual_dir +'\\'+j['name']):
                    os.mkdir(packages_path + '\\'+ manual_dir +'\\'+j['name'])
                for t in j['_child']:
                    sublime.set_timeout(self.build(t['id'],t['name'],parent_dir+'\\'),100)
        sublime.status_message('the manual has been generated')
                                    
    def search_panel(self):
        self.view.window().show_input_panel('search in thinkphp manual?', '', self.search_done, self.search_change, self.search_cancel)
                                    
    def search_done(self,arg):
        data = {'keywords' : arg}
        f = urllib2.urlopen(url = 'http://doc.thinkphp.cn/api/search',data = urllib.urlencode(data))
        data = f.read()
        data = json.loads(data)
        if data['data'] == []:
            sublime.error_message('No Search result !')
        else:
            chapter = []
            data = data['data']
            self.search_list = data
            for i in data:
                chapter.insert(int(i['id']),i['title'])
            self.view.window().show_quick_panel(chapter, self.manual_search_done)
                                    
    def manual_search_done(self,arg):
        if arg == -1:
            pass
        else:
            choose = self.search_list[arg]
            data = self._init()
            for i in data:
                if i['id'] == choose['id']:
                    self.see(choose['id'], choose['name'])
                else:
                    state = i.get('_child', None)
                    if state:
                        for j in i['_child']:
                            if j['id'] == choose['id']:
                                if not os.path.isdir(packages_path + '\\'+ manual_dir +'\\'+i['name']):
                                    os.mkdir(packages_path + '\\'+ manual_dir +'\\'+i['name'])
                                self.see(choose['id'], choose['name'], i['name']+'\\')
                                    
    def search_change(self,arg):
        pass
                                    
    def search_cancel(self):
        pass       
                                    
class update_thinkphp_manual(ThinkphpCommand,sublime_plugin.TextCommand):
    def run(self, edit):
       self.update_manual()
                                    
class search_word_thinkphp_manual(ThinkphpCommand,sublime_plugin.TextCommand):
    def run(self, edit):
        region = self.view.sel()[0]
        if region.begin() != region.end():
            self.search_done(self.view.substr(region))
        else:
            self.search_panel()
                                    
class search_thinkphp_manual(ThinkphpCommand,sublime_plugin.TextCommand):
    def run(self, edit):
        self.search_panel()

# -*- coding: utf-8 -*-  

這行註釋防止代碼有中文致使的亂碼顯示

self.view.window().show_quick_panel

這行裏的self.view.window()得到window類,以後就能夠調用window類的全部方法了,好比show_quick_panel顯示下拉列表

sublime.packages_path()

這個是獲取當前插件包的路徑,根據安裝版和綠色版返回的地址不一樣,前者win的是在用戶文檔目錄下,後者是在Sublime軟件安裝的Data\Packages裏

classThinkphpCommand(sublime_plugin.TextCommand):

這個纔是開始插件命令的定義,注意Thinkphp必定要和插件目錄名一致,當咱們保存插件py文件時,st會從新加載全部插件一次,這時在終端面板裏能夠經過view.runCommand('thinkphp')來運行它看效果,命令名要用小寫了

sublime.error_message()

Sublime類的方法能夠直接調用

class update_thinkphp_manual(ThinkphpCommand,sublime_plugin.TextCommand):

   defrun(self, edit):

      self.update_manual()

這個是前面2篇文檔沒講的,我是在gist插件的源碼裏看到的,如何在一個插件裏擴展多條命令,而且可使用當前插件的方法

settings = sublime.load_settings('Thinkphp.sublime-settings')

manual_dir = settings.get('manual_dir')

這兩句是讀取配置和獲取配置的值,固然還有本身去更新配置

region = self.view.sel()[0]
        if region.begin() != region.end():
            self.search_done(self.view.substr(region))

這個是最簡單的獲取選區的判斷後使用的例子

接下來時菜單Main.sublime-menu:

[   
    {
        "id": "tools",
        "children":
        [
            {
                "caption": "ThinkPHP manual",
                "id": "ThinkPHP manual",
                "command": "thinkphp"
            },
            {
                "caption": "ThinkPHP manual: search",
                "id": "ThinkPHP manual: search",
                "command": "search_thinkphp_manual"
            },
            {
                "caption": "ThinkPHP manual: build book",
                "id": "ThinkPHP manual: build book",
                "command": "update_thinkphp_manual"
            }
        ]
    },
    {
        "caption": "Preferences",
        "mnemonic": "n",
        "id": "preferences",
        "children":
        [
            {
                "caption": "Package Settings",
                "mnemonic": "P",
                "id": "package-settings",
                "children":
                [
                    {
                        "caption": "ThinkPHP",
                        "children":
                        [
                            {
                                "command": "open_file",
                                "args": {"file": "${packages}/Gist/ThinkPHP.sublime-settings"},
                                "caption": "Settings – Default"
                            },
                            {
                                "command": "open_file",
                                "args": {"file": "${packages}/User/ThinkPHP.sublime-settings"},
                                "caption": "Settings – User"
                            },
                            {
                                "command": "open_file",
                                "args": {
                                    "file": "${packages}/ThinkPHP/Default (Windows).sublime-keymap",
                                    "platform": "Windows"
                                },
                                "caption": "Key Bindings – Default"
                            },
                            {
                                "command": "open_file",
                                "args": {
                                    "file": "${packages}/User/Default (Windows).sublime-keymap",
                                    "platform": "Windows"
                                },
                                "caption": "Key Bindings – User"
                            },
                            { "caption": "-" }
                        ]
                    }
                ]
            }
        ]
    }
                                  
]

這裏注意的是"${packages}"表明當前插件目錄,還有就是順序,tools在preferences前面,放到後面可能不起做用了

Thinkphp.sublime-commands

[
    {
        "caption": "ThinkPHP manual: view list",
        "command": "thinkphp"
    },
    {
        "caption": "ThinkPHP manual: build book",
        "command": "update_thinkphp_manual"
    },
    {
        "caption": "ThinkPHP manual: search",
        "command": "search_thinkphp_manual"
    }
]

只有在命令文件裏寫過的命令纔會在ctrl+shift+p的命令列表中顯示

右鍵 Context.sublime-menu:

[
    { "command": "search_word_thinkphp_manual", "caption": "search_thinkphp_manual here" }
]

菜單文件配了選項在菜單中會出現,可是隻有在對應命令存在可執行,方會顯示可點擊的狀態,而不是灰色

插件命名最好使用首字母大寫的駝峯法命名如Thinkphp,最好不要帶_ 空格等。

但願你們能從這篇文章中獲得一些幫助,而後投入到轟轟烈烈的Sublime插件開發隊伍中去。。

相關文章
相關標籤/搜索