Next, my turn.

ロボットエンジニアのブログです.#Robotics #C++ #VBA #Python #Azure #MATLAB #ROS #Vim #RaspberryPi

Vim使いのためのVSCodeの設定

導入

今回は長年愛用しているテキストエディタの設定をご紹介したいと思います。

私は現在、"Visual Studio Code (VSCode)"に"Vim拡張機能"を入れて使用しており、この組み合わせがコーディング環境のベストプラクティスだと考えています。(Emacs党の人かかってきやがれ)

VSCodeは、Microsoft社が開発した、軽量で優秀な拡張機能も豊富な、エンジニアの要望に応えてくれるテキストエディタ。

Vimは、思考のスピードでテキスト編集ができるようになる機能群のこと。 学習コストはかかりますが(学習過程が楽しい)、使いこなせるようになったときの編集スピードの最高到達点は、他のエディタの追随を許しません。

目次

  1. 設定紹介
  2. 解説

設定紹介

以下の設定は、VSCodeのVim関連の設定のみ抽出しています。

{
    //・・・
    //省略
    //・・・

    //Vim
    "vim.easymotion": true,
    "vim.easymotionKeys": "asdfhjklweuio",
    "vim.foldfix": true,
    "vim.hlsearch": true,
    "vim.incsearch": true,
    "vim.leader": "<space>",
    "vim.normalModeKeyBindingsNonRecursive": [
        {"before": ["<Esc>"],                 "commands": [":nohl"]},
        {"before": ["<Enter>"],               "after": ["i", "<Enter>"]},
        //Yank
        {"before": ["Y"],                     "after": ["y", "$"]},
        {"before": ["leader", "y"],           "after": ["\"", "z", "y"]},
        {"before": ["leader", "p"],           "after": ["\"", "z", "p"]},
        //Delete
        {"before": ["x"],                     "after": ["\"", "_", "x"]},
        {"before": ["<Del>"],                 "after": ["\"", "_", "x"]},
        {"before": ["<BS>"],                  "after": ["h", "\"", "_", "x"]},
        //Cursor moving
        {"before": ["leader", "h"],           "after": ["^"]},
        {"before": ["leader", "l"],           "after": ["$"]},
        {"before": ["leader", "j"],           "after": ["G"]},
        {"before": ["leader", "k"],           "after": ["g", "g"]},
        //Center of display
        {"before": ["n"],                     "after": ["n", "z", "z"]},
        {"before": ["N"],                     "after": ["N", "z", "z"]},
        {"before": ["g*"],                    "after": ["g", "*", "z", "z"]},
        {"before": ["g#"],                    "after": ["g", "#", "z", "z"]},
        {"before": ["*"],                     "after": ["*", "z", "z"]},
        {"before": ["#"],                     "after": ["#", "z", "z"]},
        //Vim-Easymotion
        {"before": ["s"],                     "after": ["m", "z", "leader", "leader", "2", "s"]},
        {"before": ["leader", "s"],           "after": ["m", "z", "leader", "leader", "s"]},
        {"before": ["leader", "leader", "s"], "after": ["m", "z", "leader", "leader", "s"]},
        {"before": ["leader", "m"],           "after": ["`", "z"]},
 ],
    "vim.useSystemClipboard": true,
    "vim.visualModeKeyBindingsNonRecursive": [
        {"before": ["<Enter>"],               "after": ["\"", "_", "x", "i", "<Enter>"]},
        //Repetitive put
        {"before": ["p"],                     "after": ["\"", "_", "d", "P"]},
        //Yank
        {"before": ["g", "y"],                "after": ["y", "`", ">"]},
        {"before": ["leader", "y"],           "after": ["\"", "z", "y"]},
        {"before": ["leader", "p"],           "after": ["\"", "_", "d", "\"", "z", "p"]},
        //Delete
        {"before": ["x"],                     "after": ["\"", "_", "x"]},
        {"before": ["<Del>"],                 "after": ["\"", "_", "x"]},
        {"before": ["<BS>"],                  "after": ["\"", "_", "x"]},
        //Cursor moving
        {"before": ["leader", "h"],           "after": ["^"]},
        {"before": ["leader", "l"],           "after": ["$"]},
        {"before": ["leader", "j"],           "after": ["G"]},
        {"before": ["leader", "k"],           "after": ["g", "g"]},
        //Center of display
        {"before": ["n"],                     "after": ["n", "z", "z"]},
        {"before": ["N"],                     "after": ["N", "z", "z"]},
        {"before": ["g*"],                    "after": ["g", "*", "z", "z"]},
        {"before": ["g#"],                    "after": ["g", "#", "z", "z"]},
        {"before": ["*"],                     "after": ["*", "z", "z"]},
        {"before": ["#"],                     "after": ["#", "z", "z"]},
        //Indent
        {"before": [">"],                     "commands": ["editor.action.indentLines"]},
        {"before": ["<"],                     "commands": ["editor.action.outdentLines"]},
        //Comment for c++
        {"before": ["leader", "c"],           "after": ["I", "/", "/", "<Esc>"]}
        //Vim-Easymotion
        {"before": ["s"],                     "after": ["<Esc>", "m", "z", "g", "v", "leader", "leader", "2", "s"]},
        {"before": ["v", "s"],                "after": ["<Esc>", "m", "z", "g", "v", "leader", "leader", "2", "s"]},
        {"before": ["V", "s"],                "after": ["<Esc>", "m", "z", "g", "v", "leader", "leader", "2", "s"]},
        {"before": ["leader", "s"],           "after": ["<Esc>", "m", "z", "g", "v", "leader", "leader", "s"]},
        {"before": ["leader", "leader", "s"], "after": ["<Esc>", "m", "z", "g", "v", "leader", "leader", "s"]},
        {"before": ["leader", "m"],           "after": ["`", "z"]},
 ],
    "vim.whichwrap": "b,s,h,l,<,>,[,],~",
}

