2016/05/30


C言語とか C++ でマイクロフレームワークとか聞くと鼓動の高鳴りを抑えられなくなるmattnですこんにちわ。

Balde — A microframework for C based on GLib and bad intentions.

Features Simple templating engine, that converts markup to C code that is linked directly to the app...

https://balde.rgm.io/

2016年に glib で Web だと?と言われそうな気がしなくないですが面白そうな物を見つけました。特徴は

  • 簡単なテンプレートエンジンを提供し、マークアップからC言語のコードへ変換されアプリケーションのバイナリに直接埋め込まれる。
  • 静的リソースはアプリケーションのバイナリに埋め込まれサーブされる。
  • RESTful なリクエストのディスパッチを行い、ほぼ全ての HTTP メソッドをサポート。
  • URL の逆引き。 (Flask の "url_for" 関数に似ている)
  • セキュアクッキー(クライアントサイドセッション)
  • ファイルのアップロード
  • SCGI や CGI サーバとの親和性
  • GLib が稼働するあらゆるシステムで稼働する

まずは簡単なアプリケーションから。

#include <balde.h>

balde_response_t*
hello(balde_app_t *app, balde_request_t *request) {
  return balde_make_response("Hello World! I'm the balde! :D");
}

int
main(int argc, char *argv[]) {
  balde_app_t *app = balde_app_init();
  balde_app_add_url_rule(app, "hello""/", BALDE_HTTP_GET, hello);
  balde_app_run(app, argc, argv);
  balde_app_free(app);
  return 0;
}

pkg-config が提供されるのでコンパイルも楽ちん。

$ gcc -o app `pkg-config --cflags balde` main.c `pkg-config --libs balde`

静的ファイルを扱うには少し癖があり、定義ファイルからリソースとしてコンパイルする必要があります。

<?xml version="1.0" encoding="UTF-8"?>
<gresources>
    <gresource prefix="/static">
        <file>foo.js</file>
        <file>foo.css</file>
        <file>asd/bola.txt</file>
    </gresource>
</gresources>

もちろんこの XML と同様に static/foo.js, static/foo.css, static/asd/bola.txt が置かれているとします。リソースの生成方法は以下の通り。

$ glib-compile-resources --generate --sourcedir static --target static-resources.c static-resources.xml

ソースファイルは以下の様にルーティングを変更します。

#include <balde.h>
#include "static-resources.h"

balde_response_t*
hello(balde_app_t *app, balde_request_t *request) {
  return balde_make_response("Hello World! I'm the balde! :D");
}

int
main(int argc, char *argv[]) {
  balde_app_t *app = balde_app_init();
  balde_resources_load(app, static_resources_get_resource());
  balde_app_add_url_rule(app, "hello""/", BALDE_HTTP_GET, hello);
  balde_app_run(app, argc, argv);
  balde_app_free(app);
  return 0;
}

そしてコンパイル

$ gcc -o app `pkg-config --cflags balde` main.c static-resources.c `pkg-config --libs balde`

テンプレートを使う場合は専用ツールを利用します。templates/hello.html というファイルを用意します。

<h1>Hello, {{ name }}!</h1>

コマンドラインから balde-template-gen コマンドを実行します。

$ balde-template-gen templates/hello.html templates/hello.h
$ balde-template-gen templates/hello.html templates/hello.c

ソースコードを修正します。

#include <balde.h>
#include "static-resources.h"
#include "templates/hello.h"

balde_response_t*
hello(balde_app_t *app, balde_request_t *request) {
  balde_response_t *response = balde_make_response("");
  const gchar *name = balde_request_get_arg(request, "name");
  balde_response_set_tmpl_var(response, "name", name != NULL ? name : "World");
  balde_template_hello(app, request, response);
  return response;
}

int
main(int argc, char *argv[]) {
  balde_app_t *app = balde_app_init();
  balde_resources_load(app, static_resources_get_resource());
  balde_app_add_url_rule(app, "hello""/", BALDE_HTTP_GET, hello);
  balde_app_run(app, argc, argv);
  balde_app_free(app);
  return 0;
}

そしてコンパイル。

$ gcc -o app `pkg-config --cflags balde` main.c static-resources.c templates/hello.c `pkg-config --libs balde`

出来上がったアプリケーションに -s オプションを付けるとスタンドアローンサーバとして起動します。ブラウザから http://localhost:8080/?name=mattn の様なURLを開くとちゃんと動作しているのが分かるかと思います。尚、msys2 でビルドして見ましたが問題なく動作しています。glib がインストールされている同じOS同士ならばバイナリ1つでデプロイが完了します。便利そうですね。

LGPL 2.1 のライセンスのもと利用出来ます。

Posted at by



2016/04/22


コルタナさん、とても便利なのですが Vim を起動する事が出来ない。どこかで見たショートカットファイルを所定の場所に置く方法もうまく動かない。

C:\ProgramData\Microsoft\Windows\Start Menu\Programs

