はじめに(やりたいこと)
大学の課題で、実行結果をコードの最後にコメントとして貼り付けて提出なさい、と言われて作ったものです。
一瞬Emacsに乗り換えそうになりました。
Vimscriptで自動化できないかやってみたものです。C言語以外にも使うことができると思います。
引数などには(まだ)対応していません。
できたもの
以下のようなものが出来上がりました。下の方に説明があります。
:function! RRFunction()
:w
:let compile = system('gcc -o temp.out '.expand('%:p'))
:call append(line('$'), split("/*", "", 1))
:if !v:shell_error
:call cursor(line('$'), 0)
:r!./temp.out
:call system('rm -f temp.out')
:else
:call append(line('$'), split(compile, "\n", 1))
:endif
:call append(line('$'), split("*/", "", 1))
:endfunction
:command RR :call RRFunction()
動作
以下のようなC言語のソースがあるとします
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a, b;
printf("A: ");
if (scanf("%d", &a) != 1) {
printf("incorrect input\n");
exit(1);
}
printf("B: ");
if (scanf("%d", &b) != 1) {
printf("incorrect input\n");
exit(1);
}
printf("A * B = %d\n", a * b);
return 0;
}
:RR
で保存とコンパイルなどをして、実行を開始します。
コンパイル時にエラーが発生した場合はコメントにgccからのエラーをコメントアウトしてコードファイルの最後に挿入します。
ユーザーの入力を受け付ける場合は(何も表示されませんが)入力することができます。
実行が終了すると実行結果をファイルの最後に挿入します。
エラーなどがない場合
:RR
の後、4<Enter>8<Enter>
と入力した場合の結果です。
ユーザーからの入力は挿入されません(仕様です)
/* 省略 */
return 0;
}
/*
A: B: A * B = 32
*/
エラーがある場合
main関数の最後の閉じ括弧}を削除して実行してみます。
/* 省略 */
return 0;
/*
/Users/###/###.c:18:11: error: expected '}'
return 0;
^
/Users/###/###.c:5:1: note: to match this '{'
{
^
1 error generated.
*/
説明など
バックグラウンドでシェルコマンドを実行する
system関数でシェルコマンドをバックグラウンドで実行することができます。
:!
を使う方法ではいちいちEnterが必要なのでこれを省くことができます。
:let result = system('pwd')
:echo result
" -> /Users/###
実行の成功可否を調べる(シェルからの戻り値を取得)
Vim scriptではシェルコマンドの実行が成功したか失敗したかの結果がv:shell_error
に格納されます。
成功した場合
:let result = system('gcc file.c')
:echo v:shell_error
" -> 0
失敗した場合
:let result = system('gcc nosuchfile.c')
:echo v:shell_error
" -> 1
ファイルの最後の行番号を取得する
line('$')
とすることでファイルの最後の行番号を取得することができます。
:echo line('$')
" -> 19
ちなみに: line('.')
で現在のカーソルの行番号です。
system関数で取得した結果をappendで出力
何も考えずそのまま出力
:let result = system('cal')
:call append(line('$'), result)
このようにするとファイルの最後に
9月 2015^@日 月 火 水 木 金 土^@ 1 2 3 4 5^@ 6 7 8 9 10 11 12^@13 14 15 16 17 18 19^@20 21 22 23 24 25 26^@27 28 29 30^@^@
と改行がおかしくなりかなりイヤな感じで出力されます。
解決案
そこでsplitを利用してみました。
:let result = system('cal')
:call append(line('$'), split(result, "\n", 1))
このようにすれば
9月 2015
日 月 火 水 木 金 土
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
と改行も綺麗に出力してくれました。