f

2016-05-24

How to match grep command for all files including hidden files

grepコマンドでドット(.)で始まる隠しファイルを含む全ファイルを検索対象にするには,以下のどれかの書式を使う。

grep -r "pattern" .[!.]* *
grep -r "pattern" .* * --exlucde-dir=..
## for bash dotglob and zsh glob_dots option enabled
grep -r "pattern" .[!.]* [!.]*
grep -r "pattern" * --exclude-dir=..

Introduction

ファイル内の文字列を検索するgrepコマンドをよく使う。ファイル名のパターンマッチであるglobを活用し,ワイルドカードの*と組み合わせて大量のファイルから文字列を検索できる。

しかし,globの*では.から始まる隠しファイルは検索対象にならない。つまり,以下ではドット(.)から始まる.foo.baz/baz.baz/.bazは検索にヒットしない。

mkdir -p bar .baz
echo "1. file dot" > foo
echo "2. file dot foo" > .foo
echo "3. file bar/dot bar" > bar/bar
echo "4. file bar/dot bar" > bar/.bar
echo "5. file dot baz/baz" > .baz/baz
echo "6. file dot baz/dot baz" > .baz/.baz
grep -r "file" *
bar/bar:3. file bar/dot bar
bar/.bar:4. file bar/dot bar
foo:1. file dot

globの*でこれらの隠しファイルにマッチさせる方法は2通りある。

  1. bashのdotglobやzshのglob_dotsなどシェル機能を活用。
  2. ワイルドカードを駆使。

grepの隠しファイルへのマッチ方法

シェル機能を活用

bashとzshでは,ドット(.)から始まる隠しファイルにもglobの*がマッチできるようにするオプションがある。

以下のコマンドで機能をオンにできる。

## bash (~/.bashrc)
shopt -s dotglob

## zsh (~/.zshrc)
setopt glob_dots
grep -r "file" *
.baz/baz:5. file dot baz/baz
.baz/.baz:6. file dot baz/dot baz
.foo:2. file dot foo
bar/bar:3. file bar/dot bar
bar/.bar:4. file bar/dot bar
foo:1. file dot

ただ,これらの機能を設定ファイルで有効にしておくと,ターミナルからコマンドを入力したり,シェルスクリプトにも影響を与えるリスクがある。そのため,あまりこれらの機能を前提にしないほうがよいだろう。

ワイルドカードを駆使

シェルの設定に頼らずともワイルドカードを駆使すれば隠しファイルも検索対象に含めることはできる。例えば,.から始まるファイルは以下でマッチする。

grep -r "file" .*

しかし,上記コマンドは以下2点の理由から実行しないほうがいい。

  1. .*は1階層上のディレクトリを意味する..にもマッチし,ファイルシステム全体を再帰的に検索してしまう。
  2. 隠しファイル以外のファイルにマッチしない。

この2点をカバーするには,以下のように入力する。

grep -r "file" .[!.]* *

仕組みは以下のとおりだ。

  1. 最初の.[!.]*..を除く,.で始まる隠しファイルを検索対象とする。
  2. 最後の*.で始まらないファイル(通常のglobの*の動作)を検索対象とする。

なお,前述の..にマッチしてしまい,ファイルシステム全体を再帰的に検索することを回避するためにはgrepの--exclude-dirオプションで..を指定してもよい。

grep -r "file" .* * --exclude-dir=..

トラブルシューティング

bashのdotglobとzshのglob_dots有効時の不具合

grepでは検索対象を何回も指定できるが,間違えるとその分重複も発生するので注意する。つまり,ここでbashのdotglobのやzshのglob_dotsを有効にしていると不都合が起きる。これらの機能を有効にすると,*が隠しファイルにもマッチするので,.で始まる隠しファイルが2回マッチしてしまう。

例えば,以下の.a.datファイルには2回ヒットする。

bash
shopt -s dotglob

echo "return" > .a.dat
grep -r "return" .[!.]* *
.a.dat:return
.a.dat:return

これを避けるには,grepの最後の*で隠しファイルを明示的に除外する。

grep -r "return" .[!.]* [!.]*
.a.dat:return

補足だが,grepでは-eオプションで一度に複数のキーワードを検索(OR検索)できる。

grep -r -e "pattern1" .[!.]* * -e "pattern2"
POSIXでの[^...]は未定義

