【PowerShell】peco를 사용한 간이 런처

15733 단어 PowerShellPeco
PowerShell에서도 peco로 일본어를 다룰 수 있게 되었다 그래서 커맨드 라인에서 사용할 수있는 간단한 실행기를 만들려고합니다.

환경은 다음과 같습니다.
Name                           Value
----                           -----
PSVersion                      7.0.2
PSEdition                      Core
GitCommitId                    7.0.2
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

이러한 동작을 이미지하고 있습니다.
(1) よくアクセスするフォルダ/ファイルのパスをテキストファイルに列挙しておく
(2) 読み込んだファイルを peco でフィルタリング
  ・[ファイルを選んだ場合]→そのまま開く
  ・[フォルダを選んだ場合]→サブフォルダを再度 peco でフィルタリングして開く

실제로 코드를 작성합니다. 우선 peco 래퍼에서.
위의 기사에서 PowerShell 7로 버전을 올리면 $OutputEncoding의 기본값이 utf-8이되어 조금 설명이 짧습니다.
function psPeco {
    $origin = [System.Console]::OutputEncoding
    $utf8 = [System.Text.Encoding]::UTF8
    [System.Console]::OutputEncoding = $utf8
    $out = $input | Out-String -Stream | peco.exe "--initial-filter=Fuzzy"
    [System.Console]::OutputEncoding = $origin
    return $out
}

다음은 텍스트 파일의 로드 부분. C:\Personallaunch.txt 를 만들어 줄 바꿈으로 구분하여 경로를 작성합니다 (문자 코드는 BOM 없음 utf-8 ).
패스를 그대로 필터링하면 풀 패스에도 매치 해 버리기 때문에 조금 궁리했습니다.
  • 텍스트 파일의 각 행으로부터 필터링용의 「표시명」을 생성한다
  • 표시명은 패스의 뒤에 | 로 단락지어 지정
  • 지정하지 않았던 경우는, 패스 최하층을 표시명으로 한다

  • 표시명을 키로 한 해시 테이블을 조작하도록 한다
  • 키는 문자수순으로 정렬해 둔다(매치를 편하게 하기 위해서)

  • 존재하지 않는 경로는 제외합니다
  • function New-LaunchHashTable {
        $objArray = New-Object System.Collections.ArrayList
        Get-Content "C:\Personal\launch.txt" -Encoding utf8 | ForEach-Object {
            if ($_ -match "\|") {
                $pair = @($_ -split "\|")
                $fullPath = $pair[0]
                $displayName = $pair[1]
            }
            else {
                $fullPath = $_
                $displayName = $fullPath | Split-Path -Leaf
            }
            $objArray.Add([PSCustomObject]@{
                Name = $displayName
                Fullname = $fullPath
            }) > $null
        }
        $hashTable = [ordered]@{}
        $objArray | Where-Object {Test-Path $_.Fullname} | Sort-Object {($_.Name).Length} | ForEach-Object {
            $hashTable[$_.Name] = $_.Fullname
        }
        return $hashTable
    }
    
    launch.txt 를 아래와 같이 지정하면…

    launch.txt
    C:\Personal\tools
    C:\Personal\tools\mytool
    C:\Personal\tools\memo.txt
    C:\Personal\work\memo.txt|work_memo
    

    예상대로 로드되었습니다.

    Name 라고 표시되고 있는데 .Keys 로 키를 취득할 수 있는 것은 츳코미를 받을 것 같습니다만 사양입니다.


    마지막으로, 실제 필터링 처리입니다.
    하위 폴더 검색에서 *를 후보로 표시하는 이유는 텍스트 파일 후보에서 좁힌 폴더 자체를 열 수 있도록하기 때문입니다. 하위 폴더가 너무 많으면 Get-ChildItem-Depth 에서 검색 깊이를 지정하면 더 빨라집니다.
    function Invoke-FuzzyLauncher {
        $launchHashTable = New-LaunchHashTable
        $selected = $launchHashTable.Keys | psPeco -fuzzy | Select-Object -First 1
        if (-not $selected) {
            return
        }
        $rootDir = $launchHashTable[$selected]
    
        if (Test-Path $rootDir -PathType Leaf) {
            $targetPath = $rootDir
        }
        else {
            $subDir = @(Get-ChildItem $rootDir -Directory -Name)
            if (-not $subDir) {
                $targetPath = $rootDir
            }
            else {
                $sorted = @("*") + @($subDir | Sort-Object Length)
                $leafPath = $sorted | psPeco -fuzzy
                if (-not $leafPath) {
                    return
                }
                elseif ($leafPath -eq "*") {
                    $targetPath = $rootDir
                }
                else {
                    $targetPath = $rootDir | Join-Path -ChildPath $leafPath
                }
            }
        }
        Invoke-Item $targetPath
    }
    

    이상의 내용을 $profile 에 써 두면 터미널 기동시에 자동으로 읽어들여 사용할 수 있게 됩니다 ( z 등 짧은 앨리어스를 맞추어 두면 더욱 편리).



    2020-06-25 추가



    go로 다시 작성해 보았습니다.

    좋은 웹페이지 즐겨찾기