解説

デフォルト状態だと使いにくいキーバインドがあったり、ビジュアルモードでVim拡張機能が使えなかったりするので、オリジナルコマンドを追加しています。

コンセプトは、「ネイティブなVimの挙動に固執せず、自分の思考が動作に反映されるか」です。

「setting.json」は、Visual Studio Codeの画面中の、[ファイル]→[基本設定]→[設定]から「設定(JSON)を開く」アイコンをクリックすることで、直接編集できるようになります。

なお、「<Leader>」キーとして「スペースキー」を設定しています。こんなに押しやすいキーを駆使しないのはもったいないです!

基本
キーバインド 説明
Esc 検索時のハイライトを消す
Enter 改行(ノーマルモード)
選択部分を削除し改行(ビジュアルモード)
ヤンク(コピー)、プット(貼り付け)
キーバインド 説明
p 繰り返し上書きができるようレジスタを汚さず貼り付け(ビジュアルモード)
Y 行末までヤンク
gy ヤンク後、選択範囲の最後尾に移動(ビジュアルモード)
<Leader>y zレジスタにヤンク
<Leader>p zレジスタをプット
削除
キーバインド 説明
x レジスタを汚さず削除
Delete レジスタを汚さず削除
BackSpace レジスタを汚さずカーソルの左を削除
移動
キーバインド 説明
<Leader>h 行頭に移動
<Leader>l 行末に移動
<Leader>j ファイル末尾に移動
<Leader>k ファイル先頭に移動
n
N
g*
g#
*
#
検索後カーソルを画面中央に移動
インデント
キーバインド 説明
> 連続右インデント(ビジュアルモード)
< 連続左インデント(ビジュアルモード)
Vim-Easymotion(拡張機能)
キーバインド 説明
s 任意の2文字に移動
<Leader>s 任意の1文字に移動
<Leader><Leader>s 任意の1文字に移動
<Leader>m Easymotionジャンプ前に移動

まとめ

テキストエディタは、自分の手足のようなもの。自分仕様の設定にチューニングすることで、エンジニアの真の力が引き出せると考えています。

この記事を参考に、思考のスピードで編集するVimmerになってください。

【c++】処理時間を計測する(ラップタイム機能つき)

導入

