にわとり頭の Powershell スクリプト

最近は、コマンドオプションを覚えておく程度の記憶力もあいまいになってきました。そこで、condaとgitのコマンドについて、それぞれcondax、gitxとタイプすれば、オプションの指定、引数の指定がしやすいようスクリプトを作成しました。スクリプトの内容の説明は省略しますが、何か参考になるかもしれないと思いましたので公表します。

:::note warn
お約束
本スクリプトの使用によって発生する損害（データの損失、システムの障害、第三者との紛争など）について、筆者は一切責任を負いません。スクリプトの利用は利用者の自己の判断と責任で行ってください。特にこのスクリプトは、condaないしgitのコマンドを発行しますので、不用意に用いると大きな損害を生じるかもしれません。

念のため、スクリプトをそのまま実行しようとしても実行はされずに表示だけで止まるようにしてあります。もし、実行する場合には、スクリプト中には次のようにしてある部分が２か所ありますのでコメントマーク（#）を外して使用してください。

    # 実行する場合は以下のコメントを外してください
    # Invoke-Expression $cmdString

:::

PowerShellの使い方については次の記事がとても参考になります。
「PowerShell 使い方メモ」
https://qiita.com/opengl-8080/items/bb0f5e4f1c7ce045cc57

### 1. PowerShell の プロファイルを編集
   PowerShell プロファイルを開く。なければ作成する。
```
if (!(Test-Path $PROFILE)) {
  New-Item -Path $PROFILE -ItemType File -Force
}
notepad $PROFILE
```

### 2. 4.のスクリプト例をPowerShellエディタへコピペ。

### 3. プロファイルの再読み込み、または PowerShell を再起動。
```
. $PROFILE
```

