LoginSignup
6
1

More than 3 years have passed since last update.

LeaderF の紹介

Last updated at Posted at 2020-04-12

LeaderF とは

候補一覧を雑に絞り込んでコマンドを実行できるプラグインです。
似たようなプラグインには Denite.nvim や ctrlp.vim などがあります。

LeaderF の作者は、インデントの可視化をするプラグインの indentLine も作っている Yggdroot さんです。

leaderf.gif

README に実際に LeaderF を使っている動画が載っています。

インストール方法

Plug を使っている場合、以下のようにインストールします。

" Linux、Mac の場合
Plug 'Yggdroot/LeaderF', { 'do': './install.sh' }

" Windows の場合
Plug 'Yggdroot/LeaderF', { 'do': '.\install.bat' }

LeaderF は Python を使って実装されているため、Vim で Python が有効になっている必要があります。
この記事では Python を有効にする方法は解説しませんので、他の記事を参考にしてください。

設定

LeaderF にはアイコン表示の機能がありますが、正しく表示されない場合、以下のように設定してください。

set ambwidth=double

また、アイコンを表示しないようにするには、以下のように設定してください。

let g:Lf_ShowDevIcons = 0

使い方

操作の流れ

  1. :LeaderF カテゴリ で LeaderF を起動
  2. 絞り込み
  3. コマンドを実行

:Leaderf buffer とすると現在開いているバッファの一覧、:Leaderf command とするとExコマンドの一覧が表示されます。

:Leaderf buffer --popup とすることでポップアップで表示することも可能です。
また、LeaderF の各カテゴリにはたくさんのオプションがあるため、:Leaderf カテゴリ --help で実際に使用できるオプションを確認してみてください。

カテゴリ一覧

LeaderF が標準で使用可能なカテゴリは以下になります。

カテゴリ名 説明
file ファイル
tag tags ファイル内の候補
function バッファ内の関数
mru 最近、開いたファイル
searchHistory 検索履歴
cmdHistory コマンド実行履歴
help help のタグ
line カレントバッファの行
colorscheme カラースキーマ
gtags gtags を使った候補
self LeaderF で使用可能なカテゴリ
bufTag カレントバッファ内の tags ファイル内のシンボル
buffer バッファ
rg rg を使った検索
filetype ファイルタイプ
command Exコマンド
window 開かれているウィンドウ.

マッピング

LeaderF のインサートモードではマッピングが定義されており、それをもとに操作を行います。

インサートモードのマッピング

インサートモードでのマッピングは以下のようになっています。

基本

マッピング 説明
<C-C>
<ESC>
LeaderF を終了
<C-R> Fuzzy モード <-> Regex モード
<C-F> フルパスモード <-> ファイル名モード
<Tab> ノーマルモードに移行
<C-V>
<S-Insert>
クリップボードの文字を貼り付け
<C-J> 結果ウィンドウのカーソルを下に移動
<C-K> 結果ウィンドウのカーソルを上に移動
<F5> キャッシュをクリア

コマンド関連

マッピング 説明
<CR>
<2-LeftMouse>
カーソル下の候補を開く
<C-X> カーソル下の候補を水平分割で開く
<C-]> カーソル下の候補を垂直分割で開く
<C-T> カーソル下の候補を新しいタブで開く

プロンプト内のカーソル操作関連

マッピング 説明
<BS> カーソル左の文字を削除
<Del> カーソル右の文字を削除
<C-U> カーソルより左をすべて削除
<C-W> カーソルより左の単語を削除
<Home> カーソル位置を先頭に移動
<End> カーソル位置を末尾に移動
<Left> カーソル位置を1つ左に移動
<Right> カーソル位置を1つ右に移動
<Up>/<Down> プロンプトの履歴を操作

選択関連

マッピング 説明
<C-LeftMouse>
<C-S>
カーソル下の候補を選択
<S-LeftMouse> 複数候補を選択
<C-A> すべての候補を選択
<C-L> 選択している候補を解除

プレビュー関連

マッピング 説明
<C-P> カーソル下の候補をプレビュー
<C-Up> ポップアップのプレビュー内を上にスクロール (neovim のみ)
<C-Down> ポップアップのプレビュー内を下にスクロール (neovim のみ)

※ カテゴリが cmdHistorysearchHistorycommand には専用のコマンドがあり、<C-e>カーソル下の候補の編集が行なえます。

マッピング 説明
<C-o> カーソル下の候補を編集 (cmdHistory/searchHistory/command のみ)

ノーマルモードのマッピング

インサートモードで <Tab> を入力することでノーマルモードになります。
ノーマルモードの場合、通常のマッピング + LeaderF が定義しているマッピングが使用できます。

