VSCodeでショートカット一発でターミナル実行!TypeScriptマクロ実装完全ガイド

Development
スポンサーリンク
スポンサーリンク

はじめに

「VSCodeでいちいちコマンドをコピペしてターミナルで実行するのめんどくさい…」

そんな悩みを持つ開発者は多いはずです。実際、検索数から見ても:

■検索ワード(月間検索数)
- 1000~1万: "vscode ターミナル"
- 100~1000: "vscode コマンド プロンプト", "vscode powershell", "vscode gitbash"
- 10~100: "vscode ターミナル 実行", "vscode cmd"

ターミナル実行の効率化は、多くの開発者が求めている機能です。

本記事では、カーソル行または選択テキストをショートカットキー一発でターミナル実行できるTypeScriptマクロの実装方法を完全解説します。

この記事で分かること

  • ターミナル実行マクロの実装方法
  • cmd/PowerShell/Git Bashの使い分け
  • 単一行・複数行コマンドの実行方法
  • キーバインド設定のベストプラクティス
  • 実践的な使用例とワークフロー
  • トラブルシューティング

こんな人におすすめ

  • コマンドをメモ帳に保存している人
  • コマンド実行のたびにコピペしている人
  • よく使うコマンドをすぐ実行したい人
  • 複数のターミナル(cmd/PS/GitBash)を使い分けたい人

解決できる課題

従来の問題点

1. コピペの手間

1. コマンドを選択
2. Ctrl+Cでコピー
3. ターミナルをクリック
4. Ctrl+Vで貼り付け
5. Enter押下

2. コマンド管理の煩雑さ

  • よく使うコマンドをどこに保存?
  • 過去のコマンド履歴を探すのが大変
  • プロジェクトごとのコマンド集が散在

3. ターミナル切り替えの手間

  • cmd、PowerShell、Git Bashを使い分け
  • それぞれでコマンド入力が必要

この機能で実現できること

ショートカットキー一発で実行!

Before:
選択 → コピー → ターミナル切替 → 貼り付け → Enter(5ステップ)

After:
Ctrl+Shift+1(1ステップ)

複数コマンドも順次実行

# 3行を選択してCtrl+Shift+1
cd /d C:\projects
npm install
npm run dev
# → 自動で順次実行!

機能仕様

基本機能

機能説明
単一行実行カーソル行を実行
複数行実行選択範囲を行ごとに順次実行
空行スキップ空行は自動で除外
ターミナル管理専用ターミナルを自動作成・再利用

ショートカットキー

キー機能ターミナル
Ctrl+Shift+1CMD実行コマンドプロンプト
Ctrl+Shift+2PS実行PowerShell
Ctrl+Shift+3Bash実行Git Bash

動作フロー

1. テキスト未選択の場合
   ↓
   カーソル行の文字列全体を取得
   ↓
   ターミナルで実行

2. テキスト選択の場合
   ↓
   選択範囲を行ごとに分割
   ↓
   空行を除外
   ↓
   各行を順次実行(100ms待機)

TypeScript実装コード

ファイル構成

src/
├── extension.ts              # コマンド登録
└── macros/
    └── runInTerminal.ts      # ターミナル実行機能

runInTerminal.ts(完全版)

import * as vscode from 'vscode';

/**
 * ターミナルのタイプ
 */
export enum TerminalType {
    CMD = 'cmd',
    PowerShell = 'powershell',
    GitBash = 'gitbash'
}

/**
 * コマンドプロンプトで実行
 */
export async function runInCmd() {
    await runInTerminal(TerminalType.CMD);
}

/**
 * PowerShellで実行
 */
export async function runInPowerShell() {
    await runInTerminal(TerminalType.PowerShell);
}

/**
 * Git Bashで実行
 */
export async function runInGitBash() {
    await runInTerminal(TerminalType.GitBash);
}

/**
 * 指定されたターミナルでコマンド実行
 */