### 4. スクリプト例
```
#-------------------------------------------------------------------------------
# conda コマンドのらくらく入力 condax 関数
#-------------------------------------------------------------------------------
function condax {
    param(
        [string]$num,
        [Parameter(ValueFromRemainingArguments=$true)]
        [string[]]$argsList
    )

    $condaxCommands = @{
        1  = @{
            desc="仮想環境構築（引数あり）"; 
            cmd="conda create -n {0} python={1} {2}"; 
            args=3; 
            example="condax 1 myenv 3.9 numpy pandas";
            cmdFormat="conda create -n <環境名> python=<バージョン> <パッケージ1> <パッケージ2>...";
            explanation="指定した名前とPythonバージョンで仮想環境を作成し、指定したパッケージをインストールします"
        }
        2  = @{
            desc="仮想環境一覧"; 
            cmd="conda info -e"; 
            args=0; 
            example="condax 2";
            cmdFormat="conda info -e";
            explanation="インストールされているすべてのconda環境を一覧表示します"
        }
        3  = @{
            desc="仮想環境有効化（引数あり）"; 
            cmd="conda activate {0}"; 
            args=1; 
            example="condax 3 myenv";
            cmdFormat="conda activate <環境名>";
            explanation="指定した名前の環境を有効化（アクティベート）します"
        }
        4  = @{
            desc="仮想環境無効化"; 
            cmd="conda deactivate"; 
            args=0; 
            example="condax 4";
            cmdFormat="conda deactivate";
            explanation="現在有効な環境を無効化（デアクティベート）します"
        }
        5  = @{
            desc="仮想環境削除（引数あり）"; 
            cmd="conda remove -n {0} --all"; 
            args=1; 
            example="condax 5 myenv";
            cmdFormat="conda remove -n <環境名> --all";
            explanation="指定した名前の環境を完全に削除します"
        }
        6  = @{
            desc="仮想環境名称変更（引数あり）"; 
            cmd="conda create -n {0} --clone {1}"; 
            args=2; 
            example="condax 6 newenv oldenv";
            cmdFormat="conda create -n <新環境名> --clone <元環境名>";
            explanation="既存環境のクローンを新しい名前で作成します。旧環境は削除しません。"
        }
        7  = @{
            desc="旧環境削除（引数あり）"; 
            cmd="conda remove -n {0} --all"; 
            args=1; 
            example="condax 7 oldenv";
            cmdFormat="conda remove -n <環境名> --all";
            explanation="指定した名前の古い環境を完全に削除します"
        }
        8  = @{
            desc="パッケージ追加（引数あり）"; 
            cmd="conda install {0}"; 
            args=1; 
            example="condax 8 pandas matplotlib";
            cmdFormat="conda install <パッケージ1> <パッケージ2>...";
            explanation="現在の環境に指定したパッケージをインストールします"
        }
        9  = @{
            desc="パッケージインストール（引数あり）"; 
            cmd="conda install {0}"; 
            args=1; 
            example="condax 9 scipy";
            cmdFormat="conda install <パッケージ1> <パッケージ2>...";
            explanation="現在の環境に指定したパッケージをインストールします"
        }
        10 = @{
            desc="バージョン指定インストール（引数あり）"; 
            cmd="conda install {0}=={1}"; 
            args=2; 
            example="condax 10 numpy 1.21.0";
            cmdFormat="conda install <パッケージ名>==<バージョン>";
            explanation="指定したパッケージの特定バージョンをインストールします"
        }
        11 = @{
            desc="アンインストール（引数あり）"; 
            cmd="conda uninstall {0}"; 
            args=1; 
            example="condax 11 numpy";
            cmdFormat="conda uninstall <パッケージ名>";
            explanation="現在の環境から指定したパッケージをアンインストールします"
        }
        12 = @{
            desc="インストール済み一覧"; 
            cmd="conda list"; 
            args=0; 
            example="condax 12";
            cmdFormat="conda list";
            explanation="現在の環境にインストールされているすべてのパッケージを一覧表示します"
        }
        13 = @{
            desc="環境指定インストール済み一覧（引数あり）"; 
            cmd="conda list -n {0}"; 
            args=1; 
            example="condax 13 myenv";
            cmdFormat="conda list -n <環境名>";
            explanation="指定した環境にインストールされているすべてのパッケージを一覧表示します"
        }
        14 = @{
            desc="全パッケージアップデート"; 
            cmd="conda update --all"; 
            args=0; 
            example="condax 14";
            cmdFormat="conda update --all";
            explanation="現在の環境のすべてのパッケージを最新バージョンに更新します"
        }
        15 = @{
            desc="特定パッケージアップデート（引数あり）"; 
            cmd="conda update {0}"; 
            args=1; 
            example="condax 15 numpy";
            cmdFormat="conda update <パッケージ名>";
            explanation="指定したパッケージを最新バージョンに更新します"
        }
        16 = @{
            desc="パッケージ一覧更新"; 
            cmd="conda install -y conda-build"; 
            args=0; 
            example="condax 16";
            cmdFormat="conda install -y conda-build";
            explanation="conda-buildパッケージをインストールしてパッケージ一覧を更新します"
        }
    }

    function Show-CondaxList {
        Write-Host "condax コマンド一覧: condax XX とすれば、引数の説明を表示します"
        Write-Host "==========================================="
        foreach ($key in $condaxCommands.Keys | Sort-Object) {
            $desc = $condaxCommands[$key].desc
            $example = $condaxCommands[$key].example
            $cmdFormat = $condaxCommands[$key].cmdFormat
            $explanation = $condaxCommands[$key].explanation
            
            Write-Host "condax $key : $desc "
#           Write-Host "  コマンド形式: $cmdFormat"
#           Write-Host "  機能説明: $explanation"
#           Write-Host "  使用例  : $example"
#           Write-Host "------------------------------------------"
        }
    }

    function Show-Usage($num) {
        if ($condaxCommands.ContainsKey($num)) {
            $ex = $condaxCommands[$num].example
            $cmdFormat = $condaxCommands[$num].cmdFormat
            $explanation = $condaxCommands[$num].explanation
            Write-Host "機能説明: $explanation"
            Write-Host "実行されるコマンド: $cmdFormat"
            Write-Host "次（例）のように指定してください: $ex"
        } else {
            Write-Host "存在しないコマンド番号です。1〜16の番号を指定してください。"
        }
    }

    if (-not $num) {
        Show-CondaxList
        return
    }

    if ($num -match '^\d+$') {
        $numInt = [int]$num
        if (-not $condaxCommands.ContainsKey($numInt)) {
            Write-Host "1〜16の番号を指定してください。"
            return
        }

        $cmdInfo = $condaxCommands[$numInt]
        $requiredArgs = $cmdInfo.args
        $inputArgs = $argsList

        if ($inputArgs.Count -lt $requiredArgs) {
            Show-Usage $numInt
            return
        }

        # コマンド文字列の作成
        $cmdString = $cmdInfo.cmd
        
        # 特別な処理: コマンド1と8,9の場合は複数のパッケージを処理
        if ($numInt -eq 1 -and $inputArgs.Count -gt 2) {
            # 環境名とPythonバージョンを設定
            $cmdString = $cmdString -replace "\{0\}", $inputArgs[0]
            $cmdString = $cmdString -replace "\{1\}", $inputArgs[1]
            
            # 残りの引数をすべてパッケージとして扱う
            $packages = $inputArgs[2..($inputArgs.Count-1)] -join " "
            $cmdString = $cmdString -replace "\{2\}", $packages
        }
        elseif (($numInt -eq 8 -or $numInt -eq 9) -and $inputArgs.Count -ge 1) {
            # すべての引数をパッケージとして扱う
            $packages = $inputArgs -join " "
            $cmdString = $cmdString -replace "\{0\}", $packages
        }
        else {
            # 通常の引数置換
            for ($i=0; $i -lt $requiredArgs; $i++) {
                $cmdString = $cmdString -replace "\{$i\}", $inputArgs[$i]
            }
        }

        # コマンド実行前の確認（説明付き）
        Write-Host $cmdInfo.desc
        Write-Host "実行しようとしているコマンド: $cmdString"
        $confirmation = Read-Host "このコマンドを実行しますか？ （y または Y 以外はキャンセル）"
        
        if ($confirmation -eq 'y' -or $confirmation -eq 'Y') {
            Write-Host "コマンドを実行します..."
            Invoke-Expression $cmdString
        } else {
            Write-Host "コマンドの実行をキャンセルしました。"
        }
    }
    else {
        Write-Host "コマンド番号を指定してください。例えば 'condax 1' のように。"
        Show-CondaxList
    }
}


#-------------------------------------------------------------------------------
# git コマンドのらくらく入力 gitx 関数
#-------------------------------------------------------------------------------
function gitx {
    param(
        [string]$num,
        [Parameter(ValueFromRemainingArguments=$true)]
        [string[]]$argsList
    )

    $gitCommands = @{
        1  = @{
                desc="ローカル・リポジトリ準備"
                cmd="git init"
                args=0
                usage="git init"
                explanation="git init コマンドを実行します。" + `
                            "これによりプロジェクト一番上のディレクトリにて実行することでGitリポジトリの初期化を行います。" + `
                            "またカレントディレクトリに.gitディレクトリを作成してGitでの管理を可能にします。"
            }
        2  = @{
                desc="コミット準備"
                cmd="git add {0}"
                args=1
                argNames="＜ファイル名＞"
                usage="git add <file name>"
                explanation="git add <file name>コマンドを実行します。" + `
                            "これにより指定したファイルをステージングエリア（別名：インデックス）に追加します。" + `
                            "ファイル名に.を用いるとすべての変更をステージングエリアに追加できます。"
            }
        3  = @{
                desc="コミット"
                cmd='git commit -m "{0}"'
                args=1
                argNames="＜コミット・メッセージ＞"
                usage='git commit -m <commit message>'
                explanation="git commit  -m <commit message> コマンドを実行します。" + `
                            "これによりステージングエリアに追加された変更をコミットします。" + `
                            "-m オプションに続いてコミットメッセージを記述します。"
            }
        4  = @{
                desc="リモートリポジトリの登録"
                cmd="git remote add {0} {1}"
                args=2
                argNames="＜リモート・リポジトリ名＞ ＜リモート・リポジトリURL＞"
                usage="git remote add <remote repository> <remote repository URL>"
                explanation="git remote add <remote repository> <remote repository URL> コマンドを実行します。" + `
                            "これによりリモート・リポジトリを登録し、これに対するプッシュやプルが可能になります。"
            }
        5  = @{
                desc="プッシュ"
                cmd="git push {0} {1}"
                args=2
                argNames="＜リモート・リポジトリ名＞ ＜ブランチ名＞"
                usage="git push <remote repository> <branch>"
                explanation="git push <remote repository> <branch> コマンドを実行します。" + `
                            "これによりローカルのコミットをリモート・リポジトリにアップロードします。" + `
                            "通常、デフォルトのブランチは master または main です。"
            }
        6  = @{
                desc="プル"
                cmd="git pull {0} {1}"
                args=2
                argNames="＜リモート・リポジトリ名＞ ＜ブランチ名＞"
                usage="git pull <remote repository> <branch>"
                explanation="git pull <remote repository> <branch> コマンドを実行します。" + `
                            "これによりリモート・リポジトリの最新の変更をローカル・リポジトリに統合します。"
            }
        7  = @{
                desc="状態確認"
                cmd="git status"
                args=0
                usage="git status"
                explanation="git status コマンドを実行します。" + `
                            "これによりワーキング・ディレクトリとステージング・エリアの状態を表示します。" + `
                            "変更されたファイルやコミットされていないファイルを確認できます。"
            }
        8  = @{
                desc="変更内容の確認"
                cmd="git diff"
                args=0
                usage="git diff"
                explanation="git diff コマンドを実行します。これにより最後のコミット以降に変更されたコード内容を表示します。" + `
                            "ファイルごとの変更点を確認するのに役立ちます。"
            }
        9  = @{
                desc="コミット履歴の確認"
                cmd="git log"
                args=0
                usage="git log"
                explanation="git log コマンドを実行します。これによりコミット履歴を表示します。" + `
                            "各コミットにはコミット・メッセージと" + `
                            "共に一意のID（コミット・ハッシュ）が割り当てられています。"
            }
        10 = @{
                desc="履歴の詳細確認"
                cmd="git log -p"
                args=0
                usage="git log -p"
                explanation="git log -p コマンドを実行します。これにより各コミットの差分（変更内容）を表示します。" + `
                            "コードの変更履歴を詳細に追跡するのに便利です。Qキーで終了できます。"
            }
        11 = @{
                desc="クローン"
                cmd="git clone {0}"
                args=1
                argNames="＜リポジトリ URL＞"
                usage="git clone <repository URL>"
                explanation="git clone  <repository URL> コマンドを実行します。" + `
                            "これはリモート・リポジトリからローカル・リポジトリにプロジェクトを複製するためのgitコマンドです。"
            }
        12 = @{
                desc="ブランチ確認"
                cmd="git branch"
                args=0
                usage="git branch"
                explanation="git branch コマンドを実行します。" + `
                            "これにより現在のブランチ名の前にアスタリスク(*)が付いた一覧を表示します。" + `
                            "また、リポジトリに存在する全てのブランチを表示します。"
            }
        13 = @{
                desc="ブランチ作成&移動"
                cmd="git checkout -b {0}"
                args=1
                argNames="＜新ブランチ名＞"
                usage="git checkout -b <new-branch>"
                explanation="git checkout -b <new-branch> コマンドを実行します。" + `
                            "これにより新しいブランチを作成し、そのブランチに移動します。"
            }
        14 = @{
                desc="マージ"
                cmd="git merge {0}"
                args=1
                argNames="＜マージ先のブランチ名＞"
                usage="git merge <target branch>"
                explanation="git merge <target branch> コマンドを実行します。" + `
                            "これにより現在のブランチに指定したブランチの変更内容をマージします。"
            }
        15 = @{
                desc="ブランチの切り替え"
                cmd="git switch {0}"
                args=1
                argNames="＜ブランチ名＞"
                usage="git switch <branch>"
                explanation="git switch <branch> コマンドを実行します。これにより指定したブランチに切り替えます。"
            }
        16 = @{
                desc="新規ブランチ作成して切り替え"
                cmd="git switch -c {0}"
                args=1
                argNames="＜新ブランチ名＞"
                usage="git switch -c <new-branch>"
                explanation="git switch -c <new-branch> コマンドコマンドを実行します。" + `
                            "これにより新しいブランチを作成し、同時にそのブランチに切り替えます。"
            }
        17 = @{
                desc="作業ディレクトリの変更を破棄"
                cmd="git restore {0}"
                args=1
                argNames="＜ファイル名＞"
                usage="git restore <file name>"
                explanation="git restore <file name> コマンドを実行します。" + `
                            "これにより指定したファイルの作業ディレクトリの変更を破棄します。"
            }
        18 = @{
                desc="ステージングされた変更を解除"
                cmd="git restore --staged {0}"
                args=1
                argNames="＜ファイル名＞"
                usage="git restore --staged <file name>"
                explanation="git restore --staged <file name> コマンドを実行します。" + `
                            "これによりステージングされた変更を解除します。"
            }
        19 = @{
                desc="自動メンテナンスを有効化"
                cmd="git maintenance start"
                args=0
                usage="git maintenance start"
                explanation="git maintenance start コマンドを実行します。これによりGitの自動メンテナンスを有効化します。"
            }
        20 = @{
                desc="即時メンテナンス実行"
                cmd="git maintenance run"
                args=0
                usage="git maintenance run"
                explanation="git maintenance run コマンドを実行します。これにより即時にGitのメンテナンスを実行します。"
            }
        21 = @{
                desc="スパースチェックアウトを有効化"
                cmd="git sparse-checkout init"
                args=0
                usage="git sparse-checkout init"
                explanation="git sparse-checkout init コマンドを実行します。" + `
                            "これによりスパースチェックアウト（必要な部分のみチェックアウト）を有効化します。"
            }
        22 = @{
                desc="必要なディレクトリのみ指定"
                cmd="git sparse-checkout set {0}"
                args=1
                usage="git sparse-checkout set <dir1> <dir2> ..."
                explanation="git sparse-checkout set <dir1> <dir2> ... コマンドを実行します。" + `
                            "これにより指定したディレクトリのみをチェックアウト対象にします。" + `
                            "`n複数指定する場合はスペース区切りで引数を渡してください。"
            }
        23 = @{
                desc="マージの変更を詳細に確認"
                cmd="git log --remerge-diff"
                args=0
                usage="git log --remerge-diff"
                explanation="git log --remerge-diff コマンドを実行します。これによりマージの変更を詳細に確認できます。"
            }
        24 = @{
                desc="特定コミットを無視（blame）"
                cmd="git blame --ignore-rev {0}"
                args=1
                argNames="＜コミット・ハッシュ値＞"
                usage="git blame --ignore-rev <commit-hash>"
                explanation="git blame --ignore-rev コマンドを実行します。これにより指定したコミットを無視してblameを表示します。"
            }
        25 = @{
                desc="永続的に無視リストに追加"
                cmd='echo "{0}" >> .git-blame-ignore-revs
                git config blame.ignoreRevsFile .git-blame-ignore-revs'
                args=1
                argNames="＜コミット・ハッシュ値＞"
                usage='echo "<commit-hash>" >> .git-blame-ignore-revs
                git config blame.ignoreRevsFile .git-blame-ignore-revs'
                explanation="指定したコミットハッシュを無視リストに追加し、blameで無視できるように設定します。"
            }
        26 = @{
                desc="コミット範囲の差分を比較"
                cmd="git range-diff {0} {1}"
                args=2
                argNames="＜旧ブランチ名＞ ＜新ブランチ名＞"
                usage="git range-diff <old-branch> <new-branch>"
                explanation="git range-diff コマンドを実行します。これにより2つのコミット範囲の差分を比較します。"
            }
        27 = @{
                desc="ファイルの差分比較 (Git管理されていないファイル)"
                cmd="git diff --no-index {0} {1} > diff_result.txt"
                args=2
                argNames="＜ファイル１＞ ＜ファイル２＞"
                usage="git diff --no-index <file 1> <file 2> > diff_result.txt"
                explanation="git diff --no-index <file 1> <file 2> > diff_result.txt コマンドを実行します。" + `
                            "これにより2つのファイル(Git管理されていないファイル)の差分を比較します。"
            }
}
    function Get-DisplayWidth($str) {
        $width = 0
        foreach ($c in $str.ToCharArray()) {
            if ($c -match '[\p{IsCJKUnifiedIdeographs}\p{IsHiragana}\p{IsKatakana}]' -or $c -eq '　' -or $c -eq '（' -or $c -eq '）'){
                $width += 2
            }
            else {
                $width += 1
            }
        }
        return $width
    }

    function PadRightFullWidth($str, $totalWidth) {
        $currentWidth = Get-DisplayWidth $str
        $spacesNeeded = $totalWidth - $currentWidth
        if ($spacesNeeded -le 0) {
            return $str
        }
        else {
            return $str + (' ' * $spacesNeeded)
        }
    }

    function Show-GitxList {
        Write-Host "gitx コマンド一覧:"

        # desc の最大表示幅を計算
        $maxDescWidth = 0
        foreach ($cmd in $gitCommands.Values) {
            $w = Get-DisplayWidth $cmd.desc
            if ($w -gt $maxDescWidth) { $maxDescWidth = $w }
        }

        foreach ($key in $gitCommands.Keys | Sort-Object) {
            $cmd = $gitCommands[$key]
            $desc = $cmd.desc
            $argNames = $cmd.argNames

            $numberStr = "{0,3}." -f $key
            $descPadded = PadRightFullWidth $desc $maxDescWidth

            if ($argNames) {
                $commandStr = "gitx $key $argNames"
            }
            else {
                $commandStr = "gitx $key"
            }

            Write-Host "$numberStr $descPadded : $commandStr"
        }
    }




function Wrap-TextWithPeriod {
    param (
        [string]$Text,
        [int]$Width = 60
    )

    $result = ""
    $line = ""
    $charCount = 0

    foreach ($char in $Text.ToCharArray()) {
        $line += $char
        $charCount++

        if ($charCount -ge $Width) {
            # 句点なら改行
            if ($char -eq '。') {
                $result += $line + "`n"
                $line = ""
                $charCount = 0
            }
            else {
                # 句点以外でも強制改行する場合
                $result += $line + "`n"
                $line = ""
                $charCount = 0
            }
        }
        elseif ($char -eq '。') {
            # 句点で改行（幅未満でも）
            $result += $line + "`n"
            $line = ""
            $charCount = 0
        }
    }

    if ($line.Length -gt 0) {
        $result += $line
    }

    return $result.TrimEnd()
}





    function Show-Explanation {
        param (
            [int]$num
        )

        if ($gitCommands.ContainsKey($num)) {
            $cmd = $gitCommands[$num]

            Write-Host " "
            $wrappedText = Wrap-TextWithPeriod -Text $cmd.explanation -Width 70
            Write-Host $wrappedText
            Write-Host " "
        }
        else {
            Write-Host "指定された番号は存在しません。"
        }
    }




    function Show-Usage {
        param (
            [int]$num
        )

        if ($gitCommands.ContainsKey($num)) {
            $cmd = $gitCommands[$num]
            Write-Host "引数不足です。使用方法:" -NoNewline
            if ($cmd.argNames) {
                Write-Host "  gitx $num $($cmd.argNames)"
            }
            else {
                Write-Host "  gitx $num"
            }
            Write-Host " "
        }
    }


    if (-not $num) {
        Show-GitxList
        return
    }

