vimでcmakeプロジェクトをサポートするプラグインを作成しています

今日は、VIMのアドオンの作成についてお話します。

最近、便利なファイルナビゲーションのためにcmakeプロジェクトのサポートをそれに組み込むことを考えました。 もちろん、NERDツリーはこのタスクに非常に対応しますが、後者ではプロジェクトファイルだけを操作することはできません。

Achtung:この記事の著者は最初にVim Scriptに出会いました。 それはあなたが記事を読んだ後に気絶しないことを保証しません。 コメントにコードに関するコメントを残します。



cmakeプロジェクト管理プラグインは、cmakeコマンドを使用して、「build」フォルダーにアセンブリに必要なファイルを作成し、ソースファイルに簡単にアクセスできる要素をクリックして、ファイルツリーのパネルを表示する必要があります。

そして、実装を始めましょう。

cmakeで作成されたファイルの奥深くを掘り下げると、依存するソースファイルのリストが格納されている場所を見つけることができます。 半分の方法でcppshnikiで文字列の存在を検索しましょう:

grep ".*\.cpp" -R build/ 


DependInfo.cでこのコンテンツの変数を作成しました
 SET(CMAKE_DEPENDS_CHECK_CXX "/home/..../brushcombo.cpp" "/home/.../build/CMakeFiles/kdots.dir/brushcombo.o" ... ) 


