0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PowerShell CoreをzoxideとfzfとStarshipでリッチにする

0
Last updated at Posted at 2026-07-21

はじめに

これまで私はWindowsでの作業はずっとMSYS2上のbashやらfishでやってきた。これは学生時代からずっとそうで、なんなら何年か前に

なんて記事も出していた。

無論PowerShell Core(7系)の存在は知っていたが、素のままだとどうしても補完や移動が貧弱で、bashやfishに慣れた身からするとまだ「作業する気になれない」シェルだったので敬遠していた。

ところが最近、AIエージェント全盛期となり、Claude Codeやcodexをcliがら呼び出すことは日常的な事となった。問題はこれらのコーディングエージェントはmsys2などという変態的環境と相性がよろしくないということだ。

つまり最近はpowershell coreばっかつかっている。とはいえ素のpowershell coreの貧弱さはちょっと我慢ならない。

というわけで、zoxideやfzfをPowerShellにきちんと組み込んで、普段使いできるレベルまでリッチにしてみることにした。

先行事例として以下の記事を参考にした。

ただしこの2本はそれぞれ別々の設計(PSFzf+ZLocation派とzoxide派)で書かれていて、そのまま両方を足すと「ディレクトリ移動の仕組みが2重になる」という重複が発生してしまう。今回はzoxide側を採用し、PSFzfは移動以外の部分(Tab補完・履歴検索など)だけを担当させる形に整理した。

今回目指す構成

image.png

最終的に採用した構成は次の表の通りだ。

役割 採用ツール 備考
ディレクトリ移動 zoxide ZLocationは不採用(zoxideと役割が重複するため)
ファジー検索UI fzf + PSFzf Tab補完・履歴検索・Ctrl+T/Ctrl+R/Alt+C/Alt+Aを担当
入力補完・予測 PSReadLine + CompletionPredictor PredictionSourcePlugin部分を実体化させる
プロンプト装飾 Starship (Tokyo Nightプリセット) git状態・言語バージョン・現在時刻などを表示

環境はPowerShell 7.6.1(Core)。パッケージ管理は基本winget/chocolateyに寄せ、モジュール類(PSFzf・CompletionPredictor)はPowerShell Gallery経由でインストールした。

Install

Nerd Font(ターミナルの表示準備)

tokyo-nightをはじめとするStarshipのプリセットはアイコン表示にNerd Fontを前提にしているものが多く、素のフォントのままだと文字が欠けたり四角い箱(いわゆる豆腐)になったりする。そのため他のツールを入れる前段として、まずNerd Fontを用意しておく。今回はChocolateyでHackGen Nerdを入れ、Windows Terminalのプロファイル設定でフォントをそれに切り替えた。

choco install font-hackgen-nerd
{
    "profiles":
    {
        "list":
        [
            {
                "font":
                {
                    "face": "HackGen Console NF",
                    "size": 13
                },
                "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
                "hidden": false,
                "name": "PowerShell",
                "opacity": 88,
                "source": "Windows.Terminal.PowershellCore"
            }
        ]
    }
}

CLIツール(winget)

winget install ajeetdsouza.zoxide
winget install junegunn.fzf
winget install Starship.Starship

導入時点(2026-07)でwingetとChocolateyのバージョン追従を比べてみたところ、zoxide・fzfともにwingetの方が本家GitHubリリースと同じバージョンで、むしろChocolateyの方が1バージョン遅れているという結果になった。少なくとも今回はwinget優先で問題なさそうだ。

パッケージ 本家最新 winget Chocolatey
zoxide 0.10.0 0.10.0 0.9.2
fzf 0.74.1 0.74.1 0.74.0

なお、zoxideのzi(fzf連携)にはfzf ≥ v0.51.0が必要である。古い記事の情報のままfzfを入れると動かないので要注意だ。

PowerShellモジュール

Install-Module -Name PSFzf -Scope CurrentUser
Install-Module -Name CompletionPredictor -Scope CurrentUser

プロファイルへの組み込み

$PROFILE(Microsoft.PowerShell_profile.ps1)に以下を追加すればいい。

