VSCode 擴展入門,類型轉換代碼補全的實現(完整版)

項目組使用了 protobuf 作爲數據協議,其好處不用多說。可是由於 go 默認數字類型是 int,且 go 屬於強類型語言,切換類型就成了家常便飯。

一般來說,切換類型的步驟包括:

  1. 選中數字部分。
  2. 加括號。
  3. 輸入新類型。

時間長了,不免覺得有些複雜。

vscode + gopls 沒有對後綴代碼補全的支持,需要通過擴展支持。詳見 gopls 官方 issue

已有的擴展 https://github.com/yokoe/vscode-postfix-go 是一個接近的選擇,支持 len 這類表達。

可惜該擴展沒有提供數值轉換相關的支持。

在 issue 提出建議沒有收到迴應後,我決定在他的基礎進行補充,畢竟兩種表達相差不多。

Fork

首先將原項目 fork 出來,對作者信息以及許可證進行修改。在這個過程中我發現它也是在別人的基礎上 fork 而來的,感謝開源精神。

npm

vscode 擴展是通過 ts/js 實現的,自然少不了 npm 的使用。在 sudo pacman -S npm 安裝好 npm 後(筆者爲 arch 發行版)。

然後在項目目錄使用 sudo npm install 安裝工程。

 ~/code/vscode-postfix-go (master) [05:14:53]
p1gd0g$sudo npm install

> [email protected] postinstall
> node ./node_modules/vscode/bin/install

Detected VS Code engine version: ^1.12.0
Found minimal version that qualifies engine range: 1.12.0
Fetching vscode.d.ts from: https://raw.githubusercontent.com/Microsoft/vscode/72672be0b7d3eef0784077b880615f91b7ec85aa/src/vs/vscode.d.ts
vscode.d.ts successfully installed!

Coding

在該項目中很容易就可以找到對應後綴代碼補全的代碼。

比如 len 後綴的實現:

export class LenTemplate extends BaseExpressionTemplate {
  buildCompletionItem (code: string, position: vsc.Position) {
    const dotIdx = code.lastIndexOf('.', position.character)
    const codeBeforeDot = code.substr(0, dotIdx)
	// 找到 "." 前的最後一個單詞/部分
    let lastComponent = getLastComponent(codeBeforeDot)

    let builder = CompletionItemBuilder
      .create('len', lastComponent)
      .description(`len(expr)`)
	// 插入 len(*)
    builder.insertText('len(' + lastComponent + ')')
	// 刪除原字符
    builder.deleteTextBeforeCursor(position, lastComponent.length + 1)

    return builder.build()
  }
}
export const build = () => new LenTemplate()

和 type 的實現:

export class TypeTemplate extends BaseExpressionTemplate {
  constructor (private keyword: string) {
    super()
  }

  buildCompletionItem (code: string, position: vsc.Position) {
    return CompletionItemBuilder
      .create(this.keyword, code)
      .description(`type expr ${this.keyword}`)
      .replace(`type {{expr}} ${this.keyword} {\n${getIndentCharacters()}\${0}\n}`, position, true)
      .build()
  }
}
// 我們需要了解的重點在這裏,複用同一個邏輯去實現不同的代碼補全
export const build = () => [
	new TypeTemplate('struct'),
	new TypeTemplate('interface')
]

我們要做的就是將兩者結合起來。我想即使是沒有接觸 js/ts 的同學,只要有一定的編程基礎,不難完成這一目標。

export class IntTemplate extends BaseExpressionTemplate {
  constructor(private keyword: string) {
    super()
  }

  buildCompletionItem(code: string, position: vsc.Position) {
    const dotIdx = code.lastIndexOf('.', position.character)
    const codeBeforeDot = code.substr(0, dotIdx)
    let lastComponent = getLastComponent(codeBeforeDot)

    let builder = CompletionItemBuilder
      .create(this.keyword, lastComponent)
      .description(this.keyword + '(expr)')
	// 這裏借鑑 len
    builder.insertText(this.keyword + '(' + lastComponent + ')')
    builder.deleteTextBeforeCursor(position, lastComponent.length + 1)

    return builder.build()
  }
}
// 這裏借鑑 type
export const build = () => [
	new TypeTemplate('int64'),
	new TypeTemplate('uint32'),
	new TypeTemplate('int')
]

Debug

通過 vscode 自帶的調試,就可以看到我們想要的結果。

Package & Publish

打包和發佈的流程請參考官方文檔。https://code.visualstudio.com/api/working-with-extensions/publishing-extension

發佈成功後即可在 vscode 擴展上商店中看到我們自己的擴展。

以上內容不限於 go 語言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章