`Ctrl+R`を押したら、最近実行した順にコマンド履歴が列挙され、それを[[インクリメンタルサーチ]]で絞り込み、決定したらプロンプトに挿入したい。
## 解決策
[[PSFzf]]を使う。インストールが必要。
```console
Install-Module PSFzf
```
[[Microsoft.PowerShell_profile.ps1]]に設定を追加。今回の方法では[[tac]]と[[AWK]]が必要。
```powershell
Set-PSReadLineKeyHandler -Chord Ctrl+r -ScriptBlock {
$command = Get-Content (Get-PSReadlineOption).HistorySavePath | tac | awk '!a[$0]++' | Invoke-Fzf -NoSort -Exact
[Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt()
if (!$command) {
return
}
[Microsoft.PowerShell.PSConsoleReadLine]::Insert($command)
}
```
- `Get-Content (Get-PSReadlineOption).HistorySavepath` でコマンド履歴の取得 (昇順)
- `tac`で順番を逆にする
- `awk '!a[$0]++'` で重複行の削除
- `Invoke-Fzf` で[[fzf]]の実行
- `-NoSort` で結果をソートしない
- ソートするとマッチ順になってしまい、最近のコマンドが見つからないため
- `-Exact` で[[ファジー検索]]を無効化
- [[ファジー検索]]するとイメージしてたコマンドが上に来ないため
- 🪦`Invoke-Fzf`には`-Tac`というオプションもあるが、重複削除後に表示順を入れ替えると、時間帯の古い方が残ってしまい、==以前に実行されたコマンドを再実行しても、最新の履歴として表示されない問題が発生する==
- `[Microsoft.PowerShell.PSConsoleReadLine]::InvokePrompt()` でプロンプトの再表示
- 🪦==これを入れないと、プロンプトが表示されなくなる==
- `if (!$command)` でコマンドを選択せず終了した場合になにもしない処理を追加
- 🪦==これを入れないと、エラーが表示される==
- `[Microsoft.PowerShell.PSConsoleReadLine]::Insert($command)` でプロンプトに選択したコマンドを挿入
## 参考
- [How to set up your PowerShell for a better developer experience \| Medium](https://medium.com/@dorlugasigal/how-to-set-up-your-powershell-f004c90bbafb)
- [Windows PowerShell Ctrl\+R history with fzf](https://gist.github.com/nv-h/081684cee2505cd336e26c2660fc7541)
## 🪦うまくいかなかった方法
### [[fzf]]をそのまま使う
[[Microsoft.PowerShell_profile.ps1]]
```powershell
Set-PSReadLineKeyHandler -Chord Ctrl+r -ScriptBlock {
$command = Get-Content (Get-PSReadlineOption).HistorySavePath | awk '!a[$0]++' | fzf --no-sort --exact --tac
[Microsoft.PowerShell.PSConsoleReadLine]::Insert($command)
}
```
以下のエラーが表示されてしまう。
```
An exception occurred in custom key handler, see $error for more information: Argument types do not match
```
### 履歴への重複登録を禁止する
[[HistoryNoDuplicates]]を有効にした場合。
```powershell
(Get-PSReadLineOption).HistoryNoDuplicates = $True
```
この設定は連続する重複したコマンドがユニークになるだけであり、連続していない場合は登録されてしまうため利用できない。