当初,以下の様にglobでのパターンマッチングに!ではなく^を使っていた。bashとzshでは動作したが,shでうまく動作しなかった。

grep -r "file" .[^.]* [^.]*

気になって確認したところ,POSIXではワイルドカードにおける開き角括弧[の開始のサーカムフレックス^の動作([^...])は未定義のようなので,使用を控えたほうがよいだろう。

A bracket expression starting with an unquoted <circumflex> character produces unspecified results.

Shell Command Language

まとめ

元々はVimでのgrep検索について調べていたのだが,気づいたらgrep検索についてはまってしまっていた。時間を余計に使ってしまったが,POSIXの仕様も確認できて勉強になった。

冒頭でも記載した通り,現在ディレクトリ以下の隠しファイルを含む全ファイルを対象に検索したければ,以下のどちらかの書式を使う。

grep -r "pattern" .[!.]* *
## for bash dotglob and zsh glob_dots option enabled
grep -r "pattern" .[!.]* [!.]*

2番目の書式の方がbashのdotglobとzshのglob_dotsオプションに依存しないので,より確実だが,これらのオプションを考慮するのはやりすぎなような気もする。お好みで選べばよいだろう。

参考:

2016-05-22

今までの発表資料・イベント参加履歴の一覧ページの作成・公開

今までの発表資料とイベント参加履歴の一覧ページを作成してみた。

勉強会に参加し始めたのが,2013年の夏頃で,発表を始めたのが2014年03月からだ。活動を初めてもう2年ほど経過して,イベント参加累計回数も50回を越え,発表資料も10個となり蓄積してきた。

そろそろ活動履歴一覧を作ったほうがよいかなと思ったので作ってみた。狙いは以下2点だ。

  • 僕がこれまでの活動履歴を把握。
  • 他人に僕の活動履歴をアピール。

この先,ますますいろんな人と出会うことがあるだろう。そういうときに,自分が何に興味関心をもってどういう活動をしてきたかをわかりやすく伝えて,仲良くなれたらいいなと思う。そのためにも,こういう一覧ページを作るのが中長期的にとても効果的じゃないかなと思った。ブログの断片的な情報はすぐに埋もれて見えなくなってしまう。ある程度まとまった情報はWebサイトにするなど,一覧ページを作ったほうがよいだろう。

一覧ページは,このブログのヘッダー部分の[Activity]からアクセスできる。

また,以下のURLでもアクセスできる。

My Future Sight for Past: Activity http://myfuturesightforpast.blogspot.jp/p/activity.html

一覧ページ作成にあたって,大学での研究発表資料も一覧化した。

今まで発表時にはボイスレコーダーで自分の発表音声を録音していた。この音声と当時の発表資料を使って,動画も作ってみた。一覧ページの表にも掲載しているが,以下でもアクセスできる。

presentation - YouTube

当時の発表の様子などがなんとなくわかって,懐かしめたりしてよいかなと思った。

イベントに参加したり,特に発表するのはけっこうたいへんなときもあるので,自分の活動の成果としてしっかり記録していきたい。

2016-05-21

Twitterの埋め込みツイートのXHTMLへの変換ページTweet2XHTML

Twitterの埋め込みTweetをXHTMLに変換するページTweet2XHTMLを作ったので紹介する。

Twitterのツイートは,右下の[…(その他)]>[ツイートをサイトに埋め込む]でブログなどで埋め込めるHTMLを取得できる。

例えば,以下のようなHTMLコードを取得できる。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">toolとutilityをどう使い分けるか悩む。WikipediaとLongmanの英英辞書を参照した。<br>toolは物理的なもの。仕事道具とかそういう感じ。<br>utilityはコンピューター向けの用語。POSIX:2008もこちらを使っている。<br>基本はutilityにするか。</p>&mdash; せのぺん (@senopen) <a href="https://twitter.com/senopen/status/733901332176736257">2016年5月21日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

これをブログに貼り付けると以下のように表示される。

このHTMLコードには以下の不満があった。

  • HTMLの形式になっており,XHTML文書に貼り付けるとエラーになる。具体的には以下の項目がエラーとなる。
    • br要素に終端スラッシュがない。×:<br>,○:<br />
    • 文字実体参照&mdash;が使えない。×:&mdash;,○:
  • 外部JavaScriptを使いたくないので,script要素は削除したい。

文字実体参照については,以下のように文書宣言時に定義してやれば使うことはできる。

<!DOCTYPE html [
  <!ENTITY mdash "&#x02014;">
]>

しかし,使用しているエディターのBlueGriffonで対応しておらず,HTML文書が汚くなるのでこの方法は避けたかった。

今まで手作業でその都度修正していたが,煩雑だったので,簡単に処理したかった。

そこで,自分で埋め込みツイートのHTMLをXHTMLに変換するページTweet2XHTMLを作った。

Tweet2XHTML

[変換元HTML]のフォームに埋め込み用ツイートのHTMLコードを貼り付けて,[変換]ボタンを押下すれば,[変換後HTML]のフォームに整形されて表示される。

やっていることは非常に初歩的なことで,単にtextareaの文字列を正規表現で処理しているだけだ。メインの処理部分は以下となる。

<script>
  function convert() {
    var value = document.getElementById("input").value;
    value = value.replace(/<br>/g, "<br />");
    value = value.replace(/&mdash;/g, "—");
    value = value.replace(/<script.*<\/script>/g, "");
      var target = document.getElementById("output");
      target.value = value;
  }
</script>

<form>
  <fieldset>
    <legend>変換元HTML </legend>
    <textarea id="input" placeholder="ここに記入してね。" style="width: 100%; height: 10em;"></textarea>
    <button type="button" onclick="convert();">変換</button>
  </fieldset>
</form>
<form>
  <fieldset>
    <legend>変換後HTML</legend>
    <textarea id="output" placeholder="ここに表示される。" style="font-family: monospace; width: 100%; height: 10em;"></textarea>
  </fieldset>
</form>

これでTweetを備忘録にまとめるのが楽になった。もう少しJavaScriptやフォーム関連の操作方法を勉強してこういった簡単なユーティリティーを作れるようになりたい。

2016-05-15

WebベースGUIライブラリElectronのチュートリアルの実行

2016-05-11にElectron 1.0のリリースがアナウンスされた(実際のリリースは2016-05-09)。気になったので試しにチュートリアルのサンプルアプリの作成からパッケージ化までやってみた。

ElectronはGitHub社により作られた,クロスプラットフォームなデスクトップアプリを開発するためのライブラリとなっている。JavaScriptのライブラリであるNode.jsとブラウザであるChromiumをベースにHTML,CSS,JavaScriptなどのWeb技術で開発できるのが特徴となっている。最初のリリースは2013-07-15となっており,リリースが始まって約3年経過したことになる。時間が立って安定してきたので,1.0がリリースされたのだと思われる。

ネットで見ていてもElectronでのアプリ開発例をちらほらみかけるようになり,いいタイミングなのでちょっとだけ試してみることにした。

動作環境はUbuntu 14.04 64bitであり,チュートリアルとしてQuick Startを参照した。

少し長いので目次も書いておく。

  1. Electronのインストール
    1. npmのモジュールelectron-prebuiltをインストール
    2. 公式で配布されているバイナリをインストール
  2. サンプルアプリの作成・実行
    1. package.json
    2. main.js
    3. index.html
    4. サンプルアプリの実行
  3. パッケージング
    1. アプリディレクトリ丸ごとの配布
    2. asarコマンドでアプリディレクトリ.asarファイルに固めて配布
    3. Electronごと配布
  4. まとめ

Electronのインストール

Electronのインストール方法は2種類ある。

  1. npmのモジュールelectron-prebuiltをインストール。
  2. 公式で配布されているバイナリをインストール。

開発中であれば,どちらの方法でインストールしてもよい。しかし,最終的にパッケージングして配布するときは2.のバイナリを使うことになる。

npmのモジュールelectron-prebuiltをインストール

npmのモジュールであるelectron-prebuiltはビルド済みのElectronを含んでいる。以下のコマンドでインストールできる。

mkdir -p ~/local/
npm install -g --prefix=$HOME/local/ electron-prebuilt

npm install -gでインストールすると,既定では以下のディレクトリにインストールしようとする。

  • /usr/bin
  • /usr/lib/node_modules/

これらのディレクトリにインストールするには管理者権限が必要なので,--prefixオプションで以下のディレクトリにインストールされるように変更した。

  • $HOME/local/bin
  • $HOME/local/lib/node_modules/

.bashrcなどでexport PATH=$HOME/local/bin:$PATHなどと記述してPATH変数を設定しておく。これで,electronコマンドをインストールできた。以下のコマンドでelectronが起動する。

electron

npmでのインストール方法は以下を参照した。

npm のローカルモードでインストールした実行モジュールにパスを通す設定 - Qiita

公式で配布されているバイナリをインストール

Electronの各OS向けの最新のバイナリは以下のGitHubのページで公開されている。

Releases · electron/electron

ここから各OS,アーキテクチャ向けのelectronをダウンロードする。今回はUbuntu 14.04 64bitなので,electron-v1.1.0-linux-x64.zipをダウンロードして,展開し,~/local/opt/に配置した。

コマンドでやると以下のようになる。

mkdir -p ~/local/opt/; cd ~/local/opt/
VER=1.1.0
wget -nc https://github.com/electron/electron/releases/download/v$VER/electron-v$VER-linux-x64.zip
unzip -d electron-v$VER-linux-x64{,.zip}

electronを起動するときは以下のコマンドを入力する。

~/local/opt/electron-v1.1.0-linux-x64/electron

これでElectron自体のインストールは完了となる

サンプルアプリの作成・実行

まず,今回作るアプリの名前をyour-appとして作業ディレクトリを作る。

mkdir -p ~/tmp/your-app
cd ~/tmp/your-app

一般的に,Electronアプリは以下のディレクトリ構成となる。

your-app/
├── package.json
├── main.js
└── index.html

以下で各ファイルの簡単な説明とサンプルを示す。

なお,ファイル作成を簡単にするためにファイルサンプルの前後に以下のシェルコマンドを入れている。

cat << EOF > ファイル名
...
EOF

これにより,catからEOFまでをターミナルにコピーペーストするだけでファイルが作成できる。

package.json

package.jsonの形式はNodeのモジュールと同じで,mainフィールドでアプリのメインプロセスとして実行するスクリプトを指定する。例えば,以下のようになる。

cat << EOF > package.json
{
  "name"    : "your-app",
  "version" : "0.1.0",
  "main"    : "main.js"
}
EOF

package.jsonmainフィールドがなければ,Electronはindex.jsを読み込もうとする。

main.js

main.jsはウィンドウを作り,システムイベントを操作する。サンプルは以下となる。

cat << EOF > main.js
const electron = require('electron')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600})

  // and load the index.html of the app.
  mainWindow.loadURL('file://' + __dirname + '/index.html')

  // Open the DevTools.
  mainWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
  })
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow()
  }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