async function runInTerminal(terminalType: TerminalType) {
    const editor = vscode.window.activeTextEditor;
    if (!editor) {
        vscode.window.showWarningMessage('アクティブなエディタがありません');
        return;
    }

    // コマンド取得
    const commands = getCommandsToExecute(editor);
    if (commands.length === 0) {
        vscode.window.showWarningMessage('実行するコマンドがありません');
        return;
    }

    // ターミナル取得または作成
    const terminal = getOrCreateTerminal(terminalType);
    terminal.show();

    // コマンド実行(複数行の場合は順次実行)
    for (const command of commands) {
        const trimmedCommand = command.trim();
        if (trimmedCommand) {
            terminal.sendText(trimmedCommand, true);
            // 複数コマンド実行時は少し待機
            if (commands.length > 1) {
                await sleep(100);
            }
        }
    }

    // 実行完了メッセージ
    const terminalName = getTerminalDisplayName(terminalType);
    const message = commands.length === 1 
        ? `${terminalName}でコマンドを実行しました`
        : `${terminalName}で${commands.length}個のコマンドを実行しました`;
    vscode.window.showInformationMessage(message);
}

/**
 * 実行するコマンドを取得
 */
function getCommandsToExecute(editor: vscode.TextEditor): string[] {
    const selection = editor.selection;
    const document = editor.document;

    // テキストが選択されている場合
    if (!selection.isEmpty) {
        const selectedText = document.getText(selection);
        
        // 複数行の場合は行ごとに分割
        const lines = selectedText.split(/\r?\n/);
        
        // 空行を除外してコマンドリストを作成
        return lines
            .map(line => line.trim())
            .filter(line => line.length > 0);
    }

    // テキスト未選択の場合は現在行を取得
    const currentLine = document.lineAt(selection.active.line);
    const lineText = currentLine.text.trim();
    
    return lineText.length > 0 ? [lineText] : [];
}

/**
 * ターミナルを取得または作成
 */
function getOrCreateTerminal(terminalType: TerminalType): vscode.Terminal {
    const terminalName = getTerminalName(terminalType);
    
    // 既存のターミナルを探す
    const existingTerminal = vscode.window.terminals.find(
        t => t.name === terminalName
    );

    if (existingTerminal) {
        return existingTerminal;
    }

    // 新規ターミナルを作成
    return createTerminal(terminalType);
}

/**
 * 新しいターミナルを作成
 */
function createTerminal(terminalType: TerminalType): vscode.Terminal {
    const name = getTerminalName(terminalType);
    
    let shellPath: string | undefined;
    let shellArgs: string[] | undefined;

    switch (terminalType) {
        case TerminalType.CMD:
            shellPath = 'cmd.exe';
            break;
        case TerminalType.PowerShell:
            shellPath = 'powershell.exe';
            break;
        case TerminalType.GitBash:
            // Git Bashの一般的なパス
            shellPath = 'C:\\Program Files\\Git\\bin\\bash.exe';
            // 見つからない場合の代替パス
            if (!require('fs').existsSync(shellPath)) {
                shellPath = 'C:\\Program Files (x86)\\Git\\bin\\bash.exe';
            }
            shellArgs = ['--login', '-i'];
            break;
    }

    return vscode.window.createTerminal({
        name: name,
        shellPath: shellPath,
        shellArgs: shellArgs
    });
}

/**
 * ターミナル名を取得
 */
function getTerminalName(terminalType: TerminalType): string {
    switch (terminalType) {
        case TerminalType.CMD:
            return 'My Macros - CMD';
        case TerminalType.PowerShell:
            return 'My Macros - PowerShell';
        case TerminalType.GitBash:
            return 'My Macros - Git Bash';
    }
}

/**
 * ターミナル表示名を取得
 */
function getTerminalDisplayName(terminalType: TerminalType): string {
    switch (terminalType) {
        case TerminalType.CMD:
            return 'コマンドプロンプト';
        case TerminalType.PowerShell:
            return 'PowerShell';
        case TerminalType.GitBash:
            return 'Git Bash';
    }
}