#   メインの処理の該当部分

    [int]$numInt = 0  # ← ここで初期化

    if (-not [int]::TryParse($num, [ref]$numInt)) {
        Write-Host "数字でコマンド番号を指定してください。"
        return
    }

    if (-not $gitCommands.ContainsKey($numInt)) {
        Write-Host "指定された番号は存在しません。"
        return
    }

    $cmdInfo = $gitCommands[$numInt]

    if ($argsList.Count -lt $cmdInfo.args) {
        Show-Explanation -num $numInt
        Show-Usage -num $numInt
        return
    }

    Show-Explanation -num $numInt -showUsageMessage $false

    $cmdString = $cmdInfo.cmd
    for ($i = 0; $i -lt $cmdInfo.args; $i++) {
        $cmdString = $cmdString -replace "\{$i\}", $argsList[$i]
    }

    # Write-Host "実行コマンド: $cmdString"
    # 実行する場合は以下のコメントを外してください
    # Invoke-Expression $cmdString

}

#-------------------------------------------------------------------------------
# cd コマンドの再定義（エイリアス削除後）
#-------------------------------------------------------------------------------
Remove-Item Alias:cd -ErrorAction SilentlyContinue
function cd {
    param(
        [string]$path
    )
    if (-not $path) {
        Set-Location
    }
    elseif ($path -eq '/home') {
        $homePath = [Environment]::GetFolderPath('UserProfile')
        Set-Location $homePath
    }
    else {
        Set-Location $path
    }
}

