teratermマクロをvimで書くときの設定

シンタックスファイル

補完するほどじゃないと思うけど、色がついてくれることで間違いに気づける。

http://hp.vector.co.jp/authors/VA048353/garage.html
上記のサイトで公開されてるものを使わせてもらう。ただ足りない部分もあるので継ぎ足す。

  • 新しいTTLコマンド
  • 文中コメント
  • ブロックコメント
  • 文字列リテラルをASCIIコードで表現する記法

編集したやつ。
https://gist.github.com/3154584

--- ttl.vim.orig	Sat Jul 21 12:22:09 2012
+++ ttl.vim	Sat Jul 21 13:29:34 2012
@@ -4,14 +4,21 @@
 if version < 600
     syntax clear
 elseif exists("b:current_syntax")
-    finishendif
+    finish
+endif
 
-syn keyword ttlStatement    goto call end include return call execcmnd exit pause
+syn keyword ttlStatement    goto call end include return call execcmnd exit pause mpause
 syn keyword ttlRepeat       for next while endwhile
+syn keyword ttlRepeat       do loop break untile enduntil
 syn keyword ttlConditional  if then elseif else endif
 
 syn keyword ttlOperator     and not or xor
-syn keyword ttlArgument     inputstr param2 param3 result timeout 
+
+" system variables
+syn keyword ttlArgument     param1 param2 param3 param4 param5 param6 param7 param8 param9 paramcnt
+syn keyword ttlArgument     groupmatchstr1 groupmatchstr2 groupmatchstr3 groupmatchstr4 groupmatchstr5
+syn keyword ttlArgument     groupmatchstr6 groupmatchstr7 groupmatchstr8 groupmatchstr9 matchstr
+syn keyword ttlArgument     result timeout mtimeout inputstr 
 
 syn match ttlOperator       "\s[-+\*/%]\s"
 syn match ttlOperator       "="
@@ -19,13 +26,16 @@
 
 syn match ttlString         "\"[^"]*\""
 syn match ttlString         "\'[^']*\'"
+syn match ttlString         "#1[0-1][0-9]\|#1[2][0-7]\|#[1-9][0-9]\|#[1-9]"
+syn match ttlString         "#$[0-7]\x"
 
-syn match ttlLabel	    "^\s*:\s*\h\w*\>"
+syn match ttlLabel          "^\s*:\s*\h\w*\>"
 syn match ttlLabel          "\<\(goto\|call\)\s\+:\h\w*\>"
-syn match ttlLabel	    "\<goto\s\+\h\w*\>"
-syn match ttlLabel	    ":\h\w*\>"
+syn match ttlLabel          "\<goto\s\+\h\w*\>"
+syn match ttlLabel          ":\h\w*\>"
 
-syn match ttlComment        "^[ \t]*;.*$"
+syn match ttlComment        ";.*$"
+syn region  ttlComment      start="/\*"  end="\*/"
 
 syn keyword ttlImplicit     bplusrecv bplussend changedir clearscreen closett
 syn keyword ttlImplicit     connect disconnect enablekeyb flushrecv gettitle
@@ -49,6 +59,23 @@
 
 syn keyword ttlImplicit     beep closesbox exec getdate getenv gettime inputbox messagebox
 syn keyword ttlImplicit     setdate setdlgpos setexitcode settime show statusbox yesnobox
+
+" new ttl commands
+syn keyword ttlImplicit     callmenu cygconnect dispstr gethostname loginfo scprecv scpsend 
+syn keyword ttlImplicit     sendbroadcast sendlnbroadcast sendmulticast setbaud setdebug setdtr
+syn keyword ttlImplicit     setmulticastname setrts wait4all waitn waitregex ymodemrecv ymodemsend
+
+syn keyword ttlImplicit     expandenv sprintf sprintf2 strinsert strjoin strmatch strremove
+syn keyword ttlImplicit     strreplace strspecial strsplit strtrim tolower toupper
+
+syn keyword ttlImplicit     basename dirname filelock fileread filestat filetruncate fileunlock
+syn keyword ttlImplicit     foldercreate folderdelete foldersearch getfileattr setfileattr
+
+syn keyword ttlImplicit     ispassword setpassword
+
+syn keyword ttlImplicit     clipb2var crc32 crc32file filenamebox getspecialfolder getttdir getver 
+syn keyword ttlImplicit     ifdefined intdim random rotateleft rotateright setenv strdim var2clipb
+
 
 if version >= 508 || !exists("did_ttl_syntax_inits")
     if version < 508