ディレクトリ内のすべてのDependInfo.cmakeファイルを見つけ、Perlスクリプトを使用してファイルへのフルパスを見つけます。
 sub cmake_project_files { my $dir = shift; my @dependencies = File::Find::Rule->file() ->name("DependInfo.cmake") ->in($dir); my @accum = (); foreach my $filename(@dependencies) { open(FILE, $filename); my @data = <FILE>; push (@accum, src_files(\@data)); close(FILE); } return @accum; } sub src_files { my @result = (); foreach my $line(@{(shift)}) { if ($line =~ m/\s*\"(([a-zA-Z_\/]+)\/([a-zA-Z_]+\.(cpp|cc))).*/) { push(@result, $1); } } return @result; } 


完全なソースはこちら

これらの関数をプラグインにバインドする前に、〜/ .vimのディレクトリ階層を調べます。


プラグインはエディターを起動するたびにロードする必要があるため、〜/ .vim / pluginに配置します。 ファイルにcmake-project.vimという名前を付けます。

perlインタープリターの存在を確認します。
 if !has('perl') echo "Error: perl not found" finish endif 


ファイルツリーを生成する関数を作成します。 関数と変数は、さまざまなスコープで作成できます(これについては、 こちらで確認できます )。 この関数は、最初に「CMakeProject」と呼ばれる新しいウィンドウとバッファを作成します。
 function! s:cmake_project_window() vnew badd CMakeProject buffer CMakeProject " ,    ,   , VIM     setlocal buftype=nofile ... 


現在のバッファーがファイルツリーのあるパネルであるかどうかを判断するには、バッファーの名前で変数(プラグイン内のスコープ)を宣言します。
  let s:cmake_project_bufname = bufname("%") 


次に、Perlスクリプトをプラグインにバインドします。 スクリプトを〜/ .vim / plugin / cmake-projectディレクトリに配置して、libを使用して検出できるようにします。 cmakeproject :: cmake_project_files関数からファイルのリストを取得し、Wimのリストに配置します。

 perl << EOF "     Python   Ruby use lib "$ENV{'HOME'}/.vim/plugin/cmake-project"; use cmakeproject; my $dir = VIM::Eval('g:cmake_project_build_dir'); my @result = cmakeproject::cmake_project_files($dir); VIM::DoCommand("let s:cmake_project_files = []"); foreach $filename(@result) { if (-e $filename) { VIM::DoCommand("call insert(s:cmake_project_files, \'$filename\')"); } } EOF 


次に、これらのデータに基づいて、ツリーを構築します。 vimには、ハッシュとリストのいくつかのデータ構造があります。 したがって、ハッシュのキーとしてディレクトリを表します。 ハッシュキーが何か(1ではない)を指している場合、これはディレクトリであり、1である場合、これはディレクトリ内のファイルです。

以下のコードは、 "/ home / paranoik / main.cpp"の形式の文字列を{'home':{'paranoik':{'main.cpp':1}}の形式の構造に変換します。ここで{key:value}はハッシュです1つのキーと値のペア。

  let s:cmake_project_file_tree = {} for fullpath in s:cmake_project_files let current_tree = s:cmake_project_file_tree let cmake_project_args = split(fullpath, '\/') let filename = remove(cmake_project_args, -1) for path in cmake_project_args if !has_key(current_tree, path) let current_tree[path] = {} "   endif let current_tree = current_tree[path] endfor let current_tree[filename] = 1 endfor call s:cmake_project_print_bar(s:cmake_project_file_tree, 0) 


次に、バッファにツリーを表示する関数を定義します。 スペース形式のインデントは、階層のレベルに応じて定義されます(関数s:cmake_project_indentがこれを担当します)。
 function! s:cmake_project_print_bar(tree, level) for pair in items(a:tree) if type(pair[1]) == type({}) "   let name = s:cmake_project_indent(a:level) . "-" . pair[0] call append(line('$'), name . "/") "   "-<dir>/" let newlevel = a:level + 1 call s:cmake_project_print_bar(pair[1], newlevel) "      . else "   let name = s:cmake_project_indent(a:level) . pair[0] call append(line('$'), name) endif endfor endfunction 


s:cmake_project_window()関数をCMakeProコマンドにバインドします
 command -nargs=0 -bar CMakePro call s:cmake_project_window() 


cmakeファイルを生成するコマンドも必要です。
 command -nargs=1 -bar CMake call s:cmake_project_cmake(<f-args>) function! s:cmake_project_cmake(srcdir) if !isdirectory(a:srcdir) echo "This directory not exists!" . a:srcdir return endif let s:cmake_project_dir = a:srcdir exec "cd" a:srcdir if !isdirectory(g:cmake_project_build_dir) call mkdir(g:cmake_project_build_dir) endif cd build exec "!cmake" "../" cd .. call s:cmake_project_window() endfunction 


カーソルがパネル上を移動すると、カーソルの下でファイルが開きます。 s:cmake_project_cursor_moved()関数を作成し、それをCursorMovedシグナルにバインドします。
 autocmd CursorMoved * call s:cmake_project_cursor_moved() 

関数がパネルバッファーでのみ機能するようにするには、実行前にその名前を確認してください。
 function! s:cmake_project_cursor_moved() if exists('s:cmake_project_bufname') && bufname('%') == s:cmake_project_bufname <code> endif endfunction 

現在の行のデータを取得し、カーソルの下の単語を選択します。
  let cmake_project_filename = getline('.') let fullpath = s:cmake_project_var(cmake_project_filename) let highlight_pattern = substitute(fullpath, '[.]', '\\.', '') let highlight_pattern = substitute(highlight_pattern, '[/]', '\\/', '') exec "match" "ErrorMsg /" . highlight_pattern . "/" 


インデントを介してファイルが配置されるディレクトリを定義します。 ファイルがn番目のレベルの要素である場合、ファイルが配置されているディレクトリは、n番目のレベルのインデントを持つ最上位の最も近い要素です。
  let level = s:cmake_project_level(cmake_project_filename) let level -= 1 let finding_line = s:cmake_project_find_parent(level, line('.')) while level > -1 let path = s:cmake_project_var(getline(finding_line)) let fullpath = path . fullpath let level -= 1 let finding_line = s:cmake_project_find_parent(level, finding_line) endwhile let fullpath = "/" . fullpath "     


必要なファイルを開きます
  if filereadable(fullpath) wincmd l exec 'e' fullpath setf cpp endif endif 


結果は次のとおりです。

画像

ここで取得するソース: 画像

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


All Articles