VS Code エクスプローラーに右クリックして「複製」を表示させる拡張機能を追加する

VS Code標準のエクスプローラーでは、ファイルをコピー&ペーストすることはできますが、ワンアクションで「複製」を作ることができません。
そこで、ファイルやフォルダーを右クリックしてサクッと複製できるシンプルな自作拡張機能を作成しました。

今回は、この拡張機能をどのようなツールを使って、どんな仕組みで作ったのかの抜粋をご紹介します。

【実装時の注意点】
本記事では主要なロジックのみを掲載しており、拡張機能として動作させるためのpackage.jsonの初期設定や一部のヘルパー関数は省略しています。
実際に開発される際は、自作のプロジェクトテンプレートに記事内容を組み込んで不足分を実装いただくか、AIツール等に読み込ませて生成のヒントにしてください。

使用したツール・技術スタック

本拡張機能は、主に以下のツールと技術を使用して開発しています。

  • 言語: TypeScript
  • API: VS Code Extension API
  • 実行環境: Node.js
  • パッケージング: @vscode/vsce

型の恩恵を受けつつ安全に開発を進めるため、JavaScriptではなく**TypeScript**を採用しています(tsconfig.json を設定してビルドしています)。

拡張機能の仕組みとコード解説

この拡張機能は、大きく分けて「メニューへの表示」と「実際の複製処理」の2つの仕組みで動いています。

1. 右クリックメニューに「複製」を表示する仕組み

VS CodeのUIにメニューを追加するには、プログラム本体ではなく package.json の contributes フィールドに定義を記述します。

"contributes": {
  "commands": [
    {
      "command": "duplicateResource.duplicate",
      "title": "複製"
    }
  ],
  "menus": {
    "explorer/context": [
      {
        "command": "duplicateResource.duplicate",
        "when": "resourceScheme == file",
        "group": "2_workspace@20"
      }
    ]
  }
}

エクスプローラーのコンテキストメニュー(explorer/context)にコマンドを割り当てています。
"group": "2_workspace@20" と指定することで、標準の「切り取り」や「コピー」といったメニューに近い、自然な位置に「複製」を配置しています。

2. 複製先のファイル名を決定する仕組み (TypeScript)

ただコピーするだけでは同じ名前のファイルが存在してエラーになってしまうため、「既に同じ名前がある場合は連番を付ける」という仕組みを src/extension.ts で実装しています。

const COPY_SUFFIX = " copy";

// ユニークなファイルパスを取得する処理
async function getUniqueTargetUri(source: vscode.Uri, fileType: vscode.FileType): Promise<vscode.Uri> {
	const parent = vscode.Uri.file(path.dirname(source.fsPath));
	const { stem, ext } = splitNameParts(path.basename(source.fsPath), fileType);

	for (let index = 1; ; index += 1) {
		const suffix = index === 1 ? COPY_SUFFIX : `${COPY_SUFFIX} ${index}`;
		const candidate = vscode.Uri.joinPath(parent, `${stem}${suffix}${ext}`);
		if (!(await pathExists(candidate))) {
			return candidate; // 存在しないパスが見つかったら返す
		}
	}
}

元のファイル名から拡張子を分離し、ループ処理で copy, copy 2, copy 3 … と名前を変えながら vscode.workspace.fs.stat() を使ってファイルの存在確認を行っています。

3. 実際にファイルをコピーする仕組み

重複しないファイル名が決まったら、VS Code標準のファイルシステムAPIを使って複製を実行します。

async function duplicateUri(resource: vscode.Uri): Promise<vscode.Uri> {
	const sourceStat = await vscode.workspace.fs.stat(resource);
	const target = await getUniqueTargetUri(resource, sourceStat.type);
	
  // VS CodeのAPIを使ってファイルをコピー
	await vscode.workspace.fs.copy(resource, target, { overwrite: false });
	return target;
}

Node.js標準の fs モジュールを使うこともできますが、VS Codeの vscode.workspace.fs.copy を使うことで、リモートワークスペース(WSLやSSH接続先など)でも透過的に動作するというメリットがあります。

※複数ファイルの同時選択にも対応しており、選択されたすべてのパスに対して Promise.all で並列処理を行って一気に複製する工夫も入れています。

インストール・使い方について

この拡張機能は個人的なツールとして作成したため、Marketplaceには公開せず .vsix ファイルで直接インストールする方式をとっています。

  1. 拡張機能ビューを開く
  2. 右上の「…」から「Extensions: Install from VSIX…」を選ぶ
  3. 配布している vscode-duplicate-resource-0.1.0.vsix を選択する
【補足】ローカル運用時の誤公開対策
本拡張機能は個人利用を想定しているため、.vsix パッケージ化して運用する場合、誤って npm publish などを実行して外部レポジトリやnpm等へ公開されないよう、package.json 内に “private”: true を指定しています。

まとめ

VS Codeの拡張機能は、TypeScriptと公式APIを組み合わせることで、意外とシンプルなコードで普段のちょっとした不便を解消できます。皆さんも独自の拡張機能開発にチャレンジしてみてはいかがでしょうか。

CONTACT

webサイト制作、デザインに関するご相談、御見積のご依頼など、弊社へのお問い合わせはこちら