EOF
index.html

最後に,index.htmlは表示したいWebページだ。

cat << EOF > index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using node <script>document.write(process.versions.node)</script>,
    Chrome <script>document.write(process.versions.chrome)</script>,
    and Electron <script>document.write(process.versions.electron)</script>.
  </body>
</html>
EOF
サンプルアプリの実行

main.jsindex.htmlpackage.jsonを作ったら,アプリを実行してみよう。

npmelectron-prebuiltをインストールしていれば,以下のコマンドでアプリを実行できる。

electron .

バイナリをインストールしていれば,以下のコマンドでアプリを実行できる。

~/local/opt/electron-v1.1.0-linux-x64/electron .

electronコマンドにindex.htmlmain.jspackage.jsonが格納されているディレクトリを指定するとよい。

実行すると,以下のように開発者ツールの画面が開いた状態のウィンドウが表示される。

パッケージング

公式で紹介されているアプリの配布方法には以下の3通りがある。

  1. アプリディレクトリ丸ごとの配布。
  2. asarコマンドでアプリディレクトリを.asarファイルに固めて配布。
  3. Electronごと配布。

1と2は,配布するファイルサイズは小さいが利用者の環境にElectronがインストールされていないと動作しない。3は配布するファイルサイズは40 MB以上と大きくなるが,Electronごと配布するので,利用者の環境にElectronがインストールされていなくても動作する。利用者がElectronをインストールしていることは想定しにくいので,実際には3の方法を採用することになるだろう。しかし,2の方法は,.asarファイルにElectronを関連付けさせておけばダブルクリックで実行できるので悪くない方法だ。

