グレインの備忘録

プログラミング関係とかをつらつらと。

括弧の自動補完にlexima.vimを使う

以前の設定ではキーマップを駆使した汚い括弧補完を使っていた。

探してみると、もっと良さげなプラグインがあったのでそれに置き換えてみる。

導入

dein_lazy.tomlに追加。

[[plugins]]
# lexima
repo = 'cohama/lexima.vim'
on_i = 1

後はインストールすれば終わり。

括弧を補完に頼らず入力しても「())」みたいにならないし、いい感じである。

deoplete環境でneosnippetを使えるようにする

neosnippetはスニペットを挿入できるプラグインだが、機能的にdeopleteと干渉する部分があるので少し工夫をする必要がある。

メモ程度に設定方法を残しておく。

参考:neovim で deoplete + neosnippet の連携をする

導入

dein.tomlとdein_lazy.tomlに以下のとおりに追記する。

※tomlファイルを活用しているが、hook_post_source内のスクリプトをinit.vim内に書けば同じことである。

[dein.toml]

[[plugins]]
# snippets
repo = 'Shougo/neosnippet-snippets'
[dein_lazy.toml]

[[plugins]]
# neosnippet
repo = 'Shougo/neosnippet.vim'
hook_source = '''
  "Ctrl+Kにターゲットジャンプ割当
  imap <C-k> <Plug>(neosnippet_expand_or_jump)
  smap <C-k> <Plug>(neosnippet_expand_or_jump)
  xmap <C-k> <Plug>(neosnippet_expand_target)
  if has('conceal')
    set conceallevel=2 concealcursor=niv
  endif
'''
on_i  = 1
on_ft = ['snippet']
depends = ['neosnippet-snippets']

[[plugins]]
# deoplete
repo = 'Shougo/deoplete.nvim'
hook_source = '''
  let g:deoplete#enable_at_startup = 1
  "Tab補完の設定
  inoremap <expr><tab> pumvisible() ? "\<C-n>" :
        \ neosnippet#expandable_or_jumpable() ?
        \    "\<Plug>(neosnippet_expand_or_jump)" : "\<tab>"
'''
on_i = 1

操作方法

  • Ctrl+Nで候補切り替え
  • 候補を選択した状態でCtrl+Kでスニペット挿入
  • 以後Ctrl+Kで入力位置移動

deinを真面目に設定してみる(TOML)

deinはvimrcに設定を書くだけでも使える。

しかし、一般的にはTOMLと呼ばれる外部ファイルに書くらしい。

TOMLファイルを利用する

とりあえずTOMLを使う準備をしよう。

init.vimに以下の記述を追加する。

set runtimepath+=~/.vim/dein/repos/github.com/Shougo/dein.vim

let s:dein_dir = expand('~/.vim/dein')
let s:toml_dir = expand('~/.config/nvim')

"dein settings
if dein#load_state(s:dein_dir)
    call dein#begin(s:dein_dir)

   "Load TOML
    let s:toml = s:toml_dir . '/dein.toml'
    let s:lazy_toml = s:toml_dir '/dein_lazy.toml'

    call dein#load_toml(s:toml, {'lazy': 0})
    call dein#load_toml(s:lazy_toml, {'lazy': 1})

   "finalize
    call dein#end()
    call dein#save_state()
endif

この設定では、

  • deinは「~/.vim/dein/repos/github.com/Shougo/dein.vim」にcloneされている
  • TOMLは「~/.config/nvim/」以下に保存

となっている。必要に応じて該当箇所を変更すること。

起動時ロードと遅延ロード

次は、TOMLファイルに使いたいプラグインを列挙する。

ここで一つ注意する必要があるのが「遅延ロード」の存在だ。

今まで普通にdeinを使っていれば、プラグインは起動時にロードされていた。

しかし、「遅延ロード」を用いると、起動時より少し後にプラグインがロードされる。

これを用いることにより、起動時のロードを最小限にできることで起動速度が上がるらしい。

では、実際にTOMLを書いてみよう。

まずは起動時用。

# [dein.toml]

#以下のようにレポジトリ名を書くだけで良い
[[plugins]]
repo = 'Shougo/dein.vim'

[[plugins]]
# Lighline
repo = 'itchyny/lightline.vim'

[[plugins]]
# tender
repo = 'jacoborus/tender.vim'

ここでは利用していないが、他にもカスタマイズができるらしい。

