はじめに:Windows11のエクスプローラーが使い物にならない!
先日、Windows10のサポート終了がありました。
その影響でWindows11に移行し、使っていたのですがエクスプローラーに以下のような問題を感じました。
- 右クリックメニュー→その他の選択が必要
* officeで「新規」で開く際 - 右クリックメニューでキーボード入力が廃止されたせいで、操作性が悪い
* ソースを開くエディタを選ぶ際(サクラエディタとVisual Studioの二刀流運用をしているため)- 新しいウィンドウで開く
- 頻繁に落ちる/ハングアップする/バグがある
- タブをドラッグ&ドロップして別ウィンドウにしようとしたとき、ドラッグしていたタブが固まる
- 頻繁に遭遇するバグ:USBを接続(例:Eドライブ)し、エクスプローラーで新規タブでEドライブを開いた後別のタブにフォーカスしてからUSBを外すと、Eドライブではなくフォーカスしたタブのほうが閉じられる
これらを解消しようと思い立ち、作ったのがpowershellファイルマネージャです。
PowerShellに馴染みのない方はこちらも合わせてご覧ください。
まず成果物
方針/UI設計
まず、コンセプトとしては「快適な操作性」を一番に意識しようと考えました。特に、キーボードだけで操作できるようにしようと考えました。
また大枠の方針として、最初は主要(=自分がよく使う)機能だけ実現して、その後徐々に機能強化していこうと考えていました。
普通のpowershellでもそこそこ使える(参考)のですが、以下の点がエクスプローラーとの違いになります。(作り始める時点で把握してたもの)
- (タスクバーなどの、ファイルマネージャ以外の部分も管理している)
- ディレクトリ遷移すると、遷移先のすべてのファイル/ディレクトリが表示される
- クイックアクセスがない
- 戻る/進む機能(履歴)がない
- 複数ウィンドウを跨いだ操作ができない
- ショートカット(lnkファイル)に対応していない
- フォルダ丸ごとコピー/移動が遅い
欲しいのはファイルマネージャなので、1点目は無視できます。
方針を考えるにあたり、まず2ポチ目「ディレクトリ遷移すると、遷移先のすべてのファイル/ディレクトリが表示される」が一番の違いだと考えました。
ここだけ解決するなら、「cdするたびにlsする」関数を用意すれば解決するな、と考えました。
クイックアクセスや履歴もそんな感じの関数を作ればうまくいきそうです。
履歴だけ適当に実装したのが以下です。
Set-Alias ykcd yk-cd
Set-Alias ykbk yk-Back
Set-Alias ykfw yk-Forward
function yk-cd($path){
# YaKitori cd
Go-Dir $path
Clear-Host #オプショナル
Get-ChildItem
}
function yk-Back(){
Back-Dir
Clear-Host #オプショナル
Get-ChildItem
}
function yk-Forward(){
Forward-Dir
Clear-Host #オプショナル
Get-ChildItem
}
############履歴管理###############
$global:backStack = @()
$global:forwardStack = @()
function Go-Dir($path) {
if (Test-Path $path) {
$global:backStack += (Get-Location)
Set-Location $path
$global:forwardStack = @() # 進む履歴をクリア
} else {
Write-Host "Path not found: $path"
}
}
function Back-Dir {
if ($global:backStack.Count -gt 0) {
$global:forwardStack += (Get-Location)
Set-Location ($global:backStack[-1])
$global:backStack = $global:backStack[0..($global:backStack.Count - 2)]
} else {
Write-Host "No back history"
}
}
function Forward-Dir {
if ($global:forwardStack.Count -gt 0) {
$global:backStack += (Get-Location)
Set-Location ($global:forwardStack[-1])
$global:forwardStack = $global:forwardStack[0..($global:forwardStack.Count - 2)]
} else {
Write-Host "No forward history"
}
}
フォルダ内のファイル数が膨大な場合にスクロールが必要になるという問題は一旦目を瞑りました。
複数ウィンドウがないことについてはクリップボードを使えばひとまず対応できるとわかりました。以下のように使います。
scb (gi ./hoge.txt) # クリップボードに設定(Set-ClipBoard)、Get-Item
cd ./foo
copy (gcb) . # クリップボードを取得し(Get-ClipBoard)コピー
上の実装に以下の機能追加をしたのが完成品です。
- クイックアクセス
- officeファイルを新規で開く
- テキストファイルをどのソフトで開くか指定
- 普通にGet-ChildItemだと視認性が悪いため、ソート+アイコン表示
ファイル名あいまい検索あたりも実装したいところです。
各タブに履歴を持たせるのはなかなかややこしそうでできていません。
没になった代案
「ykcd」すら打つのが面倒だ、と考えて次のような実装も案としてはありました。
function ykfm(){
while($true){
Clear-Host
$CurrentList=Get-ChildItem
for($i=0;$i -lt $CurrentList.Count; $i++){
Write-Host "$i`t" $CurrentList[$i]
}
$num = Read-Host "number"
if(Test-path -path $CurrentList[$num] -PathType Leaf ){
ii $CurrentList[$num]
}else{
cd $CurrentList[$num]
}
}
}
この方針で実装し一時期使っていたのですが、今度は扱いたいファイルを見つけたときにその横の数字を読んで入力するのが面倒になってしまいました。
Read-Hostでtab補完を実装することもできるらしいのですが、Powershellのやるべきことの範疇を超えている感じがしたので今回は上記の形に落ち着きました。あいまい検索はバランスが取れてていい感じがします。
最後までお読みいただきありがとうございました。