なお,この他にサードーパーティーのパッケージ化コマンドとしてelectron-packagerelectron-builderなども存在するが,調査に時間がかかるので省略した。実際にアプリをリリースするときに検討すればよいだろう。

アプリディレクトリ丸ごとの配布

1の方法は,単に作成したアプリディレクトリ(今回は~/tmp/your-app)を配布するだけだ。利用者側ではelectronコマンドでこのディレクトリを指定すれば起動できる。

この方法だと,ユーザーにソースコードが丸見えなので,ソースコードをユーザーに隠したいときは使えない。

asarコマンドでアプリディレクトリ.asarファイルに固めて配布

事前にアプリ一式をasarコマンドで.asarファイルに固めて配布する。ユーザー側ではelectronコマンドで.asarファイルを指定することで実行できる。

ソースコードを利用者から隠したいときにこの方法が使える。

まず,npmからアプリを固めることができるasarコマンドをインストールする。

npm install -g --prefix=$HOME/lobal asar

そしてasarコマンドでアプリディレクトリを.asarファイルに固める。イメージとしてはtar.gzなどに圧縮するような感じだ。

asar pack your-app your-app.asar
# asar pack your-app{,.asar} ## シェルのブレース展開でこうしてもよい。

これで,以下のコマンドでElectronのアプリケーションを実行できる。