参考:dein.vimによるプラグイン管理のマイベストプラクティス - Qiita

次に、遅延ロード用。

# [dein_lazy.toml]

[[plugins]]
# deoplete
repo = 'Shougo/deoplete.nvim'
hook_post_source = '''
    let g:deoplete#sources#clang#libclang_path = '/usr/lib/llvm-3.8/lib/libclang-3.8.so.1'
    let g:deoplete#sources#clang#clang_header = '/usr/include/clang'
    let g:deoplete#enable_at_startup = 1
'''

[[plugins]]
# deoplete-clang
repo = 'zchee/deoplete-clang'

基本は起動時用と同じだが、遅延ロードでは「hook_post_source」というオプションが利用できる。

これは、プラグインが遅延ロードされた直後に実行するコマンドを指定するものである。

プラグインの追加設定をiniv.vimに書くとロード前に実行されてしまうので、それを防ぐためにここに書く。


とりあえず導入だけをやってみた。

有り難みもそのうちわかってくるようになるんだろう、多分。

Doxygenを導入してみる

Doxygenはソースに埋め込んだコメントを元にドキュメントを作成するツール。

メモ程度に導入方法をまとめておく。

導入

sudo apt -y install doxygen doxygen-gui graphviz

あとは、

doxywizard

を実行すればGUIが出てくるので、ウィザード通りにすすめる。

スニペット

ファイル

/**
* @file
* @brief 
* @author 
* @date 
* @details 
*/

@file ファイル名(必須) @brief 一行説明(必須) @author 作成者 @date 作成日 @details 詳細説明

関数

/**
* @fn 
* @brief 
* @param
* @retval
* @details 
*/

@fn プロトタイプ宣言(必須) @brief 一行説明(必須) @param 引数 構文:@param[in/out] <引数名> <説明> @retval 戻り値 構文:@retval <値> <説明> @details 詳細説明

変数

//! 説明

変数宣言行の上に書く。

クラスとかは上3つを組み合わせればいける。


参考文献

Ubuntu に doxygen / graphviz をインストール

最近覚えた便利アプリ[doxygen]

補助ライブラリでサクッとOpenGL(GLFW,GLEW)

OpenGLはプラットフォーム独立のライブラリだが、ウィンドウ管理などの面倒は見てくれない。

また、シェーダーを使うのには拡張機能を有効化する必要がある。

ウィンドウ管理や拡張機能の取得はプラットフォームごとに違うので、生のGLを扱うとそれなりに労力がかかる。

そこで、補助ライブラリを使ってサクッとこの問題を解決する。

1.入力・ウィンドウ管理:GLFW

GLFWはOpenGLの補助ライブラリで、

  • ウィンドウ管理や入力デバイスの制御を担当
  • 出来る限りシンプルな機能構成(Teapotや文字出力なし)
  • 2017年8月現在もメンテナンスが続いている

といった特徴がある。

導入

linuxならaptで入れる。

sudo apt -y install libglfw3-dev

Windowsならバイナリを直接入手できるらしい。 VSならNuGetもアリ。

2.拡張機能管理:GLEW

GLEWはGLFWと名前が似ていて紛らわしいが、

という感じである。

ちなみにOpenGL拡張機能取得はそれ自体が結構面倒なので、それを簡略化してくれるGLEWはマルチプラットフォームを視野に入れていなくても十分有用である。

導入

こいつもaptで可。

sudo apt -y install libglew-dev

Windowsの場合はGLFWと同様バイナリを取ってくる。 やはりこいつもNuGetパッケージがある。


とりあえず初期化だけやってみる

C++で書くとこんな感じか。

#include <iostream>
#include <string>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

class LogManager
{
public:
    LogManager(){};
    //Info out
    void LOGI(std::string msg)
    {
        std::cout << msg << std::endl;
        
    }

    //Error out
    void LOGE(std::string msg)
    {
        std::cerr << msg << std::endl;
    }
};

class App
{
public:
    App(LogManager *log) : m_log(log) {};
    bool run()
    {
        if(!init())
            return false;

        while(glfwWindowShouldClose(m_win) == GL_FALSE)
        {
            glClear(GL_COLOR_BUFFER_BIT);

            glfwSwapBuffers(m_win);
            glfwWaitEvents();
        }

        terminate();

        return true;
    }; 

private:
    LogManager *m_log;
    GLFWwindow *m_win;

