🧞

vscodeの拡張機能で右クリックメニューを増やして見る

2023/12/19に公開

これは CureApp Advent Calendar 2023 19日目の記事です。

はじめに

弊社kexiさんがvscodeの拡張機能の作り方を紹介してくれたので、せっかくなら実際の作成例を作れたらと思い記事にしました。

環境構築

kexiさんの記事を参考に開発環境を作ります

仕様

  • vscodeから自分のslackチャンネルへ通知を出したい
  • slackへの通知は右クリックメニューから行いたい
  • 選択した文のみ送信したい
  • slack URLは設定から変更したい

実際できたコード

以下2ファイルのみの変更で出来る

ソースコード
extension.ts
import vscode from "vscode";
import axios from "axios";

export function activate(context: vscode.ExtensionContext) {
  const cmd = vscode.commands.registerCommand(
    "vscode.contextmenu.sendslack",
    () => {
      //アクティブなエディタのドキュメントを取得
      const activeEditor = vscode.window.activeTextEditor;
      const doc = activeEditor && activeEditor.document;
      //選択範囲を取得
      const ref = activeEditor?.selection;
      sendSlack(doc?.getText(ref));
    }
  );

  context.subscriptions.push(cmd);
}

function sendSlack(message?: string) {
  const slackWebhookUrl = vscode.workspace
    .getConfiguration("sendslack")
    .get("sendSlackURL", "");
  axios.post(
    slackWebhookUrl,
    {
      username: "VSCode",
      icon_emoji: ":ghost:",
      text: message,
    },
    {
      headers: {
        "Content-Type": "application/json",
      },
    }
  );
}

export function deactivate() {}
package.json
{
  "name": "sendslack",
  "displayName": "sendslack",
  "description": "検索窓を増やします。ただそれだけ",
  "version": "0.0.1",
  "engines": {
    "vscode": "^1.84.0"
  },
  "categories": [
    "Other"
  ],
  "main": "./dist/extension.js",
  "activationEvents": [
    "onStartupFinished"
  ],
  "contributes": {
    "configuration": {
      "title": "sendslack",
      "properties": {
        "sendslack.sendSlackURL": {
          "type": "string",
          "default": "https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
          "description": "%configuration.sendSlackURL.description%"
        }
      }
    },
    "commands": [
      {
        "command": "vscode.contextmenu.sendslack",
        "title": "選択した文字をslackに送信します"
      }
    ],
    "menus": {
      "editor/context": [
        {
          "when": "editorFocus",
          "command": "vscode.contextmenu.sendslack",
          "group": "myGroup@1"
        }
      ]
    }
  },
  "scripts": {
    "vscode:prepublish": "npm run package",
    "compile": "webpack",
    "watch": "webpack --watch",
    "package": "webpack --mode production --devtool hidden-source-map",
    "compile-tests": "tsc -p . --outDir out",
    "watch-tests": "tsc -p . -w --outDir out",
    "pretest": "npm run compile-tests && npm run compile && npm run lint",
    "lint": "eslint src --ext ts",
    "test": "vscode-test"
  },
  "devDependencies": {
    "@types/mocha": "^10.0.6",
    "@types/node": "18.x",
    "@types/vscode": "^1.84.0",
    "@typescript-eslint/eslint-plugin": "^6.13.1",
    "@typescript-eslint/parser": "^6.13.1",
    "@vscode/test-cli": "^0.0.4",
    "@vscode/test-electron": "^2.3.8",
    "eslint": "^8.54.0",
    "ts-loader": "^9.5.1",
    "typescript": "^5.3.2",
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4"
  },
  "dependencies": {
    "axios": "^1.6.2"
  }
}

使い方

  • vscodeの設定に通知を出したいslackのhooks URLを登録する
    (hooks URLの取得方法はこちらを参考に取得)

  • vscodeのエディター上で送信したい文を選択し右クリック

  • slackに無事通知成功

解説

package.json

作った拡張機能を有効にするトリガー設定

package.json
  "activationEvents": [
    "onStartupFinished"
  ],

設定からhooks URLを読み込ませたいので設定項目を追加

package.json
  "contributes": {
    "configuration": {
      "title": "sendslack",
      "properties": {
        "sendslack.sendSlackURL": {
          "type": "string",
          "default": "https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
          "description": "%configuration.sendSlackURL.description%"
        }
      }
    },

説明を追加したい場合はdescriptionの項目に%configuration.sendSlackURL.description%と入力する。
package.nls.jsonというファイルに以下のように設定できる。
要らなければdescriptionに直接書くでもいいらしい(多言語対応する時に必要っぽい)

package.nls.json
{
  "configuration.sendSlackURL.description": "slack send hooks URL."
}

右クリックメニューに追加する設定を書く

package.json
  "contributes": {
---略ーー
    "commands": [
      {
        "command": "vscode.contextmenu.sendslack",
        "title": "選択した文字をslackに送信します"
      }
    ],
    "menus": {
      "editor/context": [
        {
          "when": "editorFocus",
          "command": "vscode.contextmenu.sendslack",
          "group": "myGroup@1"
        }
      ]
    }

"command"は同じ文字列vscode.contextmenuから始まる拡張機能名を入れる(これはあとでextension.tsでも記述する箇所がある)
"group":"myGroup@1"はメニューのどこに表示するかの記述

extension.ts

slackに通知させる処理

今回はaxiosを使う。

コマンドの登録と中身

extension.ts
  const cmd = vscode.commands.registerCommand(
    "vscode.contextmenu.sendslack",
    () => {
      //アクティブなエディタのドキュメントを取得
      const activeEditor = vscode.window.activeTextEditor;
      const doc = activeEditor && activeEditor.document;
      //選択範囲を取得
      const ref = activeEditor?.selection;
      sendSlack(doc?.getText(ref));
    }
  );

vscode.commands.registerCommand()の第一引数にpackage.jsonでも記述したcommand名を入れる。第二引数が発火した時に実行される処理
activeEditor?.selection+getText()で選択した文字列のみ取得できる

終わりに

ハマりどころはpackage.jsonの記述方法だと思いました
親子の設定を間違えないこと、"command"は各プロパティで共通のものを設定すること
この辺注意が必要だと思います

ちなみに他の方の記事でも見かけたのですが、youtubeを埋め込むとかgoogleカレンダーを表示するとかいった類はできないようでした。(要webviewにiframe読み込みさせるような構成)
残念!!

CureApp テックブログ

Discussion