electron your-app.asar

.asarファイルをelectronコマンドで開くように関連付けさせればダブルクリックでも実行できるだろう。

Electronごと配布

利用者がElectronをインストールしていることは想定しにくいので,Electronごと配布する。

  1. 配布先OS用Electronのダウンロード

    まず,以下にOSごとのElectronが配布されているので配布先のOSのものをダウンロードする。

    Releases · electron/electron

    例えば,冒頭でも行ったがLinux版だと以下のコマンドでElectron本体をダウンロードして,解凍する。

    VER=1.1.0
    wget -nc https://github.com/electron/electron/releases/download/v$VER/electron-v$VER-linux-x64.zip
    unzip -d electron-v$VER-linux-x64{,.zip}

    なお,解凍後のディレクトリはelectron-v1.1.0-linux-x64というようなOSごとのディレクトリ名になっている。説明を簡単にするために,このディレクトリを単にelectronと表記する。

  2. アプリ一式をasarコマンドでapp.asarに固める。

    ファイル名をapp.asarにしてasarコマンドでアプリ一式を固める。後からファイル名をapp.asarに変えるだけでもよい。

    例:

    asar pack your-app app.asar
    ## または以下のように既に固めたasarファイルのファイル名を変えるだけもよい。
    # asar pack your-app your-app.asar
    # mv your-app.asar app.asar
  3. 固めたapp.asarをElectronに配置。

    配布先OSに応じて以下の場所にapp.asarを配置する。

    app.asarの配置場所
    OS 配置場所

    electronは展開したElectronのディレクトリのこと。例:electron-v1.1.0-linux-x64。
    OS X electron/Electron.app/Contents/Resources/
    Windows, Linux electron/resources/

これでパッケージングは完了だ。後はelectronディレクトリに存在する,OSごとのelectronファイルをダブルクリックなどで起動するとアプリが実行される。

OS毎のelectronの実行ファイル名
OS ファイル名
Linux electron
Windows electron.exe
OS X electron.app

必要に応じて,上記の実行ファイル名electronをアプリケーションの名前に変更したり(例:your-app),アイコンを設定すればパッケージングは完了となる。

まとめ

Electronの導入として,公式サイトのチュートリアルをやってみて,パッケージングの方法までまとめた。

チュートリアルをやっていて躓いたのは,Electronごとパッケージ化の際のファイル名だった。app.asarというファイル名はただのサンプルかと思っていたらそうではなくて,このファイル名でなければならなかった。これに気づくのに時間がかかってしまった。

実際にアプリを作成するにはmain.jsの書き方や使えるモジュールなど細かく見ていかなければならない。この記事を,今後Electronでアプリを作成する際の足がかりしていきたい。

2016-05-10

Install GLFW 3.1.2 from source on Ubuntu 14.04

GLFWというOpenGLでGUIを簡単に作るためのC言語のライブラリが公開されており,興味を持ったのでUbuntu 14.04にソースからインストールしてみた。

公式サイトからファイルをダウンロードしてインストールする。インストール方法は以下の公式サイトを参照する。

GLFW: Compiling GLFW

基本的にはファイルを展開してcmakeを実行するだけだ。標準では/usr/local/にインストールされてしまう。管理者権限は使わずに,stowで管理したいので,cmakeの実行時にインストール先を指定した。