この記事では基本的なマッピングのみ紹介します。
カテゴリによって、実行できるコマンドは異なるため、詳しくはノーマルモードで <F1> を押し、ヘルプを見てください。

基本的なマッピング

マッピング 説明
q LeaderF を終了
<CR>
o
<2-LeftMouse>
カーソル下の候補を開く
i
<Tab>
インサートモードに移行
<F1> ヘルプの表示

検索モードについて

Regex モード

正規表現で検索できます。

Fuzzy モード

あいまい検索ができます。

フルパスモード と ファイル名モード (Fuzzy モードのみ)

カテゴリによっては、フルパスモードとファイル名モードを持っているものがあります。

フルパスモードを使うことで

  • file.txt というファイル名で、dir1 というディレクトリに入っているものを検索できます。

といったことができるようになります。

以下のカテゴリにはフルパスモードが使えます。

  • buffer
  • file
  • mru
  • window

フルパスモードを使うには2つの方法があります。

  • インサートモードで <C-F> を入力し、フルパスモードを有効にする。
  • プロンプトで ファイル名;パス のように入力する。
    • abc;def と入力した場合、ファイル名に abc が入り、パスに def が入る候補が絞り込まれます。

and 検索 (Fuzzy モードのみ)

プロンプトへの入力をスペース () でキーワードを区切ることで、and 検索することができます。

カスタマイズ方法

ここからは LeaderF をカスタマイズする方法について書きます。

インサートモードでのマッピング

インサートモードのマッピングは g:Lf_CommandMap でカスタマイズすることが可能です。

例えば、履歴の操作の <Up><Down><C-p><C-n> にしたい場合、以下のように設定します。

let g:Lf_CommandMap = {
\   '<Up>':     ['<C-p>'],
\   '<Down>':   ['<C-n>'],
\   '<C-p>':    ['<C-q>'],
\}

また、デフォルトの <C-p>カーソル下の候補をプレビューとなっているので、<C-q> にマッピングしています。

定義方法が map コマンドと逆なので、注意してください。(map の場合、nnoremap <C-p> <Up> のようになります。)

:Leaderf file:Leaderf rg での起点となるディレクトリの設定

g:Lf_WorkingDirectoryMode で設定できます

指定できる値は以下の5つになります。

説明
c カレントディレクトリから検索
a カレントディレクトリよりも上に g:Lf_RootMakers があれば、そのディレクトリから検索。
なければ、c と同じ
A カレントバッファのディレクトリよりも上に g:Lf_RootMakers があれば、そのディレクトリから検索。
なければ、c と同じ
f カレントバッファのディレクトリ
F カレントバッファのディレクトリがカレントディレクトリの下にない場合、f と同じ

g:Lf_RootMakers はデフォルトで ['.git', '.hg', '.svn'] が設定されています。

F の挙動について、カレントバッファのディレクトリが C:/tmp/dir1/sub で、カレントディレクトリが C:/tmp2 だった場合、カレントバッファのディレクトリ (C:/tmp/dir1/sub) から検索されます。

設定例

私の設定を紹介します。

設定例
nnoremap [Leaderf] <Nop>
nmap     <Space>f [Leaderf]

" ! をつけるとノーマルモードから始まる
nnoremap          [Leaderf]g        :<C-u>Leaderf! rg --match-path -e ""<Left>
nnoremap <silent> 0                 :<C-u>Leaderf  rg --next<CR>
nnoremap <silent> 9                 :<C-u>Leaderf  rg --previous<CR>
nnoremap <silent> [Leaderf]r        :<C-u>Leaderf! rg --recall<CR>
nnoremap <silent> [Leaderf];        :<C-u>Leaderf  cmdHistory<CR>
nnoremap <silent> [Leaderf]f        :<C-u>Leaderf  file<CR>
nnoremap <silent> [Leaderf]h        :<C-u>Leaderf  help<CR>
nnoremap <silent> [Leaderf]j        :<C-u>Leaderf  buffer<CR>
nnoremap <silent> [Leaderf]k        :<C-u>Leaderf  mru --nowrap<CR>
nnoremap <silent> [Leaderf]t        :<C-u>Leaderf  filetype<CR>
nnoremap <silent> [Leaderf]w        :<C-u>Leaderf  window<CR>
nnoremap <silent> [Leaderf]l        :<C-u>Leaderf  line<CR>
nnoremap <silent> [Leaderf]s        :<C-u>Leaderf  bufTag<CR>

nnoremap <silent> <Space><Space>    :<C-u>Leaderf command --run-immediately<CR>
nnoremap <silent> <Space>ml         :<C-u>Leaderf filer ~/memo<CR>