#-------------------------------------------------------------------------------
# 秀丸エディタで開くための notepad 関数定義
#-------------------------------------------------------------------------------
function notepad {
    param(
        [Parameter(ValueFromRemainingArguments=$true)]
        $args
    )
    $hidemaruPath = "C:\Program Files (x86)\Hidemaru\Hidemaru.exe"

    if (-Not (Test-Path $hidemaruPath)) {
        Write-Error "秀丸エディタが見つかりません: $hidemaruPath"
        return
    }

    $argString = $args -join ' '
    Start-Process -FilePath $hidemaruPath -ArgumentList $argString
}

#-------------------------------------------------------------------------------
# conda コマンドのらくらく入力 condax 関数
#-------------------------------------------------------------------------------
function condax {
    param(
        [string]$num,
        [Parameter(ValueFromRemainingArguments=$true)]
        [string[]]$argsList
    )

    $condaxCommands = @{
        1  = @{
            desc="仮想環境構築（引数あり）"; 
            cmd="conda create -n {0} python={1} {2}"; 
            args=3; 
            example="condax 1 myenv 3.9 numpy pandas";
            cmdFormat="conda create -n <環境名> python=<バージョン> <パッケージ1> <パッケージ2>...";
            explanation="指定した名前とPythonバージョンで仮想環境を作成し、指定したパッケージをインストールします"
        }
        2  = @{
            desc="仮想環境一覧"; 
            cmd="conda info -e"; 
            args=0; 
            example="condax 2";
            cmdFormat="conda info -e";
            explanation="インストールされているすべてのconda環境を一覧表示します"
        }
        3  = @{
            desc="仮想環境有効化（引数あり）"; 
            cmd="conda activate {0}"; 
            args=1; 
            example="condax 3 myenv";
            cmdFormat="conda activate <環境名>";
            explanation="指定した名前の環境を有効化（アクティベート）します"
        }
        4  = @{
            desc="仮想環境無効化"; 
            cmd="conda deactivate"; 
            args=0; 
            example="condax 4";
            cmdFormat="conda deactivate";
            explanation="現在有効な環境を無効化（デアクティベート）します"
        }
        5  = @{
            desc="仮想環境削除（引数あり）"; 
            cmd="conda remove -n {0} --all"; 
            args=1; 
            example="condax 5 myenv";
            cmdFormat="conda remove -n <環境名> --all";
            explanation="指定した名前の環境を完全に削除します"
        }
        6  = @{
            desc="仮想環境名称変更（引数あり）"; 
            cmd="conda create -n {0} --clone {1}"; 
            args=2; 
            example="condax 6 newenv oldenv";
            cmdFormat="conda create -n <新環境名> --clone <元環境名>";
            explanation="既存環境のクローンを新しい名前で作成します。旧環境は削除しません。"
        }
        7  = @{
            desc="旧環境削除（引数あり）"; 
            cmd="conda remove -n {0} --all"; 
            args=1; 
            example="condax 7 oldenv";
            cmdFormat="conda remove -n <環境名> --all";
            explanation="指定した名前の古い環境を完全に削除します"
        }
        8  = @{
            desc="パッケージ追加（引数あり）"; 
            cmd="conda install {0}"; 
            args=1; 
            example="condax 8 pandas matplotlib";
            cmdFormat="conda install <パッケージ1> <パッケージ2>...";
            explanation="現在の環境に指定したパッケージをインストールします"
        }
        9  = @{
            desc="パッケージインストール（引数あり）"; 
            cmd="conda install {0}"; 
            args=1; 
            example="condax 9 scipy";
            cmdFormat="conda install <パッケージ1> <パッケージ2>...";
            explanation="現在の環境に指定したパッケージをインストールします"
        }
        10 = @{
            desc="バージョン指定インストール（引数あり）"; 
            cmd="conda install {0}=={1}"; 
            args=2; 
            example="condax 10 numpy 1.21.0";
            cmdFormat="conda install <パッケージ名>==<バージョン>";
            explanation="指定したパッケージの特定バージョンをインストールします"
        }
        11 = @{
            desc="アンインストール（引数あり）"; 
            cmd="conda uninstall {0}"; 
            args=1; 
            example="condax 11 numpy";
            cmdFormat="conda uninstall <パッケージ名>";
            explanation="現在の環境から指定したパッケージをアンインストールします"
        }
        12 = @{
            desc="インストール済み一覧"; 
            cmd="conda list"; 
            args=0; 
            example="condax 12";
            cmdFormat="conda list";
            explanation="現在の環境にインストールされているすべてのパッケージを一覧表示します"
        }
        13 = @{
            desc="環境指定インストール済み一覧（引数あり）"; 
            cmd="conda list -n {0}"; 
            args=1; 
            example="condax 13 myenv";
            cmdFormat="conda list -n <環境名>";
            explanation="指定した環境にインストールされているすべてのパッケージを一覧表示します"
        }
        14 = @{
            desc="全パッケージアップデート"; 
            cmd="conda update --all"; 
            args=0; 
            example="condax 14";
            cmdFormat="conda update --all";
            explanation="現在の環境のすべてのパッケージを最新バージョンに更新します"
        }
        15 = @{
            desc="特定パッケージアップデート（引数あり）"; 
            cmd="conda update {0}"; 
            args=1; 
            example="condax 15 numpy";
            cmdFormat="conda update <パッケージ名>";
            explanation="指定したパッケージを最新バージョンに更新します"
        }
        16 = @{
            desc="パッケージ一覧更新"; 
            cmd="conda install -y conda-build"; 
            args=0; 
            example="condax 16";
            cmdFormat="conda install -y conda-build";
            explanation="conda-buildパッケージをインストールしてパッケージ一覧を更新します"
        }
    }

    function Show-CondaxList {
        Write-Host "condax コマンド一覧: condax XX とすれば、引数の説明を表示します"
        Write-Host "==========================================="
        foreach ($key in $condaxCommands.Keys | Sort-Object) {
            $desc = $condaxCommands[$key].desc
            $example = $condaxCommands[$key].example
            $cmdFormat = $condaxCommands[$key].cmdFormat
            $explanation = $condaxCommands[$key].explanation
            
            Write-Host "condax $key : $desc "
#           Write-Host "  コマンド形式: $cmdFormat"
#           Write-Host "  機能説明: $explanation"
#           Write-Host "  使用例  : $example"
#           Write-Host "------------------------------------------"
        }
    }

    function Show-Usage($num) {
        if ($condaxCommands.ContainsKey($num)) {
            $ex = $condaxCommands[$num].example
            $cmdFormat = $condaxCommands[$num].cmdFormat
            $explanation = $condaxCommands[$num].explanation
            Write-Host "機能説明: $explanation"
            Write-Host "実行されるコマンド: $cmdFormat"
            Write-Host "次（例）のように指定してください: $ex"
        } else {
            Write-Host "存在しないコマンド番号です。1〜16の番号を指定してください。"
        }
    }

    if (-not $num) {
        Show-CondaxList
        return
    }

    if ($num -match '^\d+$') {
        $numInt = [int]$num
        if (-not $condaxCommands.ContainsKey($numInt)) {
            Write-Host "1〜16の番号を指定してください。"
            return
        }

        $cmdInfo = $condaxCommands[$numInt]
        $requiredArgs = $cmdInfo.args
        $inputArgs = $argsList

        if ($inputArgs.Count -lt $requiredArgs) {
            Show-Usage $numInt
            return
        }

        # コマンド文字列の作成
        $cmdString = $cmdInfo.cmd
        
        # 特別な処理: コマンド1と8,9の場合は複数のパッケージを処理
        if ($numInt -eq 1 -and $inputArgs.Count -gt 2) {
            # 環境名とPythonバージョンを設定
            $cmdString = $cmdString -replace "\{0\}", $inputArgs[0]
            $cmdString = $cmdString -replace "\{1\}", $inputArgs[1]
            
            # 残りの引数をすべてパッケージとして扱う
            $packages = $inputArgs[2..($inputArgs.Count-1)] -join " "
            $cmdString = $cmdString -replace "\{2\}", $packages
        }
        elseif (($numInt -eq 8 -or $numInt -eq 9) -and $inputArgs.Count -ge 1) {
            # すべての引数をパッケージとして扱う
            $packages = $inputArgs -join " "
            $cmdString = $cmdString -replace "\{0\}", $packages
        }
        else {
            # 通常の引数置換
            for ($i=0; $i -lt $requiredArgs; $i++) {
                $cmdString = $cmdString -replace "\{$i\}", $inputArgs[$i]
            }
        }

        # コマンド実行前の確認（説明付き）
        Write-Host $cmdInfo.desc
        Write-Host "実行しようとしているコマンド: $cmdString"
        $confirmation = Read-Host "このコマンドを実行しますか？ （y または Y 以外はキャンセル）"
        
        if ($confirmation -eq 'y' -or $confirmation -eq 'Y') {
            Write-Host "コマンドを実行します..."
            # 実行する場合は以下のコメントを外してください
            #  Invoke-Expression $cmdString
        } else {
            Write-Host "コマンドの実行をキャンセルしました。"
    }
    else {
        Write-Host "コマンド番号を指定してください。例えば 'condax 1' のように。"
        Show-CondaxList
    }
}


#-------------------------------------------------------------------------------
# git コマンドのらくらく入力 gitx 関数
#-------------------------------------------------------------------------------
function gitx {
    param(
        [string]$num,
        [Parameter(ValueFromRemainingArguments=$true)]
        [string[]]$argsList
    )

    $gitCommands = @{
        1  = @{
                desc="ローカル・リポジトリ準備"
                cmd="git init"
                args=0
                usage="git init"
                explanation="git init コマンドを実行します。" + `
                            "これによりプロジェクト一番上のディレクトリにて実行することでGitリポジトリの初期化を行います。" + `
                            "またカレントディレクトリに.gitディレクトリを作成してGitでの管理を可能にします。"
            }
        2  = @{
                desc="コミット準備"
                cmd="git add {0}"
                args=1
                argNames="＜ファイル名＞"
                usage="git add <file name>"
                explanation="git add <file name>コマンドを実行します。" + `
                            "これにより指定したファイルをステージングエリア（別名：インデックス）に追加します。" + `
                            "ファイル名に.を用いるとすべての変更をステージングエリアに追加できます。"
            }
        3  = @{
                desc="コミット"
                cmd='git commit -m "{0}"'
                args=1
                argNames="＜コミット・メッセージ＞"
                usage='git commit -m <commit message>'
                explanation="git commit  -m <commit message> コマンドを実行します。" + `
                            "これによりステージングエリアに追加された変更をコミットします。" + `
                            "-m オプションに続いてコミットメッセージを記述します。"
            }
        4  = @{
                desc="リモートリポジトリの登録"
                cmd="git remote add {0} {1}"
                args=2
                argNames="＜リモート・リポジトリ名＞ ＜リモート・リポジトリURL＞"
                usage="git remote add <remote repository> <remote repository URL>"
                explanation="git remote add <remote repository> <remote repository URL> コマンドを実行します。" + `
                            "これによりリモート・リポジトリを登録し、これに対するプッシュやプルが可能になります。"
            }
        5  = @{
                desc="プッシュ"
                cmd="git push {0} {1}"
                args=2
                argNames="＜リモート・リポジトリ名＞ ＜ブランチ名＞"
                usage="git push <remote repository> <branch>"
                explanation="git push <remote repository> <branch> コマンドを実行します。" + `
                            "これによりローカルのコミットをリモート・リポジトリにアップロードします。" + `
                            "通常、デフォルトのブランチは master または main です。"
            }
        6  = @{
                desc="プル"
                cmd="git pull {0} {1}"
                args=2
                argNames="＜リモート・リポジトリ名＞ ＜ブランチ名＞"
                usage="git pull <remote repository> <branch>"
                explanation="git pull <remote repository> <branch> コマンドを実行します。" + `
                            "これによりリモート・リポジトリの最新の変更をローカル・リポジトリに統合します。"
            }
        7  = @{
                desc="状態確認"
                cmd="git status"
                args=0
                usage="git status"
                explanation="git status コマンドを実行します。" + `
                            "これによりワーキング・ディレクトリとステージング・エリアの状態を表示します。" + `
                            "変更されたファイルやコミットされていないファイルを確認できます。"
            }
        8  = @{
                desc="変更内容の確認"
                cmd="git diff"
                args=0
                usage="git diff"
                explanation="git diff コマンドを実行します。これにより最後のコミット以降に変更されたコード内容を表示します。" + `
                            "ファイルごとの変更点を確認するのに役立ちます。"
            }
        9  = @{
                desc="コミット履歴の確認"
                cmd="git log"
                args=0
                usage="git log"
                explanation="git log コマンドを実行します。これによりコミット履歴を表示します。" + `
                            "各コミットにはコミット・メッセージと" + `
                            "共に一意のID（コミット・ハッシュ）が割り当てられています。"
            }
        10 = @{
                desc="履歴の詳細確認"
                cmd="git log -p"
                args=0
                usage="git log -p"
                explanation="git log -p コマンドを実行します。これにより各コミットの差分（変更内容）を表示します。" + `
                            "コードの変更履歴を詳細に追跡するのに便利です。Qキーで終了できます。"
            }
        11 = @{
                desc="クローン"
                cmd="git clone {0}"
                args=1
                argNames="＜リポジトリ URL＞"
                usage="git clone <repository URL>"
                explanation="git clone  <repository URL> コマンドを実行します。" + `
                            "これはリモート・リポジトリからローカル・リポジトリにプロジェクトを複製するためのgitコマンドです。"
            }
        12 = @{
                desc="ブランチ確認"
                cmd="git branch"
                args=0
                usage="git branch"
                explanation="git branch コマンドを実行します。" + `
                            "これにより現在のブランチ名の前にアスタリスク(*)が付いた一覧を表示します。" + `
                            "また、リポジトリに存在する全てのブランチを表示します。"
            }
        13 = @{
                desc="ブランチ作成&移動"
                cmd="git checkout -b {0}"
                args=1
                argNames="＜新ブランチ名＞"
                usage="git checkout -b <new-branch>"
                explanation="git checkout -b <new-branch> コマンドを実行します。" + `
                            "これにより新しいブランチを作成し、そのブランチに移動します。"
            }
        14 = @{
                desc="マージ"
                cmd="git merge {0}"
                args=1
                argNames="＜マージ先のブランチ名＞"
                usage="git merge <target branch>"
                explanation="git merge <target branch> コマンドを実行します。" + `
                            "これにより現在のブランチに指定したブランチの変更内容をマージします。"
            }
        15 = @{
                desc="ブランチの切り替え"
                cmd="git switch {0}"
                args=1
                argNames="＜ブランチ名＞"
                usage="git switch <branch>"
                explanation="git switch <branch> コマンドを実行します。これにより指定したブランチに切り替えます。"
            }
        16 = @{
                desc="新規ブランチ作成して切り替え"
                cmd="git switch -c {0}"
                args=1
                argNames="＜新ブランチ名＞"
                usage="git switch -c <new-branch>"
                explanation="git switch -c <new-branch> コマンドコマンドを実行します。" + `
                            "これにより新しいブランチを作成し、同時にそのブランチに切り替えます。"
            }
        17 = @{
                desc="作業ディレクトリの変更を破棄"
                cmd="git restore {0}"
                args=1
                argNames="＜ファイル名＞"
                usage="git restore <file name>"
                explanation="git restore <file name> コマンドを実行します。" + `
                            "これにより指定したファイルの作業ディレクトリの変更を破棄します。"
            }
        18 = @{
                desc="ステージングされた変更を解除"
                cmd="git restore --staged {0}"
                args=1
                argNames="＜ファイル名＞"
                usage="git restore --staged <file name>"
                explanation="git restore --staged <file name> コマンドを実行します。" + `
                            "これによりステージングされた変更を解除します。"
            }
        19 = @{
                desc="自動メンテナンスを有効化"
                cmd="git maintenance start"
                args=0
                usage="git maintenance start"
                explanation="git maintenance start コマンドを実行します。これによりGitの自動メンテナンスを有効化します。"
            }
        20 = @{
                desc="即時メンテナンス実行"
                cmd="git maintenance run"
                args=0
                usage="git maintenance run"
                explanation="git maintenance run コマンドを実行します。これにより即時にGitのメンテナンスを実行します。"
            }
        21 = @{
                desc="スパースチェックアウトを有効化"
                cmd="git sparse-checkout init"
                args=0
                usage="git sparse-checkout init"
                explanation="git sparse-checkout init コマンドを実行します。" + `
                            "これによりスパースチェックアウト（必要な部分のみチェックアウト）を有効化します。"
            }
        22 = @{
                desc="必要なディレクトリのみ指定"
                cmd="git sparse-checkout set {0}"
                args=1
                usage="git sparse-checkout set <dir1> <dir2> ..."
                explanation="git sparse-checkout set <dir1> <dir2> ... コマンドを実行します。" + `
                            "これにより指定したディレクトリのみをチェックアウト対象にします。" + `
                            "`n複数指定する場合はスペース区切りで引数を渡してください。"
            }
        23 = @{
                desc="マージの変更を詳細に確認"
                cmd="git log --remerge-diff"
                args=0
                usage="git log --remerge-diff"
                explanation="git log --remerge-diff コマンドを実行します。これによりマージの変更を詳細に確認できます。"
            }
        24 = @{
                desc="特定コミットを無視（blame）"
                cmd="git blame --ignore-rev {0}"
                args=1
                argNames="＜コミット・ハッシュ値＞"
                usage="git blame --ignore-rev <commit-hash>"
                explanation="git blame --ignore-rev コマンドを実行します。これにより指定したコミットを無視してblameを表示します。"
            }
        25 = @{
                desc="永続的に無視リストに追加"
                cmd='echo "{0}" >> .git-blame-ignore-revs
                git config blame.ignoreRevsFile .git-blame-ignore-revs'
                args=1
                argNames="＜コミット・ハッシュ値＞"
                usage='echo "<commit-hash>" >> .git-blame-ignore-revs
                git config blame.ignoreRevsFile .git-blame-ignore-revs'
                explanation="指定したコミットハッシュを無視リストに追加し、blameで無視できるように設定します。"
            }
        26 = @{
                desc="コミット範囲の差分を比較"
                cmd="git range-diff {0} {1}"
                args=2
                argNames="＜旧ブランチ名＞ ＜新ブランチ名＞"
                usage="git range-diff <old-branch> <new-branch>"
                explanation="git range-diff コマンドを実行します。これにより2つのコミット範囲の差分を比較します。"
            }
        27 = @{
                desc="ファイルの差分比較 (Git管理されていないファイル)"
                cmd="git diff --no-index {0} {1} > diff_result.txt"
                args=2
                argNames="＜ファイル１＞ ＜ファイル２＞"
                usage="git diff --no-index <file 1> <file 2> > diff_result.txt"
                explanation="git diff --no-index <file 1> <file 2> > diff_result.txt コマンドを実行します。" + `
                            "これにより2つのファイル(Git管理されていないファイル)の差分を比較します。"
            }
}
    function Get-DisplayWidth($str) {
        $width = 0
        foreach ($c in $str.ToCharArray()) {
            if ($c -match '[\p{IsCJKUnifiedIdeographs}\p{IsHiragana}\p{IsKatakana}]' -or $c -eq '　' -or $c -eq '（' -or $c -eq '）'){
                $width += 2
            }
            else {
                $width += 1
            }
        }
        return $width
    }

    function PadRightFullWidth($str, $totalWidth) {
        $currentWidth = Get-DisplayWidth $str
        $spacesNeeded = $totalWidth - $currentWidth
        if ($spacesNeeded -le 0) {
            return $str
        }
        else {
            return $str + (' ' * $spacesNeeded)
        }
    }

    function Show-GitxList {
        Write-Host "gitx コマンド一覧:"

        # desc の最大表示幅を計算
        $maxDescWidth = 0
        foreach ($cmd in $gitCommands.Values) {
            $w = Get-DisplayWidth $cmd.desc
            if ($w -gt $maxDescWidth) { $maxDescWidth = $w }
        }

        foreach ($key in $gitCommands.Keys | Sort-Object) {
            $cmd = $gitCommands[$key]
            $desc = $cmd.desc
            $argNames = $cmd.argNames

            $numberStr = "{0,3}." -f $key
            $descPadded = PadRightFullWidth $desc $maxDescWidth

            if ($argNames) {
                $commandStr = "gitx $key $argNames"
            }
            else {
                $commandStr = "gitx $key"
            }

            Write-Host "$numberStr $descPadded : $commandStr"
        }
    }




function Wrap-TextWithPeriod {
    param (
        [string]$Text,
        [int]$Width = 60
    )

    $result = ""
    $line = ""
    $charCount = 0

    foreach ($char in $Text.ToCharArray()) {
        $line += $char
        $charCount++

        if ($charCount -ge $Width) {
            # 句点なら改行
            if ($char -eq '。') {
                $result += $line + "`n"
                $line = ""
                $charCount = 0
            }
            else {
                # 句点以外でも強制改行する場合
                $result += $line + "`n"
                $line = ""
                $charCount = 0
            }
        }
        elseif ($char -eq '。') {
            # 句点で改行（幅未満でも）
            $result += $line + "`n"
            $line = ""
            $charCount = 0
        }
    }

    if ($line.Length -gt 0) {
        $result += $line
    }

    return $result.TrimEnd()
}





    function Show-Explanation {
        param (
            [int]$num
        )

        if ($gitCommands.ContainsKey($num)) {
            $cmd = $gitCommands[$num]

            Write-Host " "
            $wrappedText = Wrap-TextWithPeriod -Text $cmd.explanation -Width 70
            Write-Host $wrappedText
            Write-Host " "
        }
        else {
            Write-Host "指定された番号は存在しません。"
        }
    }




    function Show-Usage {
        param (
            [int]$num
        )

        if ($gitCommands.ContainsKey($num)) {
            $cmd = $gitCommands[$num]
            Write-Host "引数不足です。使用方法:" -NoNewline
            if ($cmd.argNames) {
                Write-Host "  gitx $num $($cmd.argNames)"
            }
            else {
                Write-Host "  gitx $num"
            }
            Write-Host " "
        }
    }


    if (-not $num) {
        Show-GitxList
        return
    }

#   メインの処理の該当部分

    [int]$numInt = 0  # ← ここで初期化

    if (-not [int]::TryParse($num, [ref]$numInt)) {
        Write-Host "数字でコマンド番号を指定してください。"
        return
    }

    if (-not $gitCommands.ContainsKey($numInt)) {
        Write-Host "指定された番号は存在しません。"
        return
    }

    $cmdInfo = $gitCommands[$numInt]

    if ($argsList.Count -lt $cmdInfo.args) {
        Show-Explanation -num $numInt
        Show-Usage -num $numInt
        return
    }

    Show-Explanation -num $numInt -showUsageMessage $false

    $cmdString = $cmdInfo.cmd
    for ($i = 0; $i -lt $cmdInfo.args; $i++) {
        $cmdString = $cmdString -replace "\{$i\}", $argsList[$i]
    }

    Write-Host "実行コマンド: $cmdString"
    # 実行する場合は以下のコメントを外してください
    # Invoke-Expression $cmdString
}


```