国产精品高清一区二区三区不卡-国产精品一区二区三区免费视频-日韩免费高清一级毛片-亚洲欧美一区二区三区国产精品-日韩欧美一区二区三区不卡视频-亚欧免费视频一区二区三区-亚洲欧美日韩一区成人-欧美日韩视频综合一区无弹窗-精品日韩在线视频一区二区三区-国内精品视频一区二区三区

你好,歡迎進(jìn)入江蘇優(yōu)軟數(shù)字科技有限公司官網(wǎng)!

誠(chéng)信、勤奮、創(chuàng)新、卓越

友好定價(jià)、專(zhuān)業(yè)客服支持、正版軟件一站式服務(wù)提供

13262879759

工作日:9:00-22:00

利用 CTags 開(kāi)發(fā)一個(gè) Sublime Text 代碼補(bǔ)完插件

發(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è)基本的插件文檔:

  1. import sublime

  2. import sublime_plugin

  3. class ExampleCommand(sublime_plugin.TextCommand):

  4. ? ?def run(self, edit):

  5. ? ? ? ?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í)行的命令。 然后把剛才的代碼改一下:

  1. import sublime

  2. import sublime_plugin

  3. class CTagsAutoComplete(sublime_plugin.EventListener):

  4. ? ?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ǔ)全功能

sublime text 安裝插件

讀取CTags文件

為了讀取.tag文件,首先要判斷當(dāng)前項(xiàng)目是否打開(kāi)以及.tag文件是否存在,然后讀取.tag文件中的所有內(nèi)容:

  1. import sublime

  2. import sublime_plugin

  3. import os

  4. import re

  5. class CTagsAutoComplete(sublime_plugin.EventListener):

  6. ? ?def on_query_completions(self, view, prefix, locations):

  7. ? ? ? ?results = []

  8. ? ? ? ?ctags_paths = [folder + '\\.tags' for folder in view.window().folders()]

  9. ? ? ? ?ctags_rows ?= []

  10. ? ? ? ?for ctags_path in ctags_paths:

  11. ? ? ? ? ? ?if not is_file_exist(view, ctags_path):

  12. ? ? ? ? ? ? ? ?return []

  13. ? ? ? ? ? ?ctags_path = str(ctags_path)

  14. ? ? ? ? ? ?ctags_file = open(ctags_path, encoding = 'utf-8')

  15. ? ? ? ? ? ?ctags_rows += ctags_file.readlines()

  16. ? ? ? ? ? ?ctags_file.close()

  17. def is_file_exist(view, file):

  18. ? ?if (not view.window().folders() or not os.path.exists(file)):

  19. ? ? ? ?return False

  20. ? ?return True

通過(guò)以上操作,可以讀取當(dāng)前項(xiàng)目下所有.tag文件的內(nèi)容。

分析 CTags 文件

第一個(gè)是獲取 .tags 文件中包含的行:

  1. for rows in ctags_rows:

  2. ? ?target = re.findall('^' + prefix + '.*', rows)

一旦找到,該行數(shù)據(jù)就會(huì)通過(guò)正則表達(dá)式進(jìn)行處理:

  1. if target:

  2. ? ?matched = re.split('\\t', str(target[0]))

  3. ? ?trigger = matched[0] # 返回的第一個(gè)參數(shù),函數(shù)名稱(chēng)

  4. ? ?trigger += '\\t(%s)' % 'CTags' # 給函數(shù)名稱(chēng)后加上標(biāo)識(shí) 'CTags'

  5. ? ?contents = re.findall(prefix + '[0-9a-zA-Z_]*\\(.*\\)', str(matched[2])) # 返回的第二個(gè)參數(shù),函數(shù)的具體定義

  6. ? ?if (len(matched) > 1 and contents):

  7. ? ? ? ?results.append((trigger, contents[0]))

  8. ? ? ? ?results = list(set(results)) # 去除重復(fù)的函數(shù)

  9. ? ? ? ?results.sort() # 排序

處理完成后即可返回。 考慮到最好只顯示.tags中的函數(shù),我不需要顯示Text自帶的手動(dòng)補(bǔ)全函數(shù)(提取當(dāng)前頁(yè)面的變量和函數(shù)),所以我的返回結(jié)果如下:

  1. return (results, sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS)

添加配置文件

考慮到插件的功能只能關(guān)閉,所以需要添加一個(gè)配置文件來(lái)指定不啟用插件功能的語(yǔ)言。 這里我參考“All”的代碼:

  1. def plugin_loaded():

  2. ? ?global settings

  3. ? ?settings = sublime.load_settings('CTagsAutoComplete.sublime-settings')

  4. def is_disabled_in(scope):

  5. ? ?excluded_scopes = settings.get("exclude_from_completion", [])

  6. ? ?for excluded_scope in excluded_scopes:

  7. ? ? ? ?if scope.find(excluded_scope) != -1:

  8. ? ? ? ? ? ?return True

  9. ? ?return False

  10. if is_disabled_in(view.scope_name(locations[0])):

  11. ? ?return []