vimrc

filetypeの設定とか。

autocmd BufWinEnter,BufNewFile *.ttl setlocal filetype=ttl
" for NERD_commenter
autocmd Filetype ttl setlocal commentstring=;\ %s
" for quickrun
let g:quickrun_config['ttl'] = {'command': 'ttpmacro' }

サブルーチン

あとは設定ではなくて、teratermマクロを書くときにこうしたよという話。
teratermマクロにはサブルーチンがあるのだけど、引数や戻り値がないので使い勝手が悪い。かといって、まとめられる処理をベタ書きにするのも地獄なので、予め入力と出力用の変数を決めておいて、サブルーチン呼び出し前にそれらを初期化し、サブルーチン内で出力用変数に値を入れるようにすると、まあまあすっきりする。cobolっぽい。プリフィクスにIN_とかOUT_とかつけるルールにするとまあ見やすいかも。cobolぽく。

日付の計算

今のところTTLコマンドには日時に関するものはあまりなくて、一日前の日付なんか取得できない。なので、サーバにログインした後、日付を計算するコマンドを発行してから、その結果を受け取る。具体的には、sendlnでdateコマンドをログイン先のシェルに実行させて、その出力をwaitlnで受け取る。

sendln 'date "%a %Y%m%d" -d "20120721 1 days"'
waitln 'invalid' 'Sun' 'Mon' 'Tue' 'Wed' 'Thu' 'Fri' 'Sat'
messagebox inputstr 'test'

確認してないけど(!)こんな感じ。dateコマンドのエラーメッセージは環境で変わるだろうし、正常な出力結果として曜日をベタ書きにしてるのが、うわって感じがする。

はまったところ

  • 文字列変数は255文字まで! 長いコマンドを作成して、一度に終わらせようと思っても255文字以降は変数に格納されない。
  • 文字列の比較は=演算子ではできない! strcompareコマンドを実行後、システム変数resultの値を確認すること。
  • もうひとつあった。文字コードSJISじゃないと実行できなかった。マクロの文字コードについて、リファレンスに注意書きがないので、もしかしたら何か別の原因なのかもしれないけど。

vimperatorで時計の表示

表示領域を少しでも広く使いたいときに、Windowsではタスクバーを隠して使いたいのだけど、時計は見たい。何故なら時間を気にしながらじゃないと延々とインターネットしてしまう。だからvimperatorに時計を表示させたい。そんなときはclock.jsと思ってロードすると、

clock.js: not found the commandline.

なんてエラーメッセージが出る。もともとclock.jsはコマンドラインの右端に時計を出すプラグインのようで、今のvimperatorはコマンドライン(のバー)がないよってことなのかな。vimperatorのxulをぼんやり眺めると、下に表示されてるバー(vimのステータスラインぽいもの)がbottombarというものかな、多分そんな気がする。そこに時計が出ればな。windowsのタスクバーは不要になるのにな。clock.jsを無理やり動かすしかないな。

ブラウザのコンポーネントいじるjsってよく分かってないので、試しにいじったら動いたというレベル。localNameがstackじゃないとどういう事態なのとか、全く分かってない。

diff --git a/clock.js b/clock.js
index 2897a01..baafaa8 100644
--- a/clock.js
+++ b/clock.js
@@ -337,9 +337,7 @@ function year() {
 // node control
 function getCommandlineStack() {
-    let messageTextarea = window.document.getElementById('liberator-message');
-    let commandlineStack = messageTextarea.parentNode;
-    return commandlineStack.localName === 'stack' ? commandlineStack : null;
+    return window.document.getElementById('liberator-bottombar');
 }
 
 } )();

.vimrcに最近追加したもの

自動で構文チェック

rubyphpで書く用。保存時にシンタックスチェックが走って、エラーがあればQuickFixが開く。直れば閉じる。
phpに関しては、vimインストール時に同梱されてるコンパイラプラグインだと僕の環境に合ってなくて、makeprgに解釈できないオプションが付いてて実行時に固まってしまったり、errorformatが上手くマッチしなかったりする。かといってインストールされたものを修正するよりかは自前のvimrcで整えたい。
phpのerrorformatはwindowsのxammpのもので確認しながら書いた。手探りで書いたのであまりよく分かってない。

augroup My
    autocmd!
    autocmd FileType ruby setlocal makeprg=ruby\ -cw\ %
    autocmd FileType php  setlocal makeprg=php\ -l\ %
    autocmd FileType php  setlocal errorformat=%-E,%m\ in\ %f\ on\ line\ %l,%ZErrors\ parsing\ %f
    autocmd BufWritePost *.php,*.rb silent make
    autocmd QuickFixCmdPost make cw 3
