1぀のプラグむンの歎史


それはすべお、 タグバヌが私のために機胜しなくなったずきに始たりたした 。 プラグむンが゚ラヌでクラッシュしたした。おそらく、珟圚のExuberant CtagsのバヌゞョンはExuberantではありたせん。 ゜ヌスを少し調べおみるず、最埌の倖郚コマンドが゚ラヌで終了しおいるこずがわかりたした。vshell_errorは -1を返したした 。 さらに掘り䞋げずにfzfをむンストヌルしたした 。 Fzfはctrlpず同様に、ファむル、タグ、バッファヌなどでファゞヌ怜玢を実行できたすが、埌者ずは異なり、マむナスなしではなくはるかに高速に動䜜したす。 アプリケヌションは端末で盎接動䜜し、毎回入力コマンドの履歎を䞊曞きしたす。 これは、たずえば、目的のタグを怜玢するずきに、メむンバッファヌの右偎にあるバッファヌ䞀郚のスクリヌンキャストで刀断しお、 neovim に怜玢結果を衚瀺できないこずも意味したす。 厇高なものずは異なり、 fzfはファむル名にそれ以䞊の重みを付けたせん。そのため、私は期埅しおいた結果がトップに衚瀺されないこずがよくありたした。 その䞊、配色を調敎する完党な自由の欠劂は、䞀般に平均的なナヌザヌにずっおはあたり重芁ではありたせんが、私にずっおは现郚ぞの泚意が増しおいたす。 自由ずは、少なくずも、通垞の通垞のテキストずク゚リ文字列の色の区別を意味したす。


これらすべおのこずから、暙準のディレクトリビュヌアヌnetrwに䌌た独自のプラグむンを䜜成する必芁がありたした 。 この経隓が誰かに圹立぀かもしれないず信じお、私が遭遇した問題ずそれらを解決する方法を説明したす。


Vimスクリプト蚀語


たず、vimスクリプトで最初の䞀歩を螏み出しおいる人のために短いツアヌを提䟛したいず思いたす。 倉数には接頭蟞がありたす;あなたはすでにそれらのいく぀かを芋、曞いおいたす。 通垞、プラグむンは、 gプレフィックスを持぀グロヌバル倉数を䜿甚しお構成されたす。 プラグむンを䜜成するずきは、 sプレフィックスを䜿甚するこずが適切です。これにより、倉数がスクリプト内でのみ䜿甚可胜になりたす。 関数の匕数にアクセスするには、 aプレフィックスを䜿甚したす。 接頭蟞のない倉数は、宣蚀された関数に察しおロヌカルです。 プレフィックスの完党なリストは、次のコマンドで衚瀺できたすhelp internal-variables 。


バッファを管理するための2぀の非垞に単玔な関数、 getlineずsetlineがありたす。 圌らの助けを借りお、怜玢結果をバッファに貌り付けるか、ク゚リ倀を取埗できたす。 名前から倚くの堎合それが䜕をするのかはっきりしおいるので、私は各関数の説明にはこだわらないでしょう。 この蚘事のほがすべおのキヌワヌドはドキュメントに蚘茉されおいたす。したがっお、 help getlineたたはhelp setlineですが、党䜓像に぀いおは、 セクションごずにグルヌプ化されたすべおの関数のリストを含むhelp function-listを参照するこずをお勧めしたす。


むベント


Vimはすぐに䜿甚できる倚くのむベントを提䟛したすが、独自のプラグむンを䜜成する堎合は、独自のむベントを䜜成する必芁がありたす。 幞いなこずに、これは非垞に簡単に行われたす。


//   CustomEvent autocmd User CustomEvent call ... //   ,   "No matching autocommands",         if(exists("#User#CustomEvent")) doautocmd User CustomEvent endif 

オヌトロヌド


プラグむンのすべおの関数に、 finderプレフィックスを蚭定したす。 これは組み蟌みのvim autoloadメカニズムで、同じ名前の目的のファむルのruntimepathを怜玢したす。 finder関数の呌び出しはruntimepath / finder.vimファむルにあり、 finderファむルのindex関数はruntimepath / finder / files.vimファむルにありたす。 次に、プラグむンをruntimepathに远加する必芁がありたす。


 set runtimepath+=path/to/plugin 

ただし、 vim-plugなど、これらの目的にはプラグむンマネヌゞャヌを䜿甚するこずをお勧めしたす。


耇合チヌム


倚くの堎合、チヌムが異なる郚分から結合されるか、倉数の倀を挿入する必芁がある堎合に発生したす。 これらの目的のために、vimには実行コマンドがあり、これは倚くの堎合、 printf関数ずずもに䜿甚するず䟿利です。


 execute printf('syntax match finderPrompt /^\%%%il.\{%i\}/', b:queryLine, len(b:prompt)) 

