<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          “改造” VS Code 編輯器,一起寫個(gè)插件吧!

          共 12287字,需瀏覽 25分鐘

           ·

          2021-04-21 14:47

          作者:HelloGitHub-小夏

          作為一個(gè)靠代碼作為“生計(jì)”的開(kāi)發(fā)者,bug 寫的好不好,編輯器真的很重要!那么 Visual Studio Code 這個(gè)大名你肯定不會(huì)陌生。作為一個(gè)老厲害的編輯器,它的過(guò)人之處簡(jiǎn)單講講來(lái)說(shuō)有這么幾點(diǎn):

          • 首先,它的設(shè)計(jì)者是一個(gè)很有名的工程師:Eric Gamma。20年前,他是《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》的作者之一,這本書在開(kāi)發(fā)社區(qū)的地位被視為面向?qū)ο筌浖_(kāi)發(fā)的指路明燈(瞻望大佬)。

          • 其次,對(duì)于寫 JavaScript 的人來(lái)說(shuō),雖然市面上有很多大大小小不同的編輯器,比如 sublime、atom、webstorm 等等,VS Code 與他們區(qū)別在于他比 sublime 開(kāi)源,比 atom 更快,比 webstorm 更輕。

          一、介紹

          VS Code 全名 Visual Studio Code 是微軟開(kāi)源的一款編輯器,GitHub 上標(biāo)星 115k(11 萬(wàn))。它是基于 TypeScript 編寫,總計(jì)代碼數(shù)量在 30 萬(wàn)以上,大型知名開(kāi)源項(xiàng)目。

          項(xiàng)目地址:https://github.com/microsoft/vscode

          我們先來(lái)簡(jiǎn)單看一下它的產(chǎn)品定位吧~可以看到,項(xiàng)目作者對(duì)它的定位屬于輕量級(jí)的編輯器,所以要求它輕量、響應(yīng)速度快,適用于多種語(yǔ)言等等。VS Code 的編輯能力來(lái)自于一款同樣來(lái)自微軟叫做 monaco 的開(kāi)源 Web 編輯器,同時(shí)為了實(shí)現(xiàn)跨平臺(tái)的需求又引入了 Electron:一個(gè)使用 JavaScript,HTML 和 CSS 構(gòu)建跨平臺(tái)的桌面應(yīng)用程序。

          正因?yàn)橛辛饲宄亩ㄎ缓头较颍艜?huì)有了更加清晰的邊界。或許你很疑惑,他是怎么支持多種語(yǔ)言的又做到輕量級(jí)的?那我們不得不來(lái)看一下它的多進(jìn)程架構(gòu)。

          • VS Code 有一個(gè)主進(jìn)程入口,負(fù)責(zé)一些窗口管理、進(jìn)程間通信、自動(dòng)更新等全局任務(wù);
          • 渲染進(jìn)程,顧名思義負(fù)責(zé)一個(gè) Web 頁(yè)面的渲染;
          • 插件宿主進(jìn)程,每個(gè)插件的代碼都運(yùn)行在一個(gè)獨(dú)立且隔離的 Node 環(huán)境的宿主進(jìn)程中,插件無(wú)法訪問(wèn) UI;
          • Debug 進(jìn)程,用于調(diào)試;
          • 語(yǔ)言服務(wù),是一種重要的特殊拓展,可以為許多編程語(yǔ)言提供編輯體驗(yàn),還可以實(shí)現(xiàn) VS Code 支持的自動(dòng)補(bǔ)充,錯(cuò)誤檢查(診斷),跳轉(zhuǎn)到定義以及許多其他的語(yǔ)言功能。

          最核心的部分就是它的插件系統(tǒng),為編輯器的拓展帶來(lái)了更加個(gè)性化的開(kāi)源定制。只要你能找到強(qiáng)大的 VS Code 插件組合在一起,那你的編輯器一定是一個(gè)高級(jí)且高效率的工作好幫手。

          先來(lái)看一下,VS Code 大致有哪些可供我們拓展的能力。

          有沒(méi)有心癢癢地想自己動(dòng)手搞一個(gè) VS Code 插件?下面就帶大家做一個(gè)入門級(jí)的 VS Code 插件。

          二、環(huán)境準(zhǔn)備

          首先你搞個(gè) Node.js 和 Git。

          其次「全局(-g)」安裝 Yeoman(現(xiàn)代 Web 應(yīng)用程序腳手架工具)和 VS Code Extension Generator 這兩個(gè)官方指定的工具腳手架(生成 VS Code 插件項(xiàng)目的工具)。

          npm install -g yo generator-code

          當(dāng)你看到下面的信息就說(shuō)明安裝成功了:

          三、初始化項(xiàng)目結(jié)構(gòu)

          依賴環(huán)境搞好了,接下來(lái)就要用到 Yeoman 這個(gè)工具來(lái)幫我們快速創(chuàng)建項(xiàng)目結(jié)構(gòu)啦!可能有很多人對(duì)這個(gè)腳手架不熟悉,簡(jiǎn)單的說(shuō),Yeoman 是一個(gè)通用的腳手架系統(tǒng),它允許創(chuàng)建任何類型的應(yīng)用程序。你可以用它快速開(kāi)始新項(xiàng)目。所以不僅僅是 JavaScript 這個(gè)語(yǔ)言,Java,Python,C#等都可以用它來(lái)生成項(xiàng)目,只要有對(duì)應(yīng)的生成器就可以。那我們進(jìn)行下一步,在命令行中輸入 yo code

          讓我們來(lái)分析一下這幾個(gè)選項(xiàng)的意思,其實(shí)和字面意思一樣,從上到下:

          • 新的插件(Typescript)
          • 新的插件(JavaScript)
          • 新的主題顏色
          • 新的語(yǔ)言支持
          • 新的代碼片段
          • 新的鍵值綁定
          • 新的插件包
          • 新的語(yǔ)言包(本土化)

          你可以看到這個(gè)工具支持創(chuàng)建多種類型的項(xiàng)目,我們今天先從插件(Extension)入手,所以第一個(gè)和第二個(gè)的區(qū)別就是,你要是會(huì)用 TypeScript 就選第一個(gè),也是官方推薦的一個(gè);要是不想寫各種麻煩的類型定義和類型校驗(yàn),就選第二個(gè) JavaScript。這一次我們選 JavaScript 來(lái)做一個(gè)簡(jiǎn)單的入門, 隨后你會(huì)需要填寫一系列初始化的信息如下:

          注釋如下:

          • What type of extension do you want to create?(創(chuàng)建哪一種類型的擴(kuò)展?)
          • What's the name of your extension?(擴(kuò)展的名稱?應(yīng)該全部為小寫字母,沒(méi)有空格)
          • What's the identifier of your extension?(擴(kuò)展的標(biāo)示?)
          • What's the description of your extension?(擴(kuò)展的描述是什么?)
          • Initialize a git repository?(是否初始化 git 倉(cāng)庫(kù)?)
          • Which package manager to use? (因?yàn)槲覀冄b的是 npm,所以選 npm 就行了,如果你有 yarn,你也可以選 yarn)
          • 使用哪一種包管理器(來(lái)下載各種 npm 包)

          四、搞一個(gè)簡(jiǎn)單的 VS Code 插件

          前面的準(zhǔn)備的差不多啦!那我們就要開(kāi)始開(kāi)「綠皮小火車」啦。

          進(jìn)入剛創(chuàng)建的文件目錄 cd test-extension,文件目錄:

          或許你覺(jué)得文件目錄嘛,一看就知道了,不就是幾個(gè)配置信息或者項(xiàng)目說(shuō)明嘛,但是這里面的配置信息「非常重要」x3,重要到你可能少一個(gè)配置或者配置的不對(duì),功能就出不來(lái)。所以我們還是稍微花點(diǎn)筆墨聊聊這里的信息。

          首先你可以在 package.json 文件里面,看到自己在前一個(gè)步驟里面設(shè)置的各個(gè)值,配置內(nèi)的各個(gè)主要的含義如下,這里有個(gè)小點(diǎn)注意一下,如果你的 VS Code 比較舊,且更新不了最新的,你就把下面的 engines 設(shè)置的版本低一點(diǎn),比如我就改成了 ^1.52.0 確保一定能兼容目前的 VS Code 編輯器就可以 :

          {
            "name""test-extension"// 插件的名字
            "displayName""test-extension"// 在插件市場(chǎng)展示的名字
            "description""vscode extension sample"// 插件描述
            "version""0.0.1"// 插件版本
            "engines": { // 最低支持 vscode 的版本
              "vscode""^1.52.0"
            },
            "categories": [ // 插件的類別,用于在插件市場(chǎng)做區(qū)分
              "Other"
            ],
            "activationEvents": [ // 插件激活的事件列表,可以有多個(gè)觸發(fā)機(jī)制,所以是數(shù)組形式
              "onCommand:test-extension.helloWorld"
            ],
            "main""./extension.js"// 插件主入口
            "contributes": { // 貢獻(xiàn)點(diǎn),用于拓展插件功能的配置項(xiàng),這里不會(huì)細(xì)講,先用 command 舉例
              "commands": [
                {
                  "command""test-extension.helloWorld",
                  "title""Hello World"
                }
              ]
            },
            "scripts": {
              "lint""eslint .",
              "pretest""npm run lint",
              "test""node ./test/runTest.js"
            },
            "devDependencies": {
              "@types/vscode""^1.55.0",
              "@types/glob""^7.1.3",
              "@types/mocha""^8.0.4",
              "@types/node""^12.11.7",
              "eslint""^7.19.0",
              "glob""^7.1.6",
              "mocha""^8.2.1",
              "typescript""^4.1.3",
              "vscode-test""^1.5.0"
            }
          }

          熟悉了配置之后,我們?cè)賮?lái)看一下插件的入口文件 extsnsion.js ,里面主要有兩個(gè)主要的函數(shù),一個(gè)是 activate 表示激活插件時(shí)的處理,一般是注冊(cè)命令等一些初始化的操作;另一個(gè)是 deactivate ,表示插件失活的時(shí)候做的處理,其實(shí)聽(tīng)名字你也應(yīng)該有體感,這就是插件的生命周期里的兩個(gè)鉤子函數(shù)嘛。

          // 引了 vscode 這個(gè)模塊,這樣你就可以用它里面的很多很多功能啦
          const vscode = require('vscode');

          /**
           * @param {vscode.ExtensionContext} context
           */

          function activate(context{

            console.log('Congratulations, your extension "test-extension" is now active!');

            let disposable = vscode.commands.registerCommand('test-extension.helloWorld'function ({
              vscode.window.showInformationMessage('Hello World from test-extension!');
            });

            context.subscriptions.push(disposable);
          }

          function deactivate({}

          module.exports = {
            activate,
            deactivate
          }

          我們來(lái)分析一下上面這段代碼,你可以看到里面 registerComman 了一個(gè)命令,是不是有種似曾相識(shí)的感覺(jué)?沒(méi)錯(cuò),就是上面在 package.json 里面有提到的那個(gè) command,讓我們摘出來(lái)一起看看:

          ...,
           // package.json
           "contributes": { // 貢獻(xiàn)點(diǎn),用于拓展插件功能的配置項(xiàng),這里不會(huì)細(xì)講,先用 command 舉例
              "commands": [
                {
                  "command""test-extension.helloWorld",
                  "title""Hello World"
                }
              ]
            },
          ...
          ...
          // extension.js
          function activate(context{
            console.log('Congratulations, your extension "test-extension" is now active!');

            let disposable = vscode.commands.registerCommand('test-extension.helloWorld'function ({
              vscode.window.showInformationMessage('Hello World from test-extension!');
            });

            context.subscriptions.push(disposable);
          }
          ...

          這樣看起來(lái)是不是很直觀了?在 package.json 里面設(shè)置的 command 的值,就是 extension.js 里面 registerCommand 的值。那這幾行命令是什么意思呢?讓我們一起來(lái)運(yùn)行看看:

          他會(huì)幫你打開(kāi)一個(gè)新的 VS Code 編輯器,插件只會(huì)加載到這個(gè)編輯器中。現(xiàn)在我們使用調(diào)用快捷鍵(MacOS) command+p ,輸入 >Hello World (不區(qū)分大小寫):

          回車一下,你會(huì)發(fā)現(xiàn)在右下角一個(gè)不起眼的角落里輸出了這么一個(gè)提示:

          我相信聰明的你們結(jié)合代碼一定已經(jīng)恍然大悟了對(duì)不對(duì)!不知道你們有沒(méi)有這個(gè)疑問(wèn),上面那個(gè) console.log 去哪里看?別急,我們回到插件代碼的那個(gè)編輯器中,仔細(xì)看下面這邊,他會(huì)在我們輸入上面的命令之后才出現(xiàn),因?yàn)樵?package.json 里面我們配置插件的激活時(shí)機(jī)就是 onCommand:test-extension.helloWorld

          那我們現(xiàn)在抱著「刻意學(xué)習(xí)」的思路,改一下上面的代碼,比如把 test-extension 改成 test

          ...,
          // package.json
          "activationEvents": [
              "onCommand:test.helloWorld"
          ],
          ...,
          "contributes": {
            "commands": [
              {
                "command""test.helloWorld",
                "title""Hello World"
              }
            ]
          },
          ...
          // extension.js
          ...
          function activate(context) {

            console.log('我在這里!!');

            let disposable = vscode.commands.registerCommand('test.helloWorld'function ({
              vscode.window.showInformationMessage('我改變了 command 的名字!');
            });

            context.subscriptions.push(disposable);
          }
          ...

          再按照上面說(shuō)的觸發(fā)方法再來(lái)一遍,發(fā)現(xiàn)依舊是可以的!所以這里的名字只是一個(gè)命名空間,你可以改成你想要的任何名字,來(lái)適用于比較復(fù)雜的插件體系。既然是個(gè)命名空間,那其實(shí)不要這個(gè)前綴也可以。

          五、實(shí)現(xiàn)一個(gè)屬于自己的插件

          前面介紹了那么多,大家有沒(méi)有發(fā)現(xiàn)其實(shí)這個(gè)體系也不難,有大佬在前面鋪路,其實(shí)我們只要按照規(guī)則“填空”就好了,那現(xiàn)在我們就來(lái)實(shí)現(xiàn)一個(gè)小小的功能——加一個(gè)按鈕和他的點(diǎn)擊事件。

          修改我們的 package.json 如下,因?yàn)楫?dāng)前我希望插件加載的時(shí)候就已經(jīng)訂閱了按鈕的點(diǎn)擊事件,所以這里我們可以把 activationEvents 改成 *,這樣的話我們的插件在一開(kāi)始就可以激活并注冊(cè)事件了:

          ...,
          "activationEvents": [
                  "*",
          ],
          "contributes": {
            "commands": [
              {
                "command""test.helloWorld",
                "title""Hello World"
              },
              // 注冊(cè)一下按鈕點(diǎn)擊的事件,再配一個(gè)小圖標(biāo)
              {
                "command""test.button",
                "title""按鈕",
                "icon": {
                  "light""./media/light/preview.svg",
                  "dark""./media/dark/preview.svg"
                }
              }
            ],
            // 在這里加一下下面這個(gè)配置
            "menus": {
              "editor/title": [
                {
                  "command""test.button",
                  "group""navigation"
                }
              ]
            }
          },
          ...

          然后回到我們的 extension.js 里面增加一個(gè)簡(jiǎn)單的消息提醒:

          function activate(context{
            console.log('我在這里!!');
            let disposable = vscode.commands.registerCommand('test.helloWorld'function ({
              vscode.window.showInformationMessage('我改變了 command 的名字!');
            });
            // 新增一個(gè)按鈕的點(diǎn)擊命令操作內(nèi)容
            let button = vscode.commands.registerCommand('test.button'function ({
              vscode.window.showInformationMessage('按鈕點(diǎn)擊');
            });
            // 記得這個(gè)新的命令也要放進(jìn)去訂閱一下
            context.subscriptions.push(disposable, button);
          }

          看一下效果:

          是不是很簡(jiǎn)單的就自定義了 VS Code 的樣式?那我們現(xiàn)在就來(lái)分析一下我們上面做的事情。首先,我們修改了 package.json 里的配置,增加了一個(gè) menus ,這個(gè) menus 是什么呢?答案是菜單。菜單項(xiàng)定義包含選擇時(shí)應(yīng)調(diào)用的命令以及該項(xiàng)應(yīng)顯示的條件(when),所以你也可以給這個(gè)菜單項(xiàng)顯示加個(gè)顯示的邏輯,比如我們規(guī)定在打開(kāi) javascript 文件時(shí)才顯示這個(gè)按鈕:

          {
            "contributes": {
              "menus": {
                "editor/title": [
                  {
                    "when""resourceLangId == javascript",
                    "command""test.button",
                    "group""navigation"
                  }
                ]
              }
            }
          }

          group 的含義呢,是用來(lái)定義菜單項(xiàng)的排序和分組的。來(lái)自官網(wǎng)的一個(gè)圖,表示不同的 group 之間存在的順序關(guān)系,當(dāng)然這個(gè)菜單不是上面我們寫的那個(gè),而是 editor/context ,所以不同的菜單之間的 group 其實(shí)是有細(xì)微差別的,但是大體都差不多,而 navigation 的顯示優(yōu)先級(jí)是最高的:

          我們也可以加一個(gè)這個(gè)看看:

          "menus": {
            "editor/title": [
              {
                "command""test.button",
                "group""navigation",
                "when""resourceLangId == javascript"
              }
            ],
              "editor/context": [
                {
                  "command""test.button",
                  "group""navigation",
                  "when""resourceLangId == javascript"
                }
              ]
          }

          效果是一樣的:

          如果你好奇還有哪些菜單,我這里簡(jiǎn)單整理「翻譯」了一下官網(wǎng)的內(nèi)容(僅常見(jiàn)菜單非全部):

          配置菜單項(xiàng)的名稱菜單位置
          commandPalette全局命令面板
          explorer/context資源管理器上下文菜單
          editor/context編輯器右鍵上下文菜單
          editor/title編輯器標(biāo)題欄,不配置圖片就顯示文字
          editor/title/context編輯器標(biāo)題右鍵上下文菜單
          debug/callstack/context調(diào)試棧視圖的上下文菜單
          debug/toolbar調(diào)試工具欄
          scm/titleSCM 標(biāo)題菜單
          view/title看標(biāo)題菜單
          touchBarmacOS 觸摸欄
          timeline/title時(shí)間軸視圖標(biāo)題菜單欄
          extension/context擴(kuò)展程序視圖上下文菜單

          六、做個(gè)總結(jié)

          從上面的簡(jiǎn)單例子可以看出,VS Code 不僅可以支持我們自定義想要的命令,也允許我們?cè)凇赶薅ǚ秶鷥?nèi)」對(duì)編輯器進(jìn)行個(gè)性化的拓展。為什么說(shuō)是限定范圍呢?因?yàn)榘垂倬W(wǎng)的話來(lái)說(shuō),目前插件體系有下面這些局限性:

          插件不具備訪問(wèn) VS Code UI 的 DOM 的能力。所以不能將自定義的 CSS 應(yīng)用于 VS Code 或?qū)?HTML 元素添加到 VS Code UI 的擴(kuò)展中去。這樣的限制在于:

          • 確保用戶的操作在可控范圍內(nèi),保證操作的一致性
          • 防止因?yàn)榈讓?Web 技術(shù)的更迭導(dǎo)致對(duì)一些已存在的插件會(huì)有影響
          • 保證開(kāi)發(fā)人員可以繼續(xù)在原有插件基礎(chǔ)上進(jìn)行一如往常的迭代,而不用再去打破原有的規(guī)則重新學(xué)習(xí)

          其實(shí)我們今天的內(nèi)容只是工作區(qū)拓展很小一部分內(nèi)容,要學(xué)習(xí)這個(gè)龐大的體系,還是要不斷的努力學(xué)習(xí)呀!下一次,我們來(lái)走進(jìn)「聲明類語(yǔ)言特性」,想知道編輯器里的自動(dòng)提示和補(bǔ)全是怎么做到的嘛?

          ??「點(diǎn)擊關(guān)注」更多驚喜等待你!


          瀏覽 94
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产操比视频 | 99曰高清热视频 | 黄片视频在线免费观看 | 精品人妻一区二区乱码 | 久久精品大香蕉 |