2015/11/27


注意: まだ Vim Advent Calendar 2015 は始まっていません。

ctrlp.vimのエクステンションの作り方 - koturnの日記

はじめに この記事は ctrlpvim/ctrlp.vim のエクステンションの作り方についての記事であり, ctrlpの公式リポジトリのextensionsブランチ に書かれているエクステンションの...

http://koturn.hatenablog.com/entry/2015/11/19/200000

とても良い記事ですね。みんな CtrlP 拡張書いたらいいと思います。そして Vimmer おじさんから1点だけ。

let s:sample_var = {
      \ 'init': s:sid_prefix . 'init()',
      \ 'accept': s:sid_prefix . 'accept',
      \ 'lname''sample extension',
      \ 'sname''sample',
      \ 'type''path',
      \ 'nolim'1
      \}
if exists('g:ctrlp_ext_vars') && !empty(g:ctrlp_ext_vars)
  call add(g:ctrlp_ext_vars, s:sample_var)
else
  let g:ctrlp_ext_vars = [s:sample_var]
endif
unlet s:sample_var

こういう時の if 文、出来れば1行で書きたくないですか。そういう時に使えるのが get です。get は第一引数(辞書もしくは配列)から第二引数のキーで値を取得し、もしキーが存在しなければ第三引数を返すという関数です。また Vim script では g: (: の後何も付けない)という辞書変数でグローバル変数が参照出来ます。s: でスクリプトスコープ、b: でバッファスコープです。ここテストに出ます。なので

if exists('g:ctrlp_ext_vars') && !empty(g:ctrlp_ext_vars)
  call add(g:ctrlp_ext_vars, s:sample_var)
else
  let g:ctrlp_ext_vars = [s:sample_var]
endif

これは

let g:ctrlp_ext_vars = get(g:, 'ctrlp_ext_vars', []) + [s:sample_var]

と書くことができ、さらには

let g:ctrlp_ext_vars = get(g:, 'ctrlp_ext_vars', []) + [{
      \ 'init': s:sid_prefix . 'init()',
      \ 'accept': s:sid_prefix . 'accept',
      \ 'lname''sample extension',
      \ 'sname''sample',
      \ 'type''path',
      \ 'nolim'1
\}]

とすれば sample_var の代入と破棄も必要なくなります。この技、GitHub で pull-request を送ると上級者 Vimmer に見られるので要チェックです。

えっ?見られたくない?そうですか。



ちょっとしたツールを作る際にシングルヘッダのライブラリは非常に役立ちます。json を STL ライクに扱える picojson 等が有名ですね。

今日は GitHub で mmx というシングルヘッダライブラリを見つけました。

vurtun/mmx - GitHub

single header libraries for C/C++

https://github.com/vurtun/mmx

同梱されているライブラリは、JSON パーサ、C言語っぽい字句解析器、マルチスレッドスケジューラ、行列演算、ライトウェイトなウェブサーバです。

今日はこれを使ってファイルをサーブする簡単なウェブサーバを書いてみました。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#define MMW_STATIC
#define MMW_IMPLEMENTATION
#define MMW_USE_FIXED_TYPES
#define MMW_USE_ASSERT
#include "mm_web.h"

#ifdef _WIN32
#include <winsock2.h>
#define SERVER_INIT { \
  WORD wsa_version = MAKEWORD(2,2); \
  WSADATA wsa_data; \
  if (WSAStartup(wsa_version, &wsa_data)) { \
    fprintf(stderr"WSAStartup failed\n"); \
    return 1; \
  } \
}
#define SERVER_FINISH \
  WSACleanup();
#else
#define SERVER_INIT
#define SERVER_FINISH
#endif

#ifdef __APPLE__
#include <unistd.h>
#endif

static void
logger(const char* text) {
  printf("[debug] %s\n", text);
}

static int
dispatch(struct mmw_con *conn, void *userdata) {
  FILE* fp;
  char buf[4096];
  struct stat fi;

  strcpy(buf, "./public");
  strcat(buf, conn->request.uri);
  if (buf[strlen(buf)-1] == '/') strcat(buf, "index.html");
  if (stat(buf, &fi)) return 1;
  fp = fopen(buf, "r");
  if (!fp) return 1;
  mmw_response_begin(conn, 200, (int) fi.st_size, NULL0);
  while (!feof(fp)) {
    int n = fread(buf, 1sizeof buf, fp);
    mmw_write(conn, buf, n);
  }
  mmw_response_end(conn);
  fclose(fp);
  return 0;
}

int
main(void) {
  void *memory = NULL;
  mmw_size needed_memory = 0;
  struct mmw_server server;

  struct mmw_config config;
  memset(&config, 0sizeof config);
  config.address = "127.0.0.1";
  config.port = 8888;
  config.connection_max = 4;
  config.request_buffer_size = 2048;
  config.io_buffer_size = 8192;
  config.log = logger;
  config.dispatch = dispatch;

  SERVER_INIT;

  mmw_server_init(&server, &config, &needed_memory);
  memory = calloc(needed_memory, 1);
  mmw_server_start(&server, memory);
  while (1) mmw_server_update(&server);
  mmw_server_stop(&server);
  free(memory);

  SERVER_FINISH;

  return 0;
}