調べると、ボイスコマンドという API が出ているのだけど、Universal Application でないといけない。Universal Application だと System.Diagnostic からプロセスを起動できない。そこで別に立てたウェブサーバから Vim を起動させる。サーバのコードは至って簡単。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Server
{
    class Program
    {
        static void Main(string[] args)
        {
            HttpListener listener = new HttpListener();
            listener.Prefixes.Add("http://localhost:8888/");
            listener.Start();
            while (true)
            {
                HttpListenerContext context = listener.GetContext();
                HttpListenerRequest req = context.Request;
                HttpListenerResponse res = context.Response;

                if (req.RawUrl == "/vim")
                {
                    Process.Start("gvim");
                    res.StatusCode = 200;
                }
                else
                {
                    res.StatusCode = 404;
                }
                res.Close();
            }
        }
    }
}

次に空の Universal Application を作り、OnLaunched イベントでボイスコマンドAPIにコマンド定義を食わせる。

        protected async override void OnLaunched(LaunchActivatedEventArgs e)
        {
#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif
            Frame rootFrame = Window.Current.Content as Frame;

            // ウィンドウに既にコンテンツが表示されている場合は、アプリケーションの初期化を繰り返さずに、
            // ウィンドウがアクティブであることだけを確認してください
            if (rootFrame == null)
            {
                // ナビゲーション コンテキストとして動作するフレームを作成し、最初のページに移動します
                rootFrame = new Frame();

                rootFrame.NavigationFailed += OnNavigationFailed;

                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: 以前中断したアプリケーションから状態を読み込みます
                }

                // フレームを現在のウィンドウに配置します
                Window.Current.Content = rootFrame;
            }

            if (e.PrelaunchActivated == false)
            {
                if (rootFrame.Content == null)
                {
                    // ナビゲーション スタックが復元されない場合は、最初のページに移動します。
                    // このとき、必要な情報をナビゲーション パラメーターとして渡して、新しいページを
                    //構成します
                    rootFrame.Navigate(typeof(MainPage), e.Arguments);
                }
                // 現在のウィンドウがアクティブであることを確認します
                Window.Current.Activate();

                try
                {
                    // 俺コマンドの登録
                    StorageFile vcdStorageFile = await Package.Current.InstalledLocation.GetFileAsync(@"MyCommands.xml");
                    await VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(vcdStorageFile);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine("ボイスコマンドの定義でエラーが発生しました", ex);
                }
            }
        }

食わせるコマンド定義は XML で記述し、以下のようにした。

xml version="1.0" encoding="utf-8" ?>

<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.2">
  <CommandSet xml:lang="ja-jp" Name="HayCortanaLaunchVim">
    <CommandPrefix>ねぇ
    <Example>ビムを起動して
    <Command Name="OpenVim">
      <Example>ビムを起動して
      <ListenFor>ビムを起動して[下さい]
      <Feedback>ビムを起動しています
      <Navigate/>
    
  

これで「コルタナさん、ねぇ Vim を起動して」と喋るだけで http://localhost:8888/vim にリクエストが飛び、サーバを経由して Vim が起動する。

サーバ起動しておかないといけないのが面倒臭い。ちなみにちゃんと作るならクライアントサーバ間でトークンか何かをやりとりする必要があるし、サーバも localhost からのアクセスに絞るべきです。

ソースは GitHub に置いておきます。

Posted at by



2016/04/11


Software Design 2016年5月号|技術評論社

第1特集 コード編集の高速化からGitHub連携まで Vim[実戦]投入 Part1 :Vimとの長い付き合いのはじめかた …… 氏久 達博 Part2 :Vimだからでき...


http://gihyo.jp/magazine/SD/archive/2016/201605

技術評論社様から「新人に響く Vim 特集が欲しい」とのご依頼頂き、色んな方にお声かけさせて頂きましたが結果として Vim 界隈でも超ドビムな人達が選べた事に安堵の思いです。

ujihisa さん

clojure の補完プラグイン neoclojure の作者。vim-users.jp でも多くの記事を執筆したコアな Vimmer です。

thinca さん

ご存じマンボウ Vim script マスターです。thinca さんの作る物は質が高く、リポジトリのスター数を見ても皆の期待度が高いのが良く分かります。

tyru さん

eskk.vimcaw.vim の作者。ここぞという時の製造力の高さと、熱いハートの持ち主。

rhysd さん

犬さん、linda_pp さん。electron で neovim のフロントエンド NyaoVim を作っちゃった人。僕の中では C++ の人。

そして僕

わりかし Vimmer だと言われがちです。

このコアな Vimmer が、新年度に入ってくるであろう新入社員に Vim への思いを熱くぶつける記事を書き上げました。この特集でしか書かれていない内容が多く含まれており、全体的に実戦的な記事に仕上がりました。技術的な話ももちろんですが昔話も含まれる(僕です)ので若い新入社員からオジサンまで色々な人達に楽しんで頂けるかと思います。

Posted at by