try {
    $miseCommand = Get-Command mise -CommandType Application -ErrorAction Stop
    $miseActivation = & $miseCommand.Source activate pwsh 2>$null
    if ($LASTEXITCODE -eq 0 -and $miseActivation) {
        $miseActivation | Out-String | Invoke-Expression
    }

    # PSReadLine settings
    if ($Host.Name -eq 'ConsoleHost') {
        Import-Module PSReadLine -ErrorAction SilentlyContinue

        # CompletionPredictor - PredictionSourceのPlugin部分を実体化するプラグイン
        try {
            Import-Module CompletionPredictor -ErrorAction Stop
        } catch {
            # CompletionPredictor未導入。Install-Module CompletionPredictor -Scope CurrentUser
        }

        try {
            Set-PSReadLineOption -PredictionSource HistoryAndPlugin
        } catch {
            Set-PSReadLineOption -PredictionSource History
        }

        Set-PSReadLineOption -PredictionViewStyle ListView

        # PSFzf - Tabキーはfzfのファジー補完(Invoke-FzfTabCompletion)を優先
        # 標準のMenuCompleteに戻す場合は下のSet-PSReadLineKeyHandler(ScriptBlock)行をコメントアウトし、
        # catch側のSet-PSReadLineKeyHandler(Function MenuComplete)行のコメントを外す
        try {
            Import-Module PSFzf -ErrorAction Stop
            # 注: Set-PsFzfOption -TabExpansion はgit/Get-Process等の引数補完を強化するだけで、
            #     Tabキー自体の割り当てには関与しない(PSFzf.Base.ps1のSetTabExpansion参照)。
            #     Tabキーをfzfのポップアップに割り当てるには下記が必要。
            Set-PSReadLineKeyHandler -Key Tab -ScriptBlock { Invoke-FzfTabCompletion }
            # fh: 履歴をfzfであいまい検索するエイリアス (Invoke-FuzzyHistory)
            Set-PsFzfOption -EnableAliasFuzzyHistory
        } catch {
            # PSFzf未導入、または上記を無効化した場合は標準のMenuCompleteに戻す
            Set-PSReadLineKeyHandler -Key Tab -Function MenuComplete
        }
    }

    # Starship プロンプト (Tokyo Nightプリセット、設定は ~/.config/starship.toml)
    try {
        $null = Get-Command starship -CommandType Application -ErrorAction Stop
        Invoke-Expression (& { (starship init powershell | Out-String) })
    } catch {
        # starship未インストール。winget install Starship.Starship で導入可能
    }

    # zoxide (z / zi) - Starship が設定した prompt をラップして移動を記録する。
    # zoxide の pwd hook は prompt 経由で動作するため、Starship より後に初期化すること。
    try {
        $null = Get-Command zoxide -CommandType Application -ErrorAction Stop
        Invoke-Expression (& { (zoxide init --hook pwd powershell | Out-String) })
    } catch {
        # zoxide未インストール。winget install ajeetdsouza.zoxide で導入可能
    }

} catch {
    # some ai agent like codex cannot execute so that ignore error
}

Starshipの設定は~/.config/starship.tomlに生成する。

starship preset tokyo-night -o "$env:USERPROFILE\.config\starship.toml"

この環境でできること

PSFzf

Import-Module PSFzfするだけで、以下のキーバインドが自動的に有効になる。PSFzfのソース(PSFzf.Base.ps1)を覗いてみたところ、モジュールロード時に無条件でセットされる仕組みになっているようだった。

キー できること
Ctrl+T カレントディレクトリ配下をfzfで検索し、選んだパスをカーソル位置に挿入する
Ctrl+R PSReadLineの履歴をfzfであいまい検索する(標準の逆方向検索の強化版)
Alt+C カレントディレクトリ以下をfzfで探してcdする
Alt+A 過去に打ったコマンドの引数だけをfzfで検索する

Tab補完だけは、標準のMenuCompleteに代えて、明示的に以下でfzfのポップアップに切り替えている。

Set-PSReadLineKeyHandler -Key Tab -ScriptBlock { Invoke-FzfTabCompletion }