/**
 * 待機用ヘルパー関数
 */
function sleep(ms: number): Promise {
    return new Promise(resolve => setTimeout(resolve, ms));
}

extension.ts(コマンド登録)

import * as vscode from 'vscode';
import { runInCmd, runInPowerShell, runInGitBash } from './macros/runInTerminal';

export function activate(context: vscode.ExtensionContext) {
    console.log('my-macros extension is now active');

    // コマンド登録
    const commands = [
        // ターミナル実行
        vscode.commands.registerCommand('myMacros.runInCmd', runInCmd),
        vscode.commands.registerCommand('myMacros.runInPowerShell', runInPowerShell),
        vscode.commands.registerCommand('myMacros.runInGitBash', runInGitBash),
    ];

    commands.forEach(command => context.subscriptions.push(command));
}

export function deactivate() {}

package.json(設定ファイル)

{
  "name": "my-macros",
  "displayName": "My Macros",
  "version": "0.0.2",
  "contributes": {
    "commands": [
      {
        "command": "myMacros.runInCmd",
        "title": "Run in Command Prompt",
        "category": "My Macros"
      },
      {
        "command": "myMacros.runInPowerShell",
        "title": "Run in PowerShell",
        "category": "My Macros"
      },
      {
        "command": "myMacros.runInGitBash",
        "title": "Run in Git Bash",
        "category": "My Macros"
      }
    ],
    "keybindings": [
      {
        "command": "myMacros.runInCmd",
        "key": "ctrl+shift+1",
        "when": "editorTextFocus"
      },
      {
        "command": "myMacros.runInPowerShell",
        "key": "ctrl+shift+2",
        "when": "editorTextFocus"
      },
      {
        "command": "myMacros.runInGitBash",
        "key": "ctrl+shift+3",
        "when": "editorTextFocus"
      }
    ]
  }
}

コードの詳細解説

1. Enum定義

export enum TerminalType {
    CMD = 'cmd',
    PowerShell = 'powershell',
    GitBash = 'gitbash'
}

ポイント:

  • 型安全にターミナルタイプを管理
  • 文字列のタイポを防止
  • IntelliSenseが効く

2. コマンド取得ロジック

function getCommandsToExecute(editor: vscode.TextEditor): string[] {
    const selection = editor.selection;
    
    // 選択されている場合
    if (!selection.isEmpty) {
        const selectedText = document.getText(selection);
        const lines = selectedText.split(/\r?\n/);
        
        return lines
            .map(line => line.trim())
            .filter(line => line.length > 0);
    }
    
    // 未選択の場合は現在行
    const currentLine = document.lineAt(selection.active.line);
    return currentLine.text.trim().length > 0 ? [currentLine.text.trim()] : [];
}

機能:

  • 選択範囲の検知
  • 行単位で分割
  • 空行の自動除外
  • trim()でホワイトスペース除去

3. ターミナル管理

function getOrCreateTerminal(terminalType: TerminalType): vscode.Terminal {
    const terminalName = getTerminalName(terminalType);
    
    // 既存ターミナルを検索
    const existingTerminal = vscode.window.terminals.find(
        t => t.name === terminalName
    );

    if (existingTerminal) {
        return existingTerminal;
    }

    // 新規作成
    return createTerminal(terminalType);
}

メリット:

  • ターミナルの再利用
  • メモリ効率の向上
  • ターミナルの乱立防止

4. 複数コマンドの順次実行

for (const command of commands) {
    terminal.sendText(command, true);
    if (commands.length > 1) {
        await sleep(100);  // 100ms待機
    }
}

100ms待機の理由:

  • コマンドの確実な実行
  • 先行コマンドの完了待ち
  • ターミナルの処理負荷軽減

使い方

基本的な使い方

1. 単一コマンドの実行

# test_commands.txt
npm run dev
1. カーソルを行に配置
2. Ctrl+Shift+2(PowerShellで実行)
3. → PowerShellが開いて自動実行!