お決まりの手順がならびますが、ライトウェイトとは言えどある程度カスタマイズが可能なウェブサーバが作れそうです。パフォーマンスを計測してみようと思ったのですが、どこかで刺さって完走できませんでした。ただ落ちるといった事はありませんし、ブラウザで閲覧する限りにはちゃんと動作している様です。

ちょろっとファイルサーバを書きたい、といったニーズには便利そうです。

ライセンスは mm_json.h、mm_lexer.h、mm_sched.h、mm_vec.h が zlib ライセンス、mm_web.h が BSD ライセンスになります。

C++11/14 コア言語 C++11/14 コア言語
江添 亮
KADOKAWA / ¥ 4,104 (2015-09-25)
 
発送可能時間:在庫あり。


2015/11/22


先日、Visual Studio Code がオープンソースになりました。

Microsoft/vscode - GitHub
https://github.com/Microsoft/vscode

OSS になる少し前から拡張を作る為の仕組み等が github 上で展開されていたので、もしかするととは思っていましたが予想通りです。

Atom の時にも OpenVim を作ったので

Big Sky :: 21 世紀のエディタである Atom を最強にする

Atom 最高ですね!! でも、Atom は 21 世紀のエディタです。まだ 21 世紀になって 14 年しか経っていないので、 20 世紀最強のエディタ に比べてまだまだ足りない機能があるのはしょう...

http://mattn.kaoriya.net/software/atom/20140922210610.htm

これはやるしかないと決めて作ってみました。(Twitter で告知したので知っている人もいるかと思いますが)

OpenVim

Visual Studio Marketplace - OpenVim

Open a current file in Vim

https://marketplace.visualstudio.com/items/mattn.OpenVim
Open Vim というコマンドで、現在 Visual Studio Code で開いているファイルを Vim (gvim) で開けます。gvim じゃない人は openvim.executablePath という設定で起動コマンドを変更できます。
{
    "openvim.executablePath": "/usr/bin/emacs"
}

リポジトリは以下です。pull-request よろしくお願いします。

mattn/vscode-openvim - GitHub
https://github.com/mattn/vscode-openvim

もう一つ作りました。

Runner

Visual Studio Code はプロジェクトでファイルを実行するには launch.json という設定に書くしかなく、実質一つしか実行出来ない為、非常に面倒だった。そこで、ファイルタイプや拡張子に従って実行出来る物を書きました。

Visual Studio Marketplace - Runner

Run various scripts.

https://marketplace.visualstudio.com/items/mattn.Runner
Runner

CTRL+SHIFT+R をタイプすると主要なスクリプト言語は実行できます。登録されていない物や、ファイルタイプが決まらない物については、以下の様に自分のコマンドに置き換えたり拡張子で設定したりも出来ます。

{
    "runner.extensionMap": {
        "ujm": "ujm",
        "ank": "c:/dev/godev/bin/anko",
        "lisp": "sbcl"
    },
    "runner.languageMap": {
        "c": "crun.bat",
        "csharp": "cscrun.bat",
        "java": "javarun.bat"   
    }
}

個人的には Runner の方は便利だなーと思っています。

mattn/vscode-runner - GitHub
https://github.com/mattn/vscode-runner

こちらも pull-request お待ちしております。

ちなみに crun.bat は以下の様にしています。

@echo off

if "%1" equ "" goto :eof

setlocal
set tempfile=%date:~4%%time::=%
set tempfile=%tempfile:/=%
set tempfile=%tempfile:.=%
gcc -o %tempfile%.exe "%1"
%tempfile%.exe
del %tempfile%.exe

cscrun.bat も同様。

@echo off

if "%1" equ "" goto :eof

setlocal
set tempfile=%date:~4%%time::=%
set tempfile=%tempfile:/=%
set tempfile=%tempfile:.=%
c:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe /out:%tempfile%.exe "%1"
%tempfile%.exe
del %tempfile%.exe

javarun.bat は以下の通り。

@echo off
setlocal enabledelayedexpansion
set CP=.;
for %%i in (lib\*) do set CP=!CP!%%i;
if exist "%JAVA_HOME%\bin\javac.exe" goto run
for /F %%i in ('dir /b "%JAVA_HOME%\..\jdk*"') do (
  set PATH=!JAVA_HOME!\..\%%i\bin;!PATH!
  break
)
:run
javac -encoding utf-8 -cp "%CP%" %1
if %ERRORLEVEL% neq 0 goto :eof
java -cp "%CP%";%~dp1%~n1 %2 %3 %4 %5 %6 %7 %8 %9
:eof
endlocal
exit /b %ERRORLEVEL%