ymmr
Recent Articles
    公開日: 2023/11/02

    fzf に入門して VSCode のエクスプローラから卒業する

    開発中のファイル操作をするために、大体は VSCode のエクスプローラーを使用していました。最近 fzf という CLI ツールの存在を知り、いくつかの不満を解決できたので記事にします。

    fzf とは

    fzf はインタラクティブな曖昧検索 (Fuzzy Search) ができる、UNIX 思想のフィルターツールです。フィルターとして機能する特徴から、パイプで繋ぐことにより他の UNIX ツールと容易に連携できます。以下の例では find コマンドの結果を受け取り、選択したファイルを標準出力に出力しています。

    環境構築

    以下の環境を使用しました。

    MacOS: 14.1 (23B74)
    zsh: zsh 5.9 (x86_64-apple-darwin23.0)

    まずは fzf と fd をインストールします。ここで fd という別のツールが出てきますが、ファイル探索の候補から node_module などの不要フォルダーを除外する1ために使用します。

    brew install fzf
    brew install fd
    
    # ファイル検索に fd を使い、任意のフォルダーを検索対象から外す。
    export FZF_DEFAULT_COMMAND='fd --hidden --exclude .git --exclude node_modules --exclude .next'
    export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
    

    fzf とタイプするか <Ctrl+t> でファイル検索ができるようになりました。

    エクスプローラーの操作を置き換える

    長いこと VSCode のエクスプローラーを使う中でいくつかの不満2を抱えていました。以下で挙げる、よく使う操作を Z Shell の関数で置き換えていきます。

    • ファイルを開く
    • ファイルの作成
    • フォルダーの作成
    • ファイル・フォルダーの削除
    • ファイル・フォルダーのリネーム
    • ファイル・フォルダーの移動

    記事内では 2 つの関数に絞って紹介します。ちなみに "ファイル・フォルダーの移動" はモジュールの import に影響するため、今後もエクスプローラを使います。早速 "ファイル・フォルダーの削除" から見ていきましょう。

    ~/.zshrc
    # ファイル・フォルダーの削除
    frm() {
      # fzf -m で複数ファイルを選択できる様にする。選択されたファイルは rm コマンドに渡す。
      fzf -m | xargs rm -rf
    }
    

    続いて扱う "ファイルを開く" と "ファイルの作成" は少し考慮することが多いです。利便性のため、引数に応じて振る舞いを変えることにしました。

    .~/.zshrc
    # ファイルを開く / ファイル・フォルダーの作成
    fcode() {
      # 引数を受け取った場合
      if [[ "$#" -ne 0 ]]; then
        dir="$(fd -t d | fzf)"
      # index.{tsx,test.tsx,css} の様に brace expression で使うことを想定して、複数ファイルを扱えるようにする。
        for file_name in "$@"; do
          full_path="${dir}${file_name}"
          # ファイルが既に存在すれば、そのファイルを開く
          if [[ ! -e "$full_path" ]]; then
            code "$full_path"
          fi
          # ファイルが存在しなければ、新規作成する
          touch "$full_path" && code "$full_path"
        done
      # 引数を受け取らなかった場合
      else
        target="$(fzf)"
        # フォルダーが選択された場合、配下のファイルをすべて開く
        if [[ -d "$target" ]]; then
          code -a $target/**/*
        # ファイルが選択された場合、そのファイルを開く
        elif [[ -f "$target" ]]; then
          code "$target"
        fi
      fi
    }
    

    なかなか使いやすいです!

    最終的にいくつかの関数を追加する形で落ち着きました。現時点の .zshrc は Gist に公開しています。

    .zshrcGitHub Gist: instantly share code, notes, and snippets.gist.github.com

    おわりに

    fzf は Go で書かれているらしく、驚くほど高速です。パイプとして機能する特徴から、今回のような用途だけでなく幅広く活躍できるツールだと思いました。

    Footnotes

    1. https://github.com/junegunn/fzf#respecting-gitignore

    2. 検索が使いにくい。階層が深くなると視認性が悪くなる。