augroup END

tagsの設定

tagsオプションの末尾に;をつけておくと、ディレクトリを遡ってtagsファイルを探しに行ってくれる。

if has('path_extra')
    set tags+=.tags;
endif

tagsファイルを生成する場所

生成する場所について、ネットを見回してもこうしてますといった話がない。ctagsコマンドの説明の上で、こうすればカレントディレクトリにtagsファイルができますといった程度で、そんなことしてたらあらゆる場所にtagsファイルが散乱するじゃないか。そういうものなの? それはそれとして、僕はプロジェクトルートとなる場所に一つだけできて欲しい。カレントディレクトリはバッファの場所になるよう設定してるし、どうしようかな…と考えた結果、自分の場合は.git/がある場所に決め打ちすることにした。
ファイル保存時にctagsコマンドが走るようにしたんだけど、今のところ100行前後の小さいものでしか動作させてないので、まともなプロジェクトで走らせたら重くてしょうがなくなるかもしれない。

augroup Ctags
    autocmd!
    autocmd BufWritePost *.vim,*.php,*.rb silent call s:ctags()
    autocmd BufWinEnter .tags setlocal filetype=tags
augroup END

function! s:ctags()
    let l:project_root = s:search_dir('./')
    if exists('l:project_root')
        call system("cd ". shellescape(l:project_root) .
                    \" && ctags -R " . " -f " .  shellescape(l:project_root . ".tags"))
    endif
endfunction

function! s:search_dir(dir)
    if !has('file_in_path')
        return
    endif
    let l:save_path = &path
    if &path[-1:-1] != ';'
        set path+=;
    endif
    let l:dir = finddir(a:dir)
    if l:dir =~ a:dir . '$'
        let l:dir = substitute(l:dir, a:dir . '$', '', '')
    endif
    let &path = l:save_path
    return l:dir
endfunction

gvimrc_local.vim

KaoriYa版を使わせてもらってるんだけど、今まではインストール時に同梱されてるgvimrcに直接手を入れて使ってた。gvimrc_local.vimがgvimrcに先立ってロードされて、さらに下記の設定しておくとgvimrc読み込みを抑止するんですね、ということを知ったので、gvimrc_local.vimには必要な気がするものだけgvimrcからコピペして使ってる。gvimrcにちゃんと書いてあるのにね…。vimrc_local.vimについても同様にした。

" $VIM/gvimrcで設定を上書きしない
let g:gvimrc_local_finish = 1

日本語の設定

KaoriYa同梱のencode_japan.vimまかせにするようにした。それまでは、ずんwikiというところで紹介されていた設定をコピペしていたんだけど、リローダブルじゃなかったのに最近気付いた。特に困ったこともなかったんだけど。

初めて自分でvim script書いた。
職場で日次でファイルを作成してメモを取ることをしていて、毎朝yyyymmdd.txtを作るバッチを叩いている。具体的な手順は、vimでバッチを開いて、quickrunさせて、結果とバッチの2つのバッファを閉じて、生成したメモ用ファイルを開く。面倒くさい。キーストロークふたつくらいでできたい。

function! s:OpenTodayLog()
    let l:dir =  expand('~/log')
    if !isdirectory(l:dir)
        call mkdir(l:dir)
    endif
    execute ':edit ' . l:dir . '/' . strftime('%Y%m%d') . '.txt'
endfunction
command! -nargs=0 TodayLog call s:OpenTodayLog()
nnoremap <Leader>l :TodayLog<CR>

初めてちゃんとvim scriptを書いた。コマンド定義してからキーマッピングしてるのが冗長で、本当はキーマッピングに直接関数呼び出しを指定できたらいいんだけど、SIDがないとか、それはスクリプトローカルな関数だからとか、もうちょっとどうすべきかヘルプ読んで決めなくちゃと思う。特にSIDがよくわからない。

なんとなく.vimrc読み返してたら、殆ど同じ記述があって驚いた。
http://vim-users.jp/2010/11/hack181/
上記サイトの:JunkFileコマンドを、そのままコピペして使ってなかったものだった。あー車輪再発明した、けれども、おっかなびっくり書いた自分のスクリプトが間違った書き方ではない(小物スクリプトではあるものの)と思って安心はした。

追記