2. 複数コマンドの実行

# deploy.txt
cd /d C:\projects\my-app
git pull origin main
npm install
npm run build
npm run deploy
1. 全行を選択(Ctrl+A)
2. Ctrl+Shift+1(CMDで実行)
3. → 5つのコマンドが順次実行!

実践的な活用例

開発環境セットアップ

# setup_dev.txt
cd /d C:\projects
git clone https://github.com/user/repo.git
cd repo
npm install
code .
選択 → Ctrl+Shift+1で一括セットアップ!

定型作業の自動化

# daily_tasks.txt
cd /d C:\projects\app
git fetch origin
git status
npm run test
毎朝Ctrl+Shift+1で健全性チェック!

Docker操作

# docker_commands.txt
docker-compose down
docker-compose build
docker-compose up -d
docker-compose logs -f
Ctrl+Shift+2で一括操作!

キーバインドのカスタマイズ

keybindings.json での変更

// ショートカットキーを変更
[
    {
        "key": "ctrl+alt+1",
        "command": "myMacros.runInCmd",
        "when": "editorTextFocus"
    },
    {
        "key": "ctrl+alt+2",
        "command": "myMacros.runInPowerShell",
        "when": "editorTextFocus"
    },
    {
        "key": "ctrl+alt+3",
        "command": "myMacros.runInGitBash",
        "when": "editorTextFocus"
    }
]

コンテキストによる制限

// Markdownファイルでのみ有効
{
    "key": "ctrl+shift+1",
    "command": "myMacros.runInCmd",
    "when": "editorTextFocus && resourceExtname == '.md'"
}
// 特定のワークスペースでのみ有効
{
    "key": "ctrl+shift+1",
    "command": "myMacros.runInCmd",
    "when": "editorTextFocus && workspaceFolderCount > 0"
}

メリット・デメリット

メリット

1. 圧倒的な時短効果

  • コピペ操作の削減: 5ステップ → 1ステップ
  • よく使うコマンドを即実行
  • 複数コマンドも一括処理

2. コマンド集の一元管理

  • .txt または .md で管理
  • プロジェクトごとにファイル作成
  • Gitで履歴管理

3. ターミナルの使い分けが簡単

  • cmd/PS/Bashを自在に切替
  • ターミナル固有のコマンドも対応
  • ターミナルの再利用で効率化

4. 学習コストが低い

  • 直感的な操作
  • 既存のメモをそのまま活用
  • エディタ感覚で編集可能

デメリット

1. 初期セットアップが必要

  • TypeScript環境の構築
  • 拡張機能のインストール

2. 対話的なコマンドは非対応

  • npm init などの入力待ちコマンド
  • ssh でのパスワード入力

3. エラーハンドリングが弱い

  • コマンド失敗時も次へ進む
  • 自動リトライ機能なし

総評

デメリットを大きく上回る効率化が可能

特に、頻繁にコマンド実行する開発者には必須の機能です。

応用テクニック

1. プロジェクト別コマンド集

project-commands/
├── backend/
│   ├── dev.txt
│   ├── test.txt
│   └── deploy.txt
└── frontend/
    ├── dev.txt
    ├── build.txt
    └── deploy.txt

使い方:

1. dev.txtを開く
2. Ctrl+A → Ctrl+Shift+2
3. → 開発環境が起動!

2. エイリアス定義ファイル

# aliases.txt(Git Bash用)
alias ll='ls -la'
alias gs='git status'
alias gp='git pull'
alias gb='git branch'
起動時にCtrl+Shift+3で一括登録!

3. 環境変数設定

# env_setup.ps1(PowerShell用)
$env:NODE_ENV="development"
$env:API_KEY="your-api-key"
$env:DEBUG="true"
Ctrl+Shift+2で環境変数を一括設定!

4. ドキュメント化

# コマンド集

## 開発環境起動
cd /d C:\projects
npm run dev

## ビルド
npm run build