這里使用的配置文件需要添加到插件所在文件夾中,名稱(chēng)為.-,內(nèi)容為:

  1. {

  2. ? ?// An array of syntax names to exclude from being autocompleted.

  3. ? ?"exclude_from_completion": [

  4. ? ? ? ?"css",

  5. ? ? ? ?"html"

  6. ? ?]

  7. }

添加設(shè)置文件

有了配置文件,還需要在Text的“->”下添加相應(yīng)的設(shè)置,同樣放在插件所在文件夾下,名稱(chēng)為Main.-menu:

  1. [

  2. ? ?{

  3. ? ? ? ?"caption": "Preferences",

  4. ? ? ? ?"mnemonic": "n",

  5. ? ? ? ?"id": "preferences",

  6. ? ? ? ?"children": [

  7. ? ? ? ? ? ?{

  8. ? ? ? ? ? ? ? ?"caption": "Package Settings",

  9. ? ? ? ? ? ? ? ?"mnemonic": "P",

  10. ? ? ? ? ? ? ? ?"id": "package-settings",

  11. ? ? ? ? ? ? ? ?"children": [

  12. ? ? ? ? ? ? ? ? ? ?{

  13. ? ? ? ? ? ? ? ? ? ? ? ?"caption": "CTagsAutoComplete",

  14. ? ? ? ? ? ? ? ? ? ? ? ?"children": [

  15. ? ? ? ? ? ? ? ? ? ? ? ? ? ?{

  16. ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"command": "open_file",

  17. ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"args": {

  18. ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"file": "${packages}/CTagsAutoComplete/CTagsAutoComplete.sublime-settings"

  19. ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?},

  20. ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"caption": "Settings"

  21. ? ? ? ? ? ? ? ? ? ? ? ? ? ?}

  22. ? ? ? ? ? ? ? ? ? ? ? ?]

  23. ? ? ? ? ? ? ? ? ? ?}

  24. ? ? ? ? ? ? ? ?]

  25. ? ? ? ? ? ?}

  26. ? ? ? ?]

  27. ? ?}

  28. ]

總結(jié)

首先給出插件的完整源碼:

  1. import sublime

  2. import sublime_plugin

  3. import os

  4. import re

  5. def plugin_loaded():

  6. ? ?global settings

  7. ? ?settings = sublime.load_settings('CTagsAutoComplete.sublime-settings')

  8. class CTagsAutoComplete(sublime_plugin.EventListener):

  9. ? ?def on_query_completions(self, view, prefix, locations):

  10. ? ? ? ?if is_disabled_in(view.scope_name(locations[0])):

  11. ? ? ? ? ? ?return []

  12. ? ? ? ?results = []

  13. ? ? ? ?ctags_paths = [folder + '\\.tags' for folder in view.window().folders()]

  14. ? ? ? ?ctags_rows ?= []

  15. ? ? ? ?for ctags_path in ctags_paths:

  16. ? ? ? ? ? ?if not is_file_exist(view, ctags_path):

  17. ? ? ? ? ? ? ? ?return []

  18. ? ? ? ? ? ?ctags_path = str(ctags_path)

  19. ? ? ? ? ? ?ctags_file = open(ctags_path, encoding = 'utf-8')

  20. ? ? ? ? ? ?ctags_rows += ctags_file.readlines()

  21. ? ? ? ? ? ?ctags_file.close()

  22. ? ? ? ?for rows in ctags_rows:

  23. ? ? ? ? ? ?target = re.findall('^' + prefix + '.*', rows)

  24. ? ? ? ? ? ?if target:

  25. ? ? ? ? ? ? ? ?matched = re.split('\\t', str(target[0]))

  26. ? ? ? ? ? ? ? ?trigger = matched[0]

  27. ? ? ? ? ? ? ? ?trigger += '\\t(%s)' % 'CTags'

  28. ? ? ? ? ? ? ? ?contents = re.findall(prefix + '[0-9a-zA-Z_]*\\(.*\\)', str(matched[2]))

  29. ? ? ? ? ? ? ? ?if (len(matched) > 1 and contents):

  30. ? ? ? ? ? ? ? ? ? ?results.append((trigger, contents[0]))

  31. ? ? ? ? ? ? ? ? ? ?results = list(set(results))

  32. ? ? ? ? ? ? ? ? ? ?results.sort()

  33. ? ? ? ?return (results, sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS)

  34. def is_disabled_in(scope):

  35. ? ?excluded_scopes = settings.get("exclude_from_completion", [])

  36. ? ?for excluded_scope in excluded_scopes:

  37. ? ? ? ?if scope.find(excluded_scope) != -1:

  38. ? ? ? ? ? ?return True

  39. ? ?return False

  40. def is_file_exist(view, file):

  41. ? ?if (not view.window().folders() or not os.path.exists(file)):

  42. ? ? ? ?return False

  43. ? ?return True

  44. 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)系刪除!

13262879759

微信二維碼