始めたしょう


したがっお、必芁なのはク゚リ文字列ず怜玢結果だけです。 入力関数はvimのナヌザヌ入力を担圓したすが、私が知る限り、入力行を䞀番䞊に配眮するこずはできたせん。タグで怜玢するこずは、ファむルに衚瀺されおいる順序でタグを衚瀺する方が䟿利なので、これは非垞に重芁です。 さらに、時間が経぀に぀れお、netrwを瀺す同様の垜子を䜜るこずにしたした 。 入力行はバッファに実装する必芁があり、ここで最初の問題が発生したした。


リク゚スト


リク゚ストの倀を取埗するには、入力フィヌルドずツヌルチップに盞察的なオフセットが配眮されおいる行を知り、 TextChangedIむベントのハンドラヌを蚭定する必芁がありたす。 以前にプログラミングしたこずがある人は、この段階で耇雑なものは䜕もないはずなので、コヌドは省略したす。 ハンドラヌを<buffer>属性でハングアップする必芁があるこずを远加したす。


 autocmd TextChangedI <buffer> call ... 

プロンプト


ツヌルチップはナヌザヌ入力ず同じ行にあるため、䜕らかの方法で修正する必芁がありたす。 これらの目的のために、<BS>や<Del>などのキヌの動䜜を担圓するバックスペヌスオプションの倀をクリアするこずができたす。 特に、私はeolずstartにのみ興味がありたした。 Eolは行末蚘号の削陀を蚱可し、それに応じお文字列のマヌゞを蚱可したすが、startは挿入モヌドの開始埌に入力されたテキストのみの削陀を蚱可したす。 それは非垞に䟿利で簡単に刀明したした。たずえば、「Files>」ずいうプロンプトを挿入し、テキストを入力し始めるず、テキストを削陀しおもプロンプトはそのたた残りたした。 確かに、私は1぀の点を考慮したせんでした-そのようなプラグむンの操䜜のために、倚くのロゞックが必芁であり、通垞モヌドに行くこずは䞀般的な習慣でした。 どのマッピングでも新しい「セッション」を簡単に開始でき、以前に入力されたテキストは削陀されなくなりたした。 たずえば、<Esc>を抌すだけでした。


 inoremap <Cj> <Esc>:call ... 

<BS>のマッピングを䜜成し、テキストを手動で削陀する必芁がありたした。


 inoremap <buffer><BS> <Esc>:call finder#backspace()<CR> 

カヌ゜ルの奇劙なちら぀きがいく぀かあり、時間が経぀に぀れおひどく迷惑になりたした。 障害がコマンドラむンモヌドぞの移行であるこずに気づくたでに長い時間がかかりたした。通垞は、 を抌しお開始したす。 この瞬間、テキストの䞊のカヌ゜ルが消えたす。 ちら぀き効果は匷く、呌び出される関数は「より重い」。 TextChangedIむベントでハンドラヌをハングさせる詊みがあり、珟圚のカヌ゜ル䜍眮を確認したした。カヌ゜ルがツヌルチップに危険なほど近づいた堎合、必芁なのは<BS>が䜕もしないようにするこずだけでした。 残念ながら、時々1文字が削陀されたす。 しばらくしお、解決策が芋぀かりたした-属性<expr> 。


 map {lhs} {rhs} 

{rhs}は有効な匏help expression-syntaxであり、その結果はバッファヌに挿入されたす。 <BS>や<Ch>などの特殊キヌは二重匕甚笊で囲み、 \ help expr-quote文字で゚スケヌプする必芁がありたす。


 inoremap <expr><buffer><BS> finder#canGoLeft() ? "\<BS>" : "" inoremap <expr><buffer><Ch> finder#canGoLeft() ? "\<BS>" : "" inoremap <expr><buffer><Del> col(".") == col("$") ? "" : "\<Del>" inoremap <expr><buffer><Left> finder#canGoLeft() ? "\<Left>" : "" 

出口


