はじめに
これまで私は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補完・履歴検索など)だけを担当させる形に整理した。
今回目指す構成
最終的に採用した構成は次の表の通りだ。
| 役割 | 採用ツール | 備考 |
|---|---|---|
| ディレクトリ移動 | zoxide | ZLocationは不採用(zoxideと役割が重複するため) |
| ファジー検索UI | fzf + PSFzf | Tab補完・履歴検索・Ctrl+T/Ctrl+R/Alt+C/Alt+Aを担当 |
| 入力補完・予測 | PSReadLine + CompletionPredictor |
PredictionSourceのPlugin部分を実体化させる |
| プロンプト装飾 | 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.ps1のSetTabExpansion)を読むと、これはgitやGet-Process/Get-Service向けの引数補完(Register-ArgumentCompleter)を強化するだけの代物で、Tabキーそのものの割り当てには一切関与していなかった。実際、有効化してもGet-PSReadLineKeyHandlerで見るとTabはTabCompleteNextのままで変化がない。READMEを読み直してようやく、Set-PSReadLineKeyHandler -Key Tab -ScriptBlock { Invoke-FzfTabCompletion }を明示的に書く必要があることが分かった。
もう一つ、fh(履歴のあいまい検索)のような便利エイリアスはデフォルトでは無効になっていて、個別に有効化してやる必要がある。
Set-PsFzfOption -EnableAliasFuzzyHistory
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のPredictionSourceはNone/History/Plugin/HistoryAndPluginの4択だが、Plugin側の実体は何もインストールしなければ空のままだ。CompletionPredictorはこのPluginの実装の一つで、Tab補完できるものを片っ端からインラインの予測候補として出してくれるモジュールである。
Install-Module -Name CompletionPredictor -Scope CurrentUser
Import-Module CompletionPredictor # PSReadLineの設定より前に読み込む
PSFzfやzoxideとは完全に独立した機能で、キーもTabではなく右矢印キー(AcceptSuggestion)や上下矢印(ListView時の候補選択)、F2(表示切り替え)を使う。Tabキーの取り合いには一切関係しないというわけだ。
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を追加すればいい。
参考資料
- PowerShellでfzfやzlocationを使って、爆速で移動する
- Windows で zoxide を使う
- PowerShellの予測補完機能について(CompletionPredictorに触れた記事)
- zoxide (GitHub)
- PSFzf (GitHub)
- PSReadLine (GitHub)
- Using predictors in PSReadLine - Microsoft Learn
- CompletionPredictor - PowerShell Gallery
- Starship
- Starship Presets
- Starship Tokyo Night Preset