ここで一つハマった。Set-PsFzfOption -TabExpansionというオプションを見つけて、名前だけで「Tabキーをfzf補完に切り替えるスイッチ」に違いないと思い込み、最初はこれだけで済ませていた。ところが実際のソース(PSFzf.Base.ps1SetTabExpansion)を読むと、これはgitGet-Process/Get-Service向けの引数補完(Register-ArgumentCompleter)を強化するだけの代物で、Tabキーそのものの割り当てには一切関与していなかった。実際、有効化してもGet-PSReadLineKeyHandlerで見るとTabはTabCompleteNextのままで変化がない。READMEを読み直してようやく、Set-PSReadLineKeyHandler -Key Tab -ScriptBlock { Invoke-FzfTabCompletion }を明示的に書く必要があることが分かった。

もう一つ、fh(履歴のあいまい検索)のような便利エイリアスはデフォルトでは無効になっていて、個別に有効化してやる必要がある。

Set-PsFzfOption -EnableAliasFuzzyHistory

image.png

zoxide

zoxide initをプロファイルに書くと、z/ziという関数(内部的には__zoxide_z/__zoxide_ziのエイリアス)が使えるようになる。

コマンド できること
z <キーワード> 訪問頻度・最近度(frecency)から一番合致するディレクトリへジャンプする
zi <キーワード> 候補が複数ある時にfzfで選ばせる
zoxide query -ls 記憶しているディレクトリ一覧をスコア付きで表示する
zoxide remove <PATH> 誤って登録された/消えたディレクトリの履歴を削除する

PSFzfのAlt+Cとzoxideのziは見た目こそ似ているが、データソースが違う。Alt+Cはカレントディレクトリ配下を毎回スキャンするのに対し、ziは過去の訪問履歴(frecency)から選ぶ。近所のフォルダに行きたい時はAlt+C、よく使う遠いディレクトリに一気に飛びたい時はzi、と使い分けると両方の良さが活きる。

CompletionPredictor

PSReadLineのPredictionSourceNone/History/Plugin/HistoryAndPluginの4択だが、Plugin側の実体は何もインストールしなければ空のままだ。CompletionPredictorはこのPluginの実装の一つで、Tab補完できるものを片っ端からインラインの予測候補として出してくれるモジュールである。

Install-Module -Name CompletionPredictor -Scope CurrentUser
Import-Module CompletionPredictor   # PSReadLineの設定より前に読み込む

PSFzfzoxideとは完全に独立した機能で、キーもTabではなく右矢印キー(AcceptSuggestion)や上下矢印(ListView時の候補選択)、F2(表示切り替え)を使う。Tabキーの取り合いには一切関係しないというわけだ。

ListView時の様子

ListView時の様子

PSReadLine

今回の設定でのポイントは以下の2つ。

Set-PSReadLineOption -PredictionSource HistoryAndPlugin
Set-PSReadLineOption -PredictionViewStyle ListView

PredictionSourceは履歴とプラグイン(CompletionPredictor)の両方から予測を出す設定、PredictionViewStyleは候補をインラインの1行ではなく一覧(ListView)で見せる設定だ。ListViewにしておくと、候補がどのソース(History/CompletionPredictorなど)から来たかも表示されるので、動作確認がしやすい。

操作と動作を整理すると次のようになる。

操作 動作
入力するだけ 履歴+CompletionPredictorの候補がグレー表示
(右矢印) 候補をそのまま確定(Tabではない点に注意)
F2 InlineView(1行表示)とListView(一覧表示)を切り替え

starship

Nerd Fontの下準備(Installの章参照)ができたところで、見た目は公式のtokyo-nightプリセットをベースに、ディレクトリ表示だけ手元の好みに合わせて変更した。

starship preset tokyo-night -o "$env:USERPROFILE\.config\starship.toml"

デフォルトのtokyo-nightプリセットはtruncation_length = 3でパスを3階層に短縮していたので、フルパス表示になるよう以下の2箇所を変更した。

[directory]
truncation_length = 0     # 0 = 切り詰めなし(フルパス表示)
truncate_to_repo = false  # gitリポジトリルート起点への短縮も無効化

ホームディレクトリ配下は標準のhome_symbol(デフォルト~)によって自動的に~表示に置き換わるので、この設定は変更していない。

もう一点、プロンプトに出ている時計(19:04のような表示)は$timeモジュール(現在時刻)であって、$cmd_duration(コマンドの実行時間)とは別物である。tokyo-nightプリセットのformat文字列には$cmd_durationが含まれていないため、実行時間は最初から表示されない構成になっている。逆に$timeを消したい場合は[time]セクションにdisabled = trueを追加すればいい。

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?