バッファヌを終了するには、<Esc>をバむンドできたす。 䞍快な瞬間は、いく぀かのキヌの組み合わせが<Esc>ず同じ文字のシヌケンスで始たるこずです。 入力モヌドに入り、<Cv>を抌しおから矢印のいずれかを抌すず、 ^ [がプレフィックスずしお衚瀺されたす。 たずえば、巊矢印の堎合、端末は^ [ODを vimに送信したす。 したがっお、矢印たたは<S-Tab>を抌すず、vimは<Esc>によっお割り圓おられたアクションを実行し、残りの文字を解釈しようずしたす。巊矢印の堎合、これは䞊郚Oに空行を挿入し、同じ文字に倧文字の「D」を挿入したす行。 esckeysオプションは、シヌケンスが入力モヌドで<Esc>で始たる堎合、぀たり^ [で始たる堎合、新しい文字が到着するこずを期埅するかどうかを瀺したす。 䜕が必芁なように芋えたすが、<Esc>の動䜜を倉曎しない堎合にのみ機胜したす。


-

これはあなたのゞョヌク、芪愛なるIDEナヌザヌかもしれたせん。


おそらく䜕かを芋逃したかもしれたせんが、さたざたなリ゜ヌスでこのキヌの動䜜を倉曎しないこずをお勧めするこずは無駄ではありたせん。 <S-Tab>がそれほど重芁でない堎合は、矢印をバむンドしお次/前の出珟を遞択するずよいでしょう。 したがっお、<Esc>の代わりに、 InsertLeaveむベントを䜿甚したす。 これには新たな課題が䌎いたす。 入力モヌドを終了せずに関数を呌び出す方法は ドキュメントを読んでいるず、興味深い点が1぀芋぀かりたした。InsertLeaveむベントを発生させずに挿入モヌドを終了する<Ctrl-c>の組み合わせですが、マッピングに<Cc>が存圚する堎合、これは機胜せず、 InsertLeaveがポップアップしたす。 むンタヌネットをサヌフィンしおいるずきに、䞀般的な芋解を瀺す解決策が芋぀かりたした。


 inoremap <BS> <Cr>=expr<CR> 

ドキュメントから、これは匏レゞスタであるこずがわかりたす 。 匏の結果がバッファに挿入されたこずを陀いお、これはたさに私が必芁ずしたものです。 実際、すべおの身䜓の動きは挿入モヌドで発生するため、これはプラグむン党䜓が構築される堎所です。 各関数で空の文字列を返さないようにこれが行われない堎合、関数は0を返したす、目的の関数を呌び出す䞭間䜓を䜿甚するこずにしたした。


 function! finder#call(fn, ...) call call(a:fn, a:000) return "" endfunction 

a名前空間は関数の匕数ぞのアクセスを担圓し、 a000倉数にはオプションのパラメヌタヌのリストが含たれたす。 入力モヌドを終了せずにアプリケヌションロゞックを蚘述できるようになったため、 backspaceオプションを䜿甚できたす。 ただし、埌で孊んだように、このオプションの倀をリセットするずdelimitMateが怒り 、そのため正垞に機胜しなくなり、これらの詊みを䞭止するこずにしたした。


バック゚ンド


ただ䜕もありたせん、私たちはすでにたくさんの無駄なピクセルを持っおいたす。 バッファに寿呜を远加したす。 vimスクリプトを高速蚀語や耇雑なものを曞くのが良い蚀語ず呌ぶのは難しいので、Dでバック゚ンドを曞くこずにしたした。ファゞヌ怜玢が必芁なので 実装するのが面倒 必芁ありたせん。正確な発生を考慮した怜玢です。゜ヌス文字列ずナヌザヌのリク゚ストを文字ごずに比范するこずを決定したした。これは正芏衚珟を䜿甚するよりもはるかに高速だず信じおいたした。 実際に4぀のモヌドがあったこずを考えるず、^ク゚リ、ク゚リ、ク゚リ$、^ク゚リ$、コヌドは少し魅力的ではありたせんでした。 私が曞いたものを芋お、すべおを削陀しお定期的に怜玢したいずいう芁望がありたした。 しばらくしお、私は自分が曞いたものが暙準のUnixツヌルを䜿甚しお実行できるこずに気づき、最初から考えおいたgrepの䜿甚に戻るこずにしたしたが、「耇雑な」ロゞックの存圚により砎棄したした。 問題は、ファむル名で怜玢し、ファむルパスの長さで䞊べ替え、元の文字列ではなく、そのむンデックスを衚瀺する必芁があるこずでした。 UnixのgrepがDにあるstd.regexよりも4倍高速であるこずが刀明したこずは泚目に倀したす。


  1. ファむル名を取埗するには、プログラムbasenameを䜿甚できたすが、残念なこずに、暙準入力ストリヌムを読み取らず、パラメヌタを盎接操䜜するだけです。 sed 's !. * / !!'も䜿甚できたす。 すべおを最埌たでカットしたす。 vim組み蟌み関数fnamemodifyも適しおいたす。


  2. 独自の拡匵機胜を実装しお䜜成する方が簡単なので、vimツヌルを䜿甚しお䞊べ替えを行うこずにしたした。 sort関数は、 コンパレヌタを蚘述する必芁がある゜ヌトを担圓したす。


  3. むンデックスを衚瀺するには、 grepで-nフラグを䜿甚したす。これは、行番号を衚瀺したす。圢匏はnlineであり、解析が容易です。

カヌ゜ルのちら぀き


䞀般的に、これは私がかなり嫌いなこずです。 カヌ゜ルのちら぀きは、 incsearchオプションを蚭定するこずで確認できたす。 バッファ内で䜕かを探しお、入力䞭にカヌ゜ルをたどっおください。 <BS>の動䜜が倉曎されおすべおが明確になった堎合、どこにでも<expr>を曞き蟌むこずはできたせん。 このフラグは、カヌ゜ルが眮かれおいる行以倖の行の倉曎を犁止したす。 したがっお、ロゞックの残りの郚分では、䞊蚘の匏レゞスタが䜿甚されたす 。これは、 のように、匏の期間䞭カヌ゜ルを珟圚の䜍眮から削陀したす。 数千のファむルの怜玢には時間がかかるため、各文字を印刷するずきにカヌ゜ルが点滅する効果が珟れたす。 非ブロッキングvim、特にtimer_start関数が時間内に到着したこずを蚀わなければなりたせん。 バッファが非同期的に描画され始めたずき、問題はなくなりたした。 最良の解決策ではない、ず蚀わざるを埗ないが、より適切なものは芋぀けられなかった。 これが、プラグむンがvim 8バヌゞョンを必芁ずする唯䞀の理由です。


プレビュヌをしなければならなかったずきに、問題が3回目に远い぀いた。 いずれかのバッファのカヌ゜ル䜍眮が倉曎され、画面が描画された瞬間にカヌ゜ルが点滅したした。 「カヌ゜ルの䞋のキャラクタヌを匷調する構文」が䞍可欠であり、そのような詐欺をより良い時たで残すこずに決めたした。


痕跡に気づく


バッファヌの内容は絶えず倉曎されおいるため、 タブラむンはバッファヌが倉曎されたこず、および入力モヌドでの操䜜に察応する巊䞋の衚蚘が衚瀺されるこずを瀺したす。 あなたのこずは知りたせんが、私はミニマルなデザむンが奜きです。そのようなものを削陀したいず思いたす。 たた、 ルヌラヌずstatuslineを非衚瀺にするず䟿利です。 vimがバッファ内の倉曎を監芖しないようにするには、 buftypeオプションを䜿甚できたす。


 setlocal buftype=nofile 

ステヌタスラむン、ルヌラヌ、碑文-- INSERT --では、衚瀺を担圓するオプションがグロヌバルであるため、少し耇雑です。぀たり、バッファヌを終了するずきに以前の倀を埩元する必芁があるためです。 OptionSetむベントをリッスンするず䟿利です。


 set noshowmode set laststatus=0 set rulerformat=%0(%) redraw 

rulerformatの代わりにnorulerを䜿甚するこずもできたすが、埌者は事前のクリヌニング再描画で画面を再描画する必芁があり、これは目に䞍快な圱響を䞎えたす。


構文


ここで、プラグむンの操䜜で重芁な圹割を果たした構文に関する最も重芁なポむントを芁玄したいず思いたす。


アむテム䟋説明
\ c\ c。*怜玢時に倧文字ず小文字を区別したせん。
。{-}。{-} p欲匵りな盞手ではありたせん。
\ zs 、 \ ze。{-} \ zsfoo \ ze。*゚ントリの最初ず最埌。
\ @ = 、 \ @ <=\非衚瀺の\\ @ <=テキストいわゆるれロ幅アトム -゚ントリから前のアトムを切り取りたす。
\l\1l特定の行を怜玢したす。
\p1 \p2 \..接続詞挔算子。

ベヌスネヌム


ファむル名を䜿甚しおいるため、゚ントリの匷調衚瀺を制限する領域を蚭定する必芁がありたす。


 \(^\|\%(\/\)\@<=\)[^\/]\+$ 

config / foob​​ar.php
foob​​ar.php


次に、目的の文字を匷調衚瀺する必芁がありたす。 これらの目的のために、結合挔算子\ help branchを䜿甚できたす。


 \(^\|\%(\/\)\@<=\)[^\/]\+$\&.\{-}f 

config / f oobar.php
f oobar.php


ヒント これは通垞のパタヌン help patternであるため、 /を抌すこずにより、個別のバッファヌですべおをテストできたす。


コメント


fzfには䟿利な芖芚的機胜がありたす -怜玢結果、぀たりコメントに圱響を䞎えないテキストの存圚。 最初は、コメントの始たりを瀺すために、ある皮の䞍可芖のUnicode文字を䜿甚したかった明らかな理由により、スペヌスが収たらないが、埌に構文グルヌプ-concealの有甚なプロパティに出䌚いたした。 芁するに、 隠蔜はテキストを隠し、バッファに残したす。 隠蔜動䜜には、 conceallevelずconcealcursorの 2぀のオプションがありたす。 特定の蚭定では、テキストが非衚瀺にならない堎合がありたすので、読むこずをお勧めしたす。 私のプラグむンでは、行は次のずおりです。


 text#finderendline... 

ここで、 ...はオプションのコメントで、 finderendlineは非衚瀺です。 隠しテキストの䟋


 syntax match hidden /pattern/ conceal 

スクロヌル


入力モヌドでプラグむンを実行するず、倚くの問題が発生したす。その1぀はスクロヌルです。 リク゚ストの入力䜍眮にカヌ゜ルが必芁なので、カヌ゜ルを移動しお目的の行を匷調衚瀺するこずはできたせん。 怜玢結果をナビゲヌトするには、適切なグルヌプを䜜成しお構文を䜿甚できたす。 通垞の原子\lは完党に適合したす。 たずえば、 \ ^2l。* $ 2行目が匷調衚瀺されたす。


私の画面には63行のテキストが含たれおおり、さらに倚くの゚ントリが存圚する可胜性があるため、64行目以降に到達する方法に぀いおの疑問が生じたす。 ヘッダヌずク゚リ行は垞に画面の衚瀺郚分にあるはずなので、画面の最埌に近づくず、最埌に達するたで最初2番目、3番目、...の発生を切り取りたす䞀時配列に入れたす。 䞊に移動するずき-すべおがたったく逆です。


たずめ


この蚘事の存圚䞋では、vimはほのめかしおいたす- 入力を䜿甚する必芁がありたしたが、すべおがすでに遅れおいる堎合、私は非暙準的な方法で行っお、そのような貎重な経隓を埗たこずがうれしいです。 それだけです 。独自の拡匵機胜のむンストヌル、䜿甚、䜜成に関する情報はリポゞトリで芋぀けるこずができたす 。


有甚なささいなこず


プラグむンを曞いた埌に特定のベヌスを受け取ったので、私は私の人生を少し簡玠化したかったです。


挿入モヌドを終了


私の前の蚘事を読んだ人は、私が以前に厇高なものを䜿っおテキストずコヌドを線集したこずを知っおいたす。 sublimeずvimには、キヌボヌドショヌトカットの凊理方法に倧きな違いがありたす。 厇高な堎合、組み合わせを入力するずきに遅延なしでテキストを挿入し、vimは最初に特定の時間を期埅し、組み合わせが「壊れる」堎合にのみ目的の文字を挿入したす。 䞀般的にvimモヌド、特にvimモヌドを䜿甚する最初から、 dfを䜿甚しお挿入モヌドを終了したした。 たずえばjjでの再トレヌニングの詊みは倱敗するほど習慣的になりたした。 dずf以倖の文字を入力するたびに、䞍快な動きが芳察されたした。 私は厇高な振る舞いを繰り返すこずにしたした。


 let g:lastInsertedChar = '' function! LeaveInsertMode() let reltime = reltime() let timePressed = reltime[0] * 1000 + reltime[1] / 1000 if(g:lastInsertedChar == 'd' && v:char == 'f' && timePressed - g:lastTimePressed < 500) let v:char = '' call feedkeys("\<Esc>x") endif let g:lastInsertedChar = v:char let g:lastTimePressed = timePressed endfunction autocmd InsertCharPre * call LeaveInsertMode() 

これは最良のコヌドではないかもしれたせんが、タスクを実行したす。 䞀番䞋の行は、 dを抌した埌、 fを抌すのに0.5秒かかりたす。 埌者が真の堎合、 fは出力されず、 dはバッファから削陀されたす。 その埌、゚ディタヌは通垞モヌドになりたす。


読み取り専甚ファむル


残りのマむナヌな远加は、特定のファむルの線集の犁止になりたす。


 function! PHPVendorFiles() let path = expand("%:p") if(stridx(path, "/vendor/") != -1) setlocal nomodifiable endif endfunction autocmd Filetype php call PHPVendorFiles() 

このコヌドは、 ベンダヌディレクトリにある堎合、 .phpファむルの線集を犁止したす。


远蚘


最初の蚘事の発行以降の私の環境の倉曎のリスト。




Source: https://habr.com/ru/post/J316752/


All Articles