" Reference
nnoremap <silent> gr                :<C-u><C-r>=printf('Leaderf! rg --match-path -e "%s" -w -F', expand('<cword>'))<CR><CR>
vnoremap <silent> gr                :<C-u><C-r>=printf('Leaderf! rg --match-path -e %s -w -F', leaderf#Rg#visual())<CR><CR>


function! s:leaderf_settings() abort
    silent! setlocal signcolumn=no
    silent! setlocal scrolloff=0
endfunction


augroup MyLeaderf
    autocmd!
    autocmd Filetype leaderf call <SID>leaderf_settings()
augroup END


" デフォルト
let g:Lf_DefaultMode = 'NameOnly'

" カーソルの点滅をなくす
let g:Lf_CursorBlink = 0

" ステータスラインのカラースキーム
if g:colors_name ==# 'one'
    let g:Lf_StlColorscheme = 'one'
else
    let g:Lf_StlColorscheme = 'default'
endif


" 検索に使う外部ツール
let g:Lf_DefaultExternalTool = 'rg'

" カレントバッファの名前を結果に表示しない (Leaderf file のみに有効)
let g:Lf_IgnoreCurrentBufferName = 1

let g:Lf_MruMaxFiles = 1000

" ヘルプを非表示
let g:Lf_HideHelp = 1

" カレントディレクトリよりも上に `g:Lf_RootMakers` があれば、そのディレクトリから検索
" なければ、カレントディレクトリから検索
let g:Lf_WorkingDirectoryMode = 'a'

" 履歴を3000
let g:Lf_HistoryNumber = 3000

" 表示を上下逆にする
let g:Lf_ReverseOrder = 1

" 結果ウィンドウの高さ
let g:Lf_WindowHeight = 0.4

" LeaderF ウィンドウを下に表示
let g:Lf_WindowPosition = 'bottom'

" history で除外する
let g:Lf_HistoryExclude = {
\   'cmd':  ['^wq?!?$', '^qa?!?$', '^.\s*$', '^\d+$'],
\   'search':  []
\}

" file カテゴリで除外するパターン
let g:Lf_WildIgnore = {
\   'dir': ['**/.mypy_cache/*', 'node_modules/*', '*.pyc'],
\   'file': ['tags']
\}

" 詳しくは Leaderf rg --help を見て
" --glob は .gitignore のような書き方で、複数かける
let g:Lf_RgConfig = [
\   '--smart-case',
\   '--glob=!*/.mypy_cache/*',
\   '--glob=!.node_modules/*',
\   '--glob=!tags*',
\]

" ステータスラインの区切り文字をなくす
let g:Lf_StlSeparator = { 'left': '', 'right': '' }

" ノーマルモードのカスタマイズ
let g:Lf_NormalMap = get(g:, 'Lf_NormalMap', {})


" <C-r> : 検索切り替え: fuzzy / regex 
" <C-f> : 検索切り替え: fullpath / name only
" <Tab> : モード切替: Normal / Insert
" <C-v> : クリップボードから貼り付け
" <C-u> : <C-u>
" <C-j> <C-k> : 上下移動
" <Up> <Down> : 履歴操作
" <CR>  : 開く
" <C-x> : horizonal split で開く
" <C-]> : vertical split で開く
" <C-t> : タブ で開く
" <F5>  : キャッシュ更新
" <C-s> : 複数ファイル選択
" <C-a> : 全ファイル選択
" <C-l> : 全ファイル選択の解除
" <BS>, <C-h>  : 前の文字削除
" <Del> : 後ろの文字削除
" <Home> : 先頭へカーソル移動
" <End>  : 末尾にカーソル移動
" <Left> : 左にカーソル移動
" <Right> : 右にカーソル移動
" <C-p> : プレビュー表示

" cmdHistory/searchHistory/command
" <C-o> : 編集

" ~/vimfiles/plugged/LeaderF/autoload/leaderf/python/leaderf/cli.py を見てね
" key <- value (value を key として解釈させる)
let g:Lf_CommandMap = {
\   '<Up>':     ['<C-p>'],
\   '<Down>':   ['<C-n>'],
\   '<C-v>':    ['<C-o>'],
\   '<C-x>':    ['<C-s>'],
\   '<C-]>':    ['<C-v>'],
\   '<C-p>':    ['<C-q>'],
\   '<C-o>':    ['<C-e>'],
\   '<Del>':    ['<C-d>'],
\   '<C-s>':    ['<C-x>'],
\}


let g:Lf_StlPalette = {
\   'stlName': {
\       'gui': 'bold',
\       'font': 'NONE',
\       'guifg': '#2F5C00',
\       'guibg': '#baf2a3',
\       'cterm': 'bold',
\       'ctermfg': 'NONE',
\       'ctermbg': 'NONE'
\   },
\   'stlCategory': {
\       'guifg': '#4d4d4d',
\       'guibg': '#c7dac3',
\       'gui': 'NONE',
\       'font': 'NONE',
\       'ctermfg': '239',
\       'ctermbg': '151',
\       'cterm': 'NONE',
\   },
\   'stlNameOnlyMode': {
\       'guifg': '#4d4d4d',
\       'guibg': '#c9d473',
\       'gui': 'NONE',
\       'font': 'NONE',
\       'ctermfg': '239',
\       'ctermbg': '186',
\       'cterm': 'NONE',
\   },
\   'stlFullPathMode': {
\       'guifg': '#4d4d4d',
\       'guibg': '#dbe8cf',
\       'gui': 'NONE',
\       'font': 'NONE',
\       'ctermfg': '239',
\       'ctermbg': '187',
\       'cterm': 'NONE',
\   },
\   'stlFuzzyMode': {
\       'guifg': '#4d4d4d',
\       'guibg': '#dbe8cf',
\       'gui': 'NONE',
\       'font': 'NONE',
\       'ctermfg': '239',
\       'ctermbg': '187',
\       'cterm': 'NONE',
\   },
\   'stlRegexMode': {
\       'guifg': '#4d4d4d',
\       'guibg': '#acbf97',
\       'gui': 'NONE',
\       'font': 'NONE',
\       'ctermfg': '239',
\       'ctermbg': '144',
\       'cterm': 'NONE',
\   },
\   'stlCwd': {
\       'guifg': '#595959',
\       'guibg': '#e9f7e9',
\       'gui': 'NONE',
\       'font': 'NONE',
\       'ctermfg': '240',
\       'ctermbg': '195',
\       'cterm': 'NONE',
\   },
\   'stlLineInfo': {
\       'guifg': '#595959',
\       'guibg': '#e9f7e9',
\       'gui': 'NONE',
\       'font': 'NONE',
\       'ctermfg': '240',
\       'ctermbg': '195',
\       'cterm': 'NONE',
\   },
\   'stlTotal': {
\       'guifg': '#4d4d4d',
\       'guibg': '#c7dac3',
\       'gui': 'NONE',
\       'font': 'NONE',
\       'ctermfg': '239',
\       'ctermbg': '151',
\       'cterm': 'NONE',
\   }
\ }


if g:colors_name =~# '^solarized8'
    let g:Lf_StlPalette.stlBlank = {
    \   'gui': 'NONE',
    \   'font': 'NONE',
    \   'guifg': '#073642',
    \   'guibg': '#eee8d5',
    \   'cterm': 'NONE',
    \   'ctermfg': 'NONE',
    \   'ctermbg': 'NONE'
    \}
elseif g:colors_name ==# 'one'
    let g:Lf_StlPalette.stlBlank = {
    \   'gui': 'NONE',
    \   'font': 'NONE',
    \   'guifg': '#494b53',
    \   'guibg': '#e1e1e1',
    \   'cterm': 'NONE',
    \   'ctermfg': 'NONE',
    \   'ctermbg': 'NONE'
    \}
endif


let g:Lf_PreviewResult = {
\   'File': 0,
\   'Buffer': 0,
\   'Mru': 0,
\   'Tag': 0,
\   'BufTag': 0,
\   'Function': 0,
\   'Line': 1,
\   'Colorscheme': 1,
\   'Rg': 0,
\   'Gtags': 0
\}

" アイコンの追加
let g:Lf_DevIconsExactSymbols = {
\   'vimrc':  '',
\   'gvimrc': '',
\   'tags':   '󿧸',
\}

let g:Lf_DevIconsExtensionSymbols = {
\   'lock': '󿫺',
\   'vue':  ''
\}


Tips

ノーマルモードから開始する

! をつける

:Leaderf! rg -e "function"

:Leaderf command で引数なしのコマンドだったらすぐ実行する

--run-immediately を使います

:Leaderf command --run-immediately

:Leaderf rg でファイルパスも絞り込み対象に入れる

--match-path を使います

:Leaderf rg --match-path -e "function"

:Leaderf rg で単語検索する

-w を使います

:Leaderf rg -e "pattern" -w

hello pattern world はマッチするけど、hellopatternworld はマッチしなくなります。

:Leaderf rg でリテラル検索する

-F を使います

:Leaderf rg -e "exists('*" -F

おわりに

以上が LeaderF の紹介になります。LeaderF を使うことで、さまざまなものを同じインターフェースで扱えるため、とても便利になると思います。
この記事をきっかけとして使っていただけると嬉しいです!

また、LeaderF はカテゴリを自作するための仕組みも用意されているため、自分で拡張することもできます。VimScript と Python を使って拡張することが可能です。
最後に、宣伝になりますが LeaderF-filer というファイラーを作っていますので、よろしければ使ってみてください。

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1