PowerShellでghq + fzf環境を作る

Windowsでもghqを使ったリポジトリ管理を行いたくて、最初WSLからUbuntuを使おうと思ったんだけど、ダルくなったのでPowerShellでやることにした。

PS>go version
go version go1.9.2 windows/amd64

PS>$Psversiontable

Name                           Value
----                           -----
PSVersion                      6.2.4
PSEdition                      Core
GitCommitId                    6.2.4
OS                             Microsoft Windows 10.0.18362 
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0窶ヲ}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

golangとgitは昔インストールしてたやつが残ってたんだけど、あまりにも古すぎるので別途アップデートする…

ghq と fzfのインストール

Windowsでのパッケージマネージャーは見直すたびに今はこれだーと入れ替わっている印象がある。今回はscoopを使うことにした。

scoop.sh

PS>Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force  
PS> iex (New-Object net.webclient).downloadstring('https://get.scoop.sh')

PS>scoop install fzf 
PS>scoop install ghq

ghq rootのパスを決める

Windoesでもghq rootのパスはgit configで変更できる

git config --global ghq.root D:\dev\src\

Profileの編集してリポジトリを選択できるようにする

bashでいう .bash_profile のようにPowerShellにもプロファイルが存在する。パスが変数に入っているので便利。

PS>$profile
C:\Users\User\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

自分は $Profileの中身で $PSInclude という変数を定義して、そのフォルダ内のスクリプトをぜんぶ読み込むということをしている。これで$Profileが長くならずに済む。

$PSInclude = "C:\Users\User\Documents\PowerShell\include\"
ls $PSInclude  *.ps1 | 
    %{
        $_.Name
        $path = $PSInclude  + $_.Name
        . $path
    }

そしてそのなかにPowerShellスクリプトを置く。

function ghq-fzf {
  $repo = $(ghq list | fzf)
  Set-Location ( Join-Path $(ghq root) $repo)
}

これで ghq-fzf を叩くといつものリポジトリの選択画面になり、選択後そのフォルダに飛べるようになる。毎度関数を叩きたくないのでショートカットにする。Set-PSReadLineKeyHandler を使うと良さそう。今回はCtrl+gで選択画面に飛べるようにした。

function ghq-fzf {
  $repo = $(ghq list | fzf)
  Set-Location ( Join-Path $(ghq root) $repo)
}

Set-PSReadLineKeyHandler -Chord Ctrl+g -ScriptBlock { 
  ghq-fzf
  [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine() 
}

[Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine() が無いと選択後もう一度Enterを押さないと先に進まないので入れている。

これでPowerShellでもリポジトリが検索できるようになりましたとさ。

Historyも検索したい(おまけ)

ここまでやってPowerShellHistoryファイルから過去実行したコマンドを再実行できると便利なのでは、と思ったのでついでにやる。

function history-fzf {
  Invoke-Expression ((Get-Content $(Get-PSReadLineOption).HistorySavePath) | fzf)
}

Set-PSReadLineKeyHandler -Chord Ctrl+l -ScriptBlock {
  [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine()
  history-fzf 
}

PowerShellの履歴ファイルのパスは Get-PSReadLineOptionで取得できるプロパティの一つから取得できる。それをfzfで選択してInvoke-Expressionで実行するだけ。

今のままだとファイルの頭から読んでしまうので、Historyの最近実行した順番に並んでくれるとそれっぽい。fzfの --reverse オプションでうまく行かないのでどうやればいいんだろう~って考えたのが今。それと、PowerShellの関数の命名規則に疎いのでもう少ししきたりに習ってよく書けるのだろうかとも考えている。