你好,歡迎進(jìn)入江蘇優(yōu)軟數(shù)字科技有限公司官網(wǎng)!
發(fā)布時(shí)間:2023-08-15
瀏覽次數(shù):0
作者|
喜歡使用Text的同事都知道,Text相當(dāng)于Linux上的Vim。 它們都具有擴(kuò)展性強(qiáng)、功能豐富、速度快等特點(diǎn)。 它們對(duì)于處理大文件和項(xiàng)目非常高效,所以如果不是很復(fù)雜的項(xiàng)目,我通常使用 Text 來(lái)編譯和編譯它們。
但在使用Text進(jìn)行開(kāi)發(fā)的過(guò)程中,我發(fā)現(xiàn)了一個(gè)問(wèn)題:Text本身的手動(dòng)補(bǔ)全功能只搜索當(dāng)前視圖中正在編輯文件的功能。 當(dāng)我想在其他文件中使用自定義函數(shù)時(shí),沒(méi)有手動(dòng)補(bǔ)全功能。 的。 而且當(dāng)自??定義功能過(guò)多時(shí),效率會(huì)大大提高,于是我開(kāi)始尋找具有相關(guān)功能的插件。
一開(kāi)始我用的是非常流行的“”插件,確實(shí)很好用。 不幸的是,這個(gè)插件不支持C/C++,而且占用大量空間。 我必須尋找另一種方式來(lái)追求簡(jiǎn)單和輕盈。 后來(lái)我發(fā)現(xiàn)了一個(gè)“All”插件。 該插件擴(kuò)展了Text默認(rèn)的手動(dòng)補(bǔ)全功能。 它可以搜索當(dāng)前視圖中打開(kāi)的所有文件中定義的函數(shù)和變量。 雖然效果很好,但也存在很多問(wèn)題。 顯然,必須同時(shí)打開(kāi)多個(gè)文件,極其不方便,所以我又放棄了。
在網(wǎng)上找了半天,沒(méi)有找到我想要的插件,于是我開(kāi)始考慮自己寫(xiě)一個(gè)這樣的插件,正好利用這個(gè)機(jī)會(huì)入門(mén)。 這時(shí)我就想到是否可以使用CTags,它可以提取當(dāng)前項(xiàng)目中的所有自定義函數(shù),生成.tags文件,并提供符號(hào)跳轉(zhuǎn)功能,只需提取.tags文件上的信息,使用正則匹配,然后添加到Text的手動(dòng)補(bǔ)全功能還不夠。
為了完成這個(gè)插件,我在網(wǎng)上查找了相關(guān)資料,找到了相關(guān)資料并重新思考,同時(shí)參考了All插件的源碼。
需要提到的是,Text下安裝CTags的方法這里就不說(shuō)了,請(qǐng)自行查看。
插件的想法
?
讀取設(shè)置,設(shè)置中添加的語(yǔ)言禁用了插件功能
?
檢查.tag文件是否存在,如果不存在,則直接
?
讀取當(dāng)前文件夾中的.tag文件
?
正則匹配函數(shù)名
?
正則匹配函數(shù)體
?
添加到手動(dòng)完成的套接字
動(dòng)筆
新插件
剛開(kāi)始寫(xiě)Text插件的時(shí)候,其實(shí)需要了解Text提供的各種。 于是,我去Text的官網(wǎng)查找相關(guān)文檔:[1]、Text[2]。
首先,在Text中選擇“Tools->->New”,創(chuàng)建一個(gè)基本的插件文檔:
import sublime
import sublime_plugin
class ExampleCommand(sublime_plugin.TextCommand):
? ?def run(self, edit):
? ? ? ?self.view.insert(edit, 0, "Hello, World!")
這里 和 是需要的模塊,具體的類(lèi)和方法可以參考官方API[3]。
接下來(lái)sublime text 安裝插件,將此文件保存到文件夾(默認(rèn)保存位置User文件夾的上層)中的文件夾(新建)中,并命名為.py。 雖然命名沒(méi)有限制,但是最好使用插件的名字來(lái)統(tǒng)一命名。
然后回到Text,通過(guò)快捷鍵Ctrl+`輸入Text,然后進(jìn)入view.(''),如果底部顯示“Hello World”,則說(shuō)明插件已正常加載。
這里之所以直接使用'',是因?yàn)槊蠲前凑招?xiě)字符分割的。
文本中的術(shù)語(yǔ)
?
:Text的當(dāng)前窗口對(duì)象
?
View:當(dāng)前窗口中打開(kāi)的文本視圖對(duì)象
?
:Text中快捷鍵Ctrl+Shift+P打開(kāi)的交互列表
確定插頭插座類(lèi)型
Text 下的插件命令有 3 種命令類(lèi)型(均來(lái)自模塊):
?
Class[4]:通過(guò) View 對(duì)象提供對(duì)所選文件/緩沖區(qū)內(nèi)容的訪(fǎng)問(wèn)。
?
Class[5]:通過(guò)對(duì)象提供對(duì)當(dāng)前窗口的引用
?
Class[6]:該類(lèi)不引用任何特定的窗口或文件/緩沖區(qū),因此很少使用
2種風(fēng)暴竊聽(tīng):
?
Class[7]:竊聽(tīng)Text中的各種干擾并執(zhí)行命令
?
Class[8]:提供類(lèi)似于風(fēng)暴處理的類(lèi)sublime text 安裝插件,但綁定到特定視圖。
2 個(gè)輸入處理程序:
?
Class[9]:可用于接受文本輸入。
?
Class[10]:可用于接受來(lái)自列表項(xiàng)的選擇輸入。
因?yàn)槲乙獙?shí)現(xiàn)的功能比較簡(jiǎn)單,只需要監(jiān)聽(tīng)輸入風(fēng)暴并觸發(fā)手動(dòng)補(bǔ)全功能,所以需要使用Class。 在這個(gè)類(lèi)下,我們找到了一種方法來(lái)處理觸發(fā)手動(dòng)完成時(shí)執(zhí)行的命令。 然后把剛才的代碼改一下:
import sublime
import sublime_plugin
class CTagsAutoComplete(sublime_plugin.EventListener):
? ?def on_query_completions(self, view, prefix, locations):
?
視圖:當(dāng)前視圖
?
:觸發(fā)??手動(dòng)完成時(shí)輸入的文本
?
:觸發(fā)??手動(dòng)完成時(shí),輸入緩沖區(qū)中的位置。 您可以使用該參數(shù)來(lái)確定執(zhí)行不同命令的語(yǔ)言
?
返回類(lèi)型:
?無(wú)
?[["\\thint",""]...],其中\(zhòng)\thint是可選的,為手動(dòng)完成的函數(shù)名稱(chēng)添加提示
?(,flag),這是一個(gè)包含手動(dòng)完成的句子的列表,如上所述; flag是一個(gè)附加參數(shù),可以用來(lái)控制是否顯示Text自帶的手動(dòng)補(bǔ)全功能
讀取CTags文件
為了讀取.tag文件,首先要判斷當(dāng)前項(xiàng)目是否打開(kāi)以及.tag文件是否存在,然后讀取.tag文件中的所有內(nèi)容:
import sublime
import sublime_plugin
import os
import re
class CTagsAutoComplete(sublime_plugin.EventListener):
? ?def on_query_completions(self, view, prefix, locations):
? ? ? ?results = []
? ? ? ?ctags_paths = [folder + '\\.tags' for folder in view.window().folders()]
? ? ? ?ctags_rows ?= []
? ? ? ?for ctags_path in ctags_paths:
? ? ? ? ? ?if not is_file_exist(view, ctags_path):
? ? ? ? ? ? ? ?return []
? ? ? ? ? ?ctags_path = str(ctags_path)
? ? ? ? ? ?ctags_file = open(ctags_path, encoding = 'utf-8')
? ? ? ? ? ?ctags_rows += ctags_file.readlines()
? ? ? ? ? ?ctags_file.close()
def is_file_exist(view, file):
? ?if (not view.window().folders() or not os.path.exists(file)):
? ? ? ?return False
? ?return True
通過(guò)以上操作,可以讀取當(dāng)前項(xiàng)目下所有.tag文件的內(nèi)容。
分析 CTags 文件
第一個(gè)是獲取 .tags 文件中包含的行:
for rows in ctags_rows:
? ?target = re.findall('^' + prefix + '.*', rows)
一旦找到,該行數(shù)據(jù)就會(huì)通過(guò)正則表達(dá)式進(jìn)行處理:
if target:
? ?matched = re.split('\\t', str(target[0]))
? ?trigger = matched[0] # 返回的第一個(gè)參數(shù),函數(shù)名稱(chēng)
? ?trigger += '\\t(%s)' % 'CTags' # 給函數(shù)名稱(chēng)后加上標(biāo)識(shí) 'CTags'
? ?contents = re.findall(prefix + '[0-9a-zA-Z_]*\\(.*\\)', str(matched[2])) # 返回的第二個(gè)參數(shù),函數(shù)的具體定義
? ?if (len(matched) > 1 and contents):
? ? ? ?results.append((trigger, contents[0]))
? ? ? ?results = list(set(results)) # 去除重復(fù)的函數(shù)
? ? ? ?results.sort() # 排序
處理完成后即可返回。 考慮到最好只顯示.tags中的函數(shù),我不需要顯示Text自帶的手動(dòng)補(bǔ)全函數(shù)(提取當(dāng)前頁(yè)面的變量和函數(shù)),所以我的返回結(jié)果如下:
return (results, sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS)
添加配置文件
考慮到插件的功能只能關(guān)閉,所以需要添加一個(gè)配置文件來(lái)指定不啟用插件功能的語(yǔ)言。 這里我參考“All”的代碼:
def plugin_loaded():
? ?global settings
? ?settings = sublime.load_settings('CTagsAutoComplete.sublime-settings')
def is_disabled_in(scope):
? ?excluded_scopes = settings.get("exclude_from_completion", [])
? ?for excluded_scope in excluded_scopes:
? ? ? ?if scope.find(excluded_scope) != -1:
? ? ? ? ? ?return True
? ?return False
if is_disabled_in(view.scope_name(locations[0])):
? ?return []
這里使用的配置文件需要添加到插件所在文件夾中,名稱(chēng)為.-,內(nèi)容為:
{
? ?// An array of syntax names to exclude from being autocompleted.
? ?"exclude_from_completion": [
? ? ? ?"css",
? ? ? ?"html"
? ?]
}
添加設(shè)置文件
有了配置文件,還需要在Text的“->”下添加相應(yīng)的設(shè)置,同樣放在插件所在文件夾下,名稱(chēng)為Main.-menu:
[
? ?{
? ? ? ?"caption": "Preferences",
? ? ? ?"mnemonic": "n",
? ? ? ?"id": "preferences",
? ? ? ?"children": [
? ? ? ? ? ?{
? ? ? ? ? ? ? ?"caption": "Package Settings",
? ? ? ? ? ? ? ?"mnemonic": "P",
? ? ? ? ? ? ? ?"id": "package-settings",
? ? ? ? ? ? ? ?"children": [
? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ?"caption": "CTagsAutoComplete",
? ? ? ? ? ? ? ? ? ? ? ?"children": [
? ? ? ? ? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"command": "open_file",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"args": {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"file": "${packages}/CTagsAutoComplete/CTagsAutoComplete.sublime-settings"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?},
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"caption": "Settings"
? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ?]
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?]
? ? ? ? ? ?}
? ? ? ?]
? ?}
]
總結(jié)
首先給出插件的完整源碼:
import sublime
import sublime_plugin
import os
import re
def plugin_loaded():
? ?global settings
? ?settings = sublime.load_settings('CTagsAutoComplete.sublime-settings')
class CTagsAutoComplete(sublime_plugin.EventListener):
? ?def on_query_completions(self, view, prefix, locations):
? ? ? ?if is_disabled_in(view.scope_name(locations[0])):
? ? ? ? ? ?return []
? ? ? ?results = []
? ? ? ?ctags_paths = [folder + '\\.tags' for folder in view.window().folders()]
? ? ? ?ctags_rows ?= []
? ? ? ?for ctags_path in ctags_paths:
? ? ? ? ? ?if not is_file_exist(view, ctags_path):
? ? ? ? ? ? ? ?return []
? ? ? ? ? ?ctags_path = str(ctags_path)
? ? ? ? ? ?ctags_file = open(ctags_path, encoding = 'utf-8')
? ? ? ? ? ?ctags_rows += ctags_file.readlines()
? ? ? ? ? ?ctags_file.close()
? ? ? ?for rows in ctags_rows:
? ? ? ? ? ?target = re.findall('^' + prefix + '.*', rows)
? ? ? ? ? ?if target:
? ? ? ? ? ? ? ?matched = re.split('\\t', str(target[0]))
? ? ? ? ? ? ? ?trigger = matched[0]
? ? ? ? ? ? ? ?trigger += '\\t(%s)' % 'CTags'
? ? ? ? ? ? ? ?contents = re.findall(prefix + '[0-9a-zA-Z_]*\\(.*\\)', str(matched[2]))
? ? ? ? ? ? ? ?if (len(matched) > 1 and contents):
? ? ? ? ? ? ? ? ? ?results.append((trigger, contents[0]))
? ? ? ? ? ? ? ? ? ?results = list(set(results))
? ? ? ? ? ? ? ? ? ?results.sort()
? ? ? ?return (results, sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS)
def is_disabled_in(scope):
? ?excluded_scopes = settings.get("exclude_from_completion", [])
? ?for excluded_scope in excluded_scopes:
? ? ? ?if scope.find(excluded_scope) != -1:
? ? ? ? ? ?return True
? ?return False
def is_file_exist(view, file):
? ?if (not view.window().folders() or not os.path.exists(file)):
? ? ? ?return False
? ?return True
plugin_loaded()
然后我會(huì)把這個(gè)插件集成起來(lái)并上傳到網(wǎng)站上,讓更多的人可以更方便的使用。 通過(guò)這個(gè)條目,我嘗到了甜頭。 在未來(lái)的發(fā)展過(guò)程中,可能會(huì)出現(xiàn)各種奇特的需求。 如果現(xiàn)有的插件無(wú)法提供幫助,那就自己動(dòng)手吧。
如有侵權(quán)請(qǐng)聯(lián)系刪除!
Copyright ? 2023 江蘇優(yōu)軟數(shù)字科技有限公司 All Rights Reserved.正版sublime text、Codejock、IntelliJ IDEA、sketch、Mestrenova、DNAstar服務(wù)提供商
13262879759
微信二維碼