画像処理や通信に要する処理時間を計測するサンプルプログラムをご紹介します。

このプログラムを使用すると、処理前後の経過時間や、ラップタイムを計測することができます。

目次

  1. サンプルプログラム
  2. 出力結果
  3. 使い方
  4. 解説

サンプルプログラム

#include <iostream>
#include <vector>
#include <windows.h>
using namespace std;

const static int LAP_BUFF_SIZE = 5;

class StopWatch {
private:
    double         start;      //スタート時のシステム起動からの相対時間
    double         end;        //スタートからストップまでの時間
    vector<double>  lap;        //スタートからラップまでの時間
    bool           is_started; //true: 時間カウント中, false: 時間カウントしていない
    double         Get(void);  //システム起動からの相対時間を取得
public:
    StopWatch();
    ~StopWatch();
    void   Start(void);
    bool   Lap(void);
    bool   Stop(void);
    void   Print(void);
};

StopWatch::StopWatch()
    :start(0.0), 
     end(0.0), 
     is_started(false)
{
}

StopWatch::~StopWatch()
{
}

void StopWatch::Start() {
    //Clear time
    this->end = 0.0;
    this->lap.clear();
    this->lap.shrink_to_fit();

    this->start = this->Get();
    this->is_started = true;
    return;
}

bool StopWatch::Lap() {
    double now; //Relative time from system boot

    if (this->is_started == false) {
        cerr << "Lap() called before SetStart()" << endl;
        return false;
    }

    if (this->lap.size() < LAP_BUFF_SIZE) {
        now = this->Get();
        this->lap.push_back(now - this->start);
    }
    else {
        cerr << "Lap time buffer size exceeded the limit" << endl;
    }
    return true;
}

bool StopWatch::Stop() {
    double now; //Relative time from system boot

    if (is_started == false) {
        cerr << "Stop() called before SetStart()" << endl;
        return false;
    }

    now = this->Get();
    this->end = now - this->start;
    return true;
}

double StopWatch::Get(void) {
    double sys_time;
    static LARGE_INTEGER freq;
    LARGE_INTEGER time;

    if (freq.QuadPart == 0) {
        QueryPerformanceFrequency(&freq);
    }
    QueryPerformanceCounter(&time);
    sys_time = (double)time.QuadPart / (double)freq.QuadPart;
    return sys_time;
}

void StopWatch::Print() {
    for (unsigned int i = 0; i < this->lap.size(); i++) {
        cout << "Lap(" << i + 1 << ") : " << this->lap[i] << " [s]" << endl;
    }
    cout << "Time : " << this->end << " [s]" << endl;
    return;
}

int main() {
    StopWatch sw;

    sw.Start();

    //--------------------------------
    Sleep(500); //0.5s
    //--------------------------------
    sw.Lap();

    //--------------------------------
    Sleep(500); //0.5s
    //--------------------------------

    sw.Stop();
    sw.Print();

    getchar();
    return 0;
}

出力結果

スタートしてから一回目のラップタイムは「0.502758秒」、ストップ時の時間は「1.00516秒」となりました。

PCの性能によっては、異なる秒数が表示されるかもしれません。

Lap(1) : 0.502758 [s]
Time : 1.00516 [s]

使い方

StopWatch::Start()

時間計測を開始します。ストップウォッチのSTARTボタンに該当します。

時間計測を開始すると、過去のラップタイムはすべて初期化されます。

StopWatch::Lap()

ラップタイムを計測します。ストップウォッチのLAPボタンに該当します。

StopWatch::Stop()

時間計測を停止します。ストップウォッチのSTOPボタンに該当します。

StopWatch::Print()

計測した時間情報(STARTボタンが押された時間を基準に、LAPボタン、STOPボタンが押された時間)を表示します。

解説

このプログラムでは、Windows OSのパフォーマンス カウンター のAPIを使用して、時間を計算しています。

まとめ

このようなプログラムを使用することによって、処理性能を調査したり、処理のボトルネックを調べたりすることができます。

下記にGitHubのリンクを貼っておりますので、ぜひご活用ください。

最後まで読んでいただき、ありがとうございました!