LeaderF とは
候補一覧を雑に絞り込んでコマンドを実行できるプラグインです。
似たようなプラグインには Denite.nvim や ctrlp.vim などがあります。
LeaderF の作者は、インデントの可視化をするプラグインの indentLine も作っている Yggdroot さんです。
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
使い方
操作の流れ
-
:LeaderF カテゴリ
で LeaderF を起動 - 絞り込み
- コマンドを実行
: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 のみ) |
※ カテゴリが cmdHistory
と searchHistory
と command
には専用のコマンドがあり、<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 というファイラーを作っていますので、よろしければ使ってみてください。