VER=3.1.2
cd ~/local/src
wget -nc https://github.com/glfw/glfw/releases/download/$VER/glfw-$VER.zip
unzip glfw-$VER.zip
cd glfw-$VER
mkdir glfw-build
cd glfw-build
cmake ../ -DCMAKE_INSTALL_PREFIX:PATH=$HOME/local/stow/glfw-$VER
make install
cd ~/local/stow/
stow glfw-$VER

思っていた以上に簡単にインストールできた。

なお,stowでインストールするにあたって,~/.bashrcなどで以下のように各種PATHを設定している。GLFWではpkg-configを使うので,忘れずにPKG_CONFIG_PATHを設定しておく。

  ### local install path
  LOCAL="${HOME}/local"
  export PATH="${LOCAL}/bin:$PATH"
  export LD_LIBRARY_PATH="${LOCAL}/lib:$LD_LIBRARY_PATH"
  export CPATH="${LOCAL}/include:$CPATH"
  export MANPATH="${LOCAL}/man:${LOCAL}/share/man:$MANPATH"
  export INFOPATH="${LOCAL}/info:${LOCAL}/share/info:$INFOPATH"

  export PKG_CONFIG_PATH="${LOCAL}/lib/pkgconfig:${PKG_CONFIG_PATH}"

早速サンプルプログラムをビルドしてみる。

サンプルは以下に示す公式サイトのものを使用する。

// \file example.c

#include <GLFW/glfw3.h> int main(void) { GLFWwindow* window; /* Initialize the library */ if (!glfwInit()) return -1; /* Create a windowed mode window and its OpenGL context */ window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL); if (!window) { glfwTerminate(); return -1; } /* Make the window's context current */ glfwMakeContextCurrent(window); /* Loop until the user closes the window */ while (!glfwWindowShouldClose(window)) { /* Render here */ /* Swap front and back buffers */ glfwSwapBuffers(window); /* Poll for and process events */ glfwPollEvents(); } glfwTerminate(); return 0; }

GLFWのプログラムのビルド手順は以下を参考にする。

GLFW: Building applications

GLFWではpkg-configを使って必要なライブラリをリンクする。以下のようにpkg-configの実行結果をコンパイル時の引数に渡してやる。

cc -o example.{exe,c} $(pkg-config --cflags --static --libs glfw3)

不要かなと思っていたのだけど,なぜか--staticがないとビルドできなかった。ビルドできたら以下のコマンドで起動してみる。

./example.exe

これで以下の真っ黒なウィンドウが表示される。なお,ファイラーからダブルクリックでexample.exeは起動できないようだ。PATHを通したりアプリと同じ場所にlibglfw3.aを配置してもダメだった。cmakeでビルドしないとダメなのかもしれない。cmakeは使い方をよく知らないのでまた勉強しよう。

Windows 10では,MSYS2のpacmanからインストールしたらうまくいったのを確認できた。MSYS2でGLFWをソースからインストールしようとcmakeを実行するとWindowsのビルド環境を認識してしまいうまくいかなかった。

pacman -S --noconfirm mingw-w64-x86_64-glfw

ビルドコマンドは先ほど掲載したUbuntu 14.04でのものと同じでうまくいった。

Windowsでは/mingw64/bin/glfw3.dllをアプリと同じディレクトリに入れておけばExplorerからも起動できた。ただし,起動したら一瞬で閉じられてしまった。

ひとまずこれでGLFWでアプリを作る準備はできただろう。

2016-05-08

Vimで特定ファイルタイプでだけキーマップを無効化

Vimのノーマルモードの改行(<CR>)には,挿入モードと同じようにその場で改行できるように~/.vimrcに以下のキーマップを割り当てている。

nnoremap <CR> i<CR><ESC>

しかし,quickfix-windowやロケーションウィンドウ(ファイルタイプ:qf)やでは改行で対象箇所にジャンプする機能がある。上記キーマップがあるため,<CR>を入力すると以下のエラーが出てうまくジャンプできない。

E21: Cannot make changes, 'modifiable' is off

オプションmodifiableがoffになっているのにファイルを修正しようとしてエラーになってしまっている。

このジャンプの機能は残しておきたいので,quickfix-windowでは自分で定義した上記のキーマップを無効化したい。

以下のサイトで特定ファイルタイプでキーマップを無効化する方法が記されている。

参考:特定のファイル種別の時だけキーマップを無効化する方法 - かせいさんとこ

