Zenn

ファイルを結合コピーできる Visual Studio Code 拡張機能 UniCopy を作った話

2025/03/29に公開

UniCopy Visual Studio Code 拡張を開発した話

kohe です。
Visual Studio Code 向けに拡張機能 UniCopy を開発した。
簡単にいうとフォルダ内のファイルもしくは開いているタブのファイルを結合してクリップボードに貼り付けることができる。

https://marketplace.visualstudio.com/items/?itemName=0xkohe.uni-copy
https://github.com/0xkohe/uni-copy-vscode-extention

UIプレビュー

開発中、「このフォルダ内のファイルをすべてまとめてコピーしたい」「今開いているタブのコードを一括でAIに渡したい」とめちゃくちゃ感じていた。UniCopy は、そのための拡張機能である。

Cline、Roo-CodeやGitHub Copilot Agentも良いのだが、やはりコスパの最強を目指したい。
せっかくサブスク課金をしているClaudeやChatGPTをもっと使ってコストを抑えまくりたいという欲求があった。
(GitHub Copilot Agentをメインで使っているが、レートリミットが結構くるので、その間はこの機能で代替している)
※Sonnet 3.7良いんですけど、Roo-Codeの場合は高い、GitHub Copilot Agentの場合は若干遅い&レートリミット結構早く来るという課題感 ※2025/03/27


機能概要

以下の2つの機能を提供する。

  • 📁 フォルダの内容を一括コピー
    • 再帰コピーの有無を選択可能
    • ファイルごとに区切り(ヘッダー)を付加
  • 📑 開いているすべてのタブを一括コピー
    • 重複を排除し、ファイル名付きで整形

どちらの機能も、テキストとしてクリップボードにコピーされる。


コアコードの構造

開いているタブの内容を結合してコピーする例

const unifiedCopyTabsCommand = vscode.commands.registerCommand('extension.unifiedCopyTabs', async () => {
  let combinedText = '';
  const tabGroups = vscode.window.tabGroups.all;
  const docPromises: Thenable<vscode.TextDocument>[] = [];

  for (const group of tabGroups) {
    for (const tab of group.tabs) {
      const input = tab.input as any;
      if (input && input.uri) {
        docPromises.push(vscode.workspace.openTextDocument(input.uri));
      }
    }
  }

  const docs = await Promise.all(docPromises);
  const seen = new Set<string>();
  const uniqueDocs = docs.filter(doc => {
    const key = doc.uri.toString();
    if (seen.has(key)) return false;
    seen.add(key);
    return true;
  });

  for (const doc of uniqueDocs) {
    const baseName = path.basename(doc.fileName || 'Untitled');
    combinedText += `=== ${baseName} ===\n${doc.getText()}\n\n`;
  }

  await vscode.env.clipboard.writeText(combinedText);
});

この関数では、開いている全タブを対象に重複を除外しながら内容を結合し、ファイル名ごとに明示的な区切りを付与している。


フォルダコピー機能(再帰あり)

async function processFiles(uri: vscode.Uri, isRecursive: boolean) {
  let combinedText = '';
  let fileCount = 0;
  const maxFiles = 30;

  async function readFiles(folder: vscode.Uri) {
    const entries = await vscode.workspace.fs.readDirectory(folder);
    for (const [name, type] of entries) {
      if (fileCount >= maxFiles) return;
      const entryUri = vscode.Uri.joinPath(folder, name);
      if (type === vscode.FileType.File) {
        const fileContentBytes = await vscode.workspace.fs.readFile(entryUri);
        const fileContent = new TextDecoder('utf-8').decode(fileContentBytes);
        combinedText += `=== ${name} ===\n${fileContent}\n\n`;
        fileCount++;
      } else if (type === vscode.FileType.Directory && isRecursive) {
        await readFiles(entryUri);
      }
    }
  }

  await readFiles(uri);
  await vscode.env.clipboard.writeText(combinedText);
}

上記により、サブディレクトリを含めたフォルダ内の最大30ファイルを対象とし、ファイル名込で内容を結合する。


ユースケース

UniCopy は、以下のような場面で活用できる。

  • コード全体の構造をAIに伝えたい場合
  • ファイルを跨いだ質問やレビューを効率化したい場合
  • 一時的にコードを共有・抜粋したい場合

特に、AIと対話する前段階で「文脈を整える」作業を効率化できる点において、本拡張は効果を発揮する。


終わりに

最近の開発はVisual Studio Codeの 左にRoo-Code(DeepSeek-V3-0324,Gemini Pro 2.5)、右にGitHub Copilot Agent(Sonnet3.7 or 3.5)
ブラウザにClaude, ChatGPT, Geminiというのを使っている。
それぞれが違う個性を持った人に適切にタスクをアサインしていく感じがしていて面白くはある。

Discussion

ログインするとコメントできます