## デプロイ
npm run deploy
Markdownで管理 + 実行可能!

トラブルシューティング

Git Bashが起動しない

エラー:

Failed to launch terminal

解決策:

// runInTerminal.ts
case TerminalType.GitBash:
    // パスを環境に合わせて修正
    shellPath = 'C:\\Program Files\\Git\\bin\\bash.exe';
    // または
    shellPath = 'C:\\Program Files (x86)\\Git\\bin\\bash.exe';
    // または
    shellPath = 'C:\\git\\bin\\bash.exe';
    break;

コマンドが実行されない

原因1: 空行が含まれる
trim()filter() で除外済み

原因2: ターミナルが閉じている
→ 自動で再作成されるはずだが、手動で閉じた場合は再実行

原因3: パスに空白が含まれる

# NG
cd C:\Program Files\app

# OK
cd "C:\Program Files\app"

複数コマンドが途中で止まる

原因: コマンド実行時間が長い

解決策: 待機時間を調整

// 100ms → 500msに変更
if (commands.length > 1) {
    await sleep(500);
}

キーバインドが効かない

確認ポイント:

  1. when条件の確認
"when": "editorTextFocus"
// エディタにフォーカスがあるか?
  1. 競合の確認
Ctrl+Shift+P → "Preferences: Open Keyboard Shortcuts"
→ Ctrl+Shift+1で検索
  1. 拡張機能の有効化確認
Ctrl+Shift+P → "Extensions: Show Installed Extensions"
→ My Macros が有効か確認

パフォーマンス最適化

ターミナルの再利用

// ターミナル名で識別して再利用
function getOrCreateTerminal(terminalType: TerminalType): vscode.Terminal {
    const terminalName = getTerminalName(terminalType);
    
    const existingTerminal = vscode.window.terminals.find(
        t => t.name === terminalName
    );

    return existingTerminal || createTerminal(terminalType);
}

メリット:

  • 新規作成のオーバーヘッド削減
  • 環境変数の保持
  • 作業ディレクトリの維持

非同期処理の最適化

// 並列実行は避ける(コマンドの依存関係のため)
for (const command of commands) {
    await terminal.sendText(command, true);
    // 順次実行を保証
}

まとめ

VSCodeでショートカット一発でターミナル実行できるTypeScriptマクロを実装しました。

得られる効果:

  • コマンド実行が5ステップ → 1ステップに
  • よく使うコマンドを即座に実行
  • 複数コマンドの一括実行
  • cmd/PowerShell/Git Bashの使い分けが簡単

こんな人に最適:

  • 頻繁にコマンド実行する開発者
  • コマンドをメモ帳管理している人
  • 作業を効率化したい人
  • 複数のターミナルを使い分ける人

次のステップ:

  1. 環境構築(TypeScript + VSCode拡張)
  2. コード実装(この記事のコードをコピー)
  3. パッケージ化してインストール
  4. よく使うコマンド集を作成
  5. ショートカットで爆速実行!

ぜひ実装して、開発効率を劇的に向上させてください!

関連記事

TypeScript拡張機能の開発環境構築

VSCode TypeScriptマクロ開発環境の完全ガイド【セットアップから運用まで】
はじめにVSCodeでカスタムマクロを作成したいけど、どうやって開発環境を構築すればいいか分からない。そんな悩みを持つ方に向けて、TypeScriptでVSCode拡張機能を開発する環境の構築から、実際にマクロを作成して使えるようにするまで...

サクラエディタからVSCodeへのマクロ移行

サクラエディタからVSCodeへマクロ移行!快適開発環境の構築記録
はじめに長年愛用してきたサクラエディタのマクロ機能。便利なJavaScript/VBSマクロを多数作成して日常業務で活用してきましたが、最近のAWS開発やブログ執筆でVSCodeを使う機会が増えてきました。「VSCodeでもサクラエディタの...

タグ: #VSCode #TypeScript #マクロ #ターミナル #コマンド実行 #生産性向上 #自動化

コメント