これによると,特定ファイルタイプでだけバッファーローカルの設定でグローバルな設定を上書きすればよいとのことだ。つまり,以下の内容のファイルタイプごとの設定ファイル~/.vim/after/ftplugin/qf.vimを作ればよい。

" \file qf.vim

if exists("b:did_ftplugin_qf") | finish | endif let b:did_ftplugin_qf = 1 "" Disable line break nnoremap <buffer> <CR> <CR>

ここでは,自分で定義した<CR>をもともとの<CR>に割り当て直している。

これで特定ファイルでだけキーマップを無効化できた。

2016-09-24追記:実際のところ,今回実現したいことは上記のように個別のファイルでの設定は不要で簡単にできた。以下の内容を~/.vimrcに記入すればいい。

"" Insert line break by Enter
autocmd BufEnter * if &modifiable | nnoremap <buffer> <CR> i<CR><ESC> | endif

autocmdでバッファーを開くたびに,modifiableが有効かどうか判定し,有効であるときだけそのバッファーでキーマップを有効にしている。これにより,QuickFixだけでなく,VimのHelpなどでもキーマップを無効(厳密には未設定なだけ)にでき,Enterでタグジャンプできる。

2016-05-04

VimのQuickFix-windowを自動で開く設定

quickfix-window(QuickFixウィンドウ)は自動で開かれないので,自分で:cwで開かないといけない。

以下の設定を記述すると,該当するQucikFixコマンドを実行して,対象があるときだけ自動的にquickfix-windowを開いてくれる。

autocmd QuickfixCmdPost make,grep,grepadd,vimgrep cwindow

vimでquickfixを自動で開く - Webtech Walker

作業中のファイルとquickfixで確認・修正するウィンドウは別にしたほうが作業しやすいと思う。quickfix-windowを新しいタブで開くには以下のようにする。

autocmd QuickfixCmdPost make,grep,grepadd,vimgrep tab cwindow

Vim quickfix list launch files in new tab - Stack Overflow

quickfix-windowでは,Enterで該当ファイルの該当箇所にジャンプできる。しかし,たくさん見比べるときはタブで開きたいときがある。新しいタブで開きたければ,以下のキーバインドを使えばいい。なお,^[はC-vを押して,Alt+Enterを押して直接制御文字を入力する。

nnoremap ^[ <C-W><CR><C-W>T

これで,quickfix-windowでAlt+Enterで該当ファイルの該当箇所を新しいタブで開ける。

ターミナルの制約で,C-CRやS-CRにキーを割り当てるのは難しいみたい。

参考:

2016-05-17追記

上記のキーバインドは,Windowsなどで使えなかったりする。可搬性が下がるのでやめておこう。

代わりに以下の内容の~/.vim/after/ftplugin/qf.vimを作成しよう。

if exists("b:did_ftplugin_qf") | finish | endif
let b:did_ftplugin_qf = 1

"" open new tab nnoremap <buffer> t <C-W><CR><C-W>T

この設定により,quickfix-windowでだけ,tで現在カーソルのファイルを新しいタブページで開ける。<C-W>Tのキーで現在のバッファーを新しいタブページに異動させる。このキーは普段使いでも便利そうなので覚えておこう。

JScriptのWScript.Echo()とJavaScriptのconsole.log()の共通化

JScriptで書いたコードがJavaScriptでも動作するように調整する。

メッセージの表示でよく使うWScript.Echo()console.log()を共通化する。try-catch文で実際に関数を実行して成功するかどうかで判定する。

function print(text){
try {
console.log(text);
} catch (e) {
WScript.Echo(text);
}
}

print("HI");

このようにprint()というWrapper関数を作ってしまえば,JScriptとJavaScriptのどちらでも使える。

以下のようにif文でconsoleオブジェクトの有無で判定すると,オブジェクトが存在しなければ,エラーが表示されてしまう。tryで実際に試してエラーを検知したほうが確実だ。

if (typeof(console)) console.log(text);
else WScript.Echo(text);

2016-08-14追記:これはif文のやりかたが悪かっただけだった。以下のようにきちんとやれば問題ない。

if (typeof(print) === "undefined"){  // for SpiderMonkey
  function print(text){
    if      (typeof(console) !== "undefined") console.log(text );
    else if (typeof(WScript) !== "undefined") WScript.Echo(text);
  }
}

SpiderMonkeyではprint関数が既にあるので,if文を関数定義の前に書いて回避している。