コメントをもらって、キーマップから関数呼び出しの書き方を教わったので.vimrcをそのように直した。
動きを確認してからヘルプを読んだら、最初に読んだときに分からなかったことが少し分かった気がする。SIDはmapコマンドの変換処理を挟んで、スクリプトローカルなスコープを解決する修飾子みたいなものになると理解しました。
# 英語を読むときも、ある程度あたりがついてないと読めないなあ。

SQL ゼロからはじめるデータベース操作を読んだ

CD付 SQL ゼロからはじめるデータベース操作 (プログラミング学習シリーズ)

CD付 SQL ゼロからはじめるデータベース操作 (プログラミング学習シリーズ)

ミックさんが書いた初心者向けの本。そうだったのかと思う部分がたくさんありました。
以下、改めて知ったことや良かったこと。

  • つまづきやすいところが書かれてある
    • WHERE句に取れる式の制限とか
  • 書ける場所、書けない場所を教えてくれている
  • 句の実行順序
    • 上ふたつのことも、実行順序が分かっていればだいたい理屈で納得できる
  • 主要なDBMSでの記法をサポートしてる
  • SQL標準で書くことを推奨してる
    • 例えば僕はテーブル結合でjoin句を使ってなかった
    • そもそも何がSQL標準か、何がそうでないかを知らなかった
  • ところどころで中級への道を示している
    • EXISTS述語とIN述語の違い
    • 関係除算
    • NOT IN述語にNULLを取ったときの動作

これを書いてる途中でおさらいをしたんだけど、相関サブクエリの動作イメージが分かった。気がする。SQLの実行順は内側から、つまりサブクエリから展開されていくというのに捕らわれていて、相関サブクエリ内のバインドの部分を解釈できないでいた。サブクエリ単体で見ると、バインドの値が未定で表が出来上がらないから。じゃあ逆にと思って外側からレコード一行ずつ見ていくと、バインドする値は当然決まるし、そうなると相関サブクエリが返す値はひとつに絞られてWHERE句に収まることができる。すっきりした。

やっぱり分からないのは関係除算で例に出てたSQL。EXISTSと相関サブクエリの関係をよくわかってることが前提なのかな。EXCEPTで差集合を取ってるのだけど、引く側が引かれる側を内包してる(と思う)ので空集合になるのではないか、とかよく分からない。今後の課題。

ubuntu 10.04をインストールした。DELLのLatitude D400に。一度無邪気に9.04からアップグレードさせたら起動画面から真っ黒になって動かなくなって悲しい思いをしたので、以来慎重になっていたのだけど、LPIに受かったので腕試しのつもりでやってみた。とはいえハードウェアのことは全然分からない。検索してみて、対策とされているものを調べながらひとつずつlive cdでオプションを試していく。

ここに辿り着くまでに、他所のサイトで見たオプションを幾つか試した。

quiet splashを外す

起動時のカーネルメッセージを画面に出力してくれるようになった。全部の意味は分からないけど、何の処理らへんでつまってるか分かるかも。

xforcevesa

ドライバをvesaというものに変えるオプション。これをつけるとテキストモードでは起動するまでには至った。startxを打つとエラーが出て終わる。

i915.modeset=1

ワークアラウンドの最初にある対策。結果、これでXが起動するようになった。インストール後は速やかにmenu.lstを書き換えてupdate-grubすること。システムの更新で再起動を要求されたときにうっかりOKを押してしまうし、またブラックアウトすることになった。

無事10.04が動いたので初期設定などしていたんだけどFirefoxがすごく重い…。

LPI対策

LPIのレベル1に合格しました。Linuxには多少慣れていたので苦労しなかったのですが、受験料が安くないので失敗はできません。どう勉強したかというのを少し書きます。

試験は結局暗記であるので、効率よく記憶するには手を動かす必要がある。自分の環境を作ってそのなかで遊ぶために、仮想環境の構築をしました。重いソフトウェアは嫌なので、coLinuxを選びました。(普段使ってるOSはWindowsです。)またパッケージ管理の問いでdebian系とRedHat系の二通りあるので、debianfedoraを選びました。これらのOSにはTeraTermProで接続します。Windowsのコンソールより使いやすいし、さらにGnu screenを使えばひとつのウィンドウで済むのでAlt+tabでガチャガチャアプリケーションを探さなくて済みます。sshの勉強にもなる。

まとめ

    • coLinux軽い
    • 複数起動して比較できる(他のだと重くて複数起動する気になれないというだけ…)
    • ネットワーク、ロケールタイムゾーンの設定は自分でやるので自然に身につきますね