    bool init()
    { 
        if(!init_glfw())
        {
            m_log->LOGE("Failed to initialize GLFW.");
            terminate();
            return false;
        }
        m_log->LOGI("GLFW Initialized.");

        if(!init_window(640, 480, "SAMPLE"))
        {
            m_log->LOGE("Failed to initialize window.");
            terminate();
            return false;
        }
        m_log->LOGI("Window Initialized.");

        //必ずGLEW初期化より前
        glfwMakeContextCurrent(m_win);
        
        if(!init_glew())
        {
            m_log->LOGE("Failed to initialize GLEW.");
            terminate();
            return false;
        }
        m_log->LOGI("GLEW Initialized.");


        glClearColor(1.0f, 1.0f, 1.0f, 0.0f);

        return true;
    }
    
    void terminate()
    {
        glfwTerminate();
    }

    bool init_glfw(void)
    {
        if(glfwInit() == GL_FALSE)
            return false;

        return true;
    }

    bool init_window(int width, int height, std::string title)
    {
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

        m_win = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
        
        if(m_win == nullptr)
            return false;

        return true;
    }

    bool init_glew(void)
    {
        GLenum err;
        err = glewInit();
        if(err != GLEW_OK)
        {
            m_log->LOGE(
                    "GLEW Error :"
                    + std::string((char*)glewGetErrorString(err))
            );
            return false;
        }

        return true;
    }
};

static LogManager s_logman;

int main(void)
{
    App app(&s_logman);
    
    return app.run() ? 0 : -1;
}

初期化の順としては

  1. GLFW初期化
  2. GLFWでウィンドウ初期化
  3. GLFWでコンテキスト有効化(glfwMakeContextCurrent)
  4. GLEW初期化

となる。

特に、GLEWの初期化にはコンテキストが有効である必要があるので注意する。

以降は、App.run()のようにループを組み、自由にOpenGLを利用する。

追記:コンパイルオプション

ライブラリ名の指定が迷いそうになるが、

$(LDFLAGS) = -lglfw -lGLEW -lGL

でOK。

タブ独立のファイルツリーで快適コーディング

やはり、ファイルツリーをVim内で開いておけると何かと便利だ。

ファイルツリーといえばNERDTreeが有名だが、それのタブ独立版があるそうなので試してみた。

vim-nerdtree-tabsのインストール

まずはプラグイン導入から。

vimrcに追加

call dein#add('scrooloose/nerdtree') 
call dein#add('jistr/vim-nerdtree-tabs')

そして、

call dein#install()

で完了。

使い方

:NERDTreeTabsOpen

で即座に開く。操作方法は通常のNERDTreeと全く同じである。

本家と違うのは、新規にタブを生成したり、画面を分割したりしても一切影響を受けないという点だ。

ファイルフィルタ

中間生成ファイルが見えると邪魔なことがある。そのようなときにはフィルタを活用しよう。

例えば*.oファイルをフィルタするには、vimrcに以下の行を追加する。

let g:NERDTreeIgnore = ['\.o']

そして、NERDTree内で「f」キーを押すとフィルタの有無が切り替わる。

C++補完用にdeoplete-clangを導入する

コードを書くにはやっぱり補完がないと辛い。

C++をNeoVimで書くならdeoplete-clangがベストチョイスのようだ。

導入

deopleteはNeoVimのRemotePlugin機能を使うのでpython-clientを入れておく必要がある。

以下のコマンドでインストールできる。

sudo apt -y install python3-pip
pip3 install neovim

次はプラグイン導入。

init.vimに以下を追加する。

call dein#begin()
"(中略)
call dein#add('Shougo/deoplete.nvim')
call dein#add('zchee/deoplete-clang')
"(中略)
call dein#end()

"deoplete settings
let g:deoplete#sources#clang#libclang_path = '/usr/lib/llvm-3.8/lib/libclang-3.8.so.1'
let g:deoplete#sources#clang#clang_header = '/usr/include/clang'

続いて、インストール作業。

:call dein#install()
:UpdateRemotePlugins

これで正しくdeoplete及びdeoplete-clangがインストールされた。

所感

f:id:grainrigi:20170827133758p:plain

外部ライブラリのヘッダ等もちゃんと解析している模様。

Intellisenseとも遜色なく、十分に使い勝手が良いと思う。

ただ、#includeディレクティブそのものの補完はしないのでneoincludeも組み合わせるといいだろう。