2024年12月16日月曜日

Vim 本体に evalfunc (Vim script 関数) を追加する

この記事は Vim 駅伝 の 2024/12/16 の記事です。 前回の記事は yuys13 さんによる、 2024/12/13 の「ソフトウェア技術者とコミュニティ活動~vim-jp radioに出演しました~」という記事でした。

次回は 2024/12/18 に投稿される予定です。

この記事はなに?

少し前に Vim script 関数を追加する Pull Request を出したので、その流れを忘れないように記録するための記事です。

VimConf 2024 の Kato さんのセッションとかぶってしまっていますが、実装の一例として見ていただくのがいいかと思います。 セッションの方がより深掘りされているので、視聴がおすすめです。

今回は、足し算をする関数を追加してみる。

前提

  • Vim のビルド環境が整った状態からスタート

手順概要

  1. 関数の実体を実装
  2. 関数のエントリーポイントを追加
  3. ドキュメントを追加
    1. 関数の説明を追加
    2. タグを追加
    3. 関数リストに追加
  4. 関数のテストを実装

実装

関数の実体を実装

evalfunc.c:

一番下に、実装する。

diff --git a/src/evalfunc.c b/src/evalfunc.c
index b2905da2a..99527029e 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -12125,3 +12125,9 @@ f_xor(typval_T *argvars, typval_T *rettv)
 }
-
 #endif // FEAT_EVAL
+
+    int
+add_num(int x, int y)
+{
+    return x + y;
+}

関数のエントリーポイントを追加

引数パターンの確認

今回追加するのは、ふたつの引数がそれぞれ「数値」、「数値」の引数を持つ関数。

Lists of functions that check the argument types of a builtin function. と コメントされている行から下に、引数のパターンごとに変数がつくられている。

今回追加したいパターンの引数の組み合わせは arg2_number[] となる。

エントリーポイント関数の追加

evalfunc.c:

今回は、さきほど実装した「関数の実体」の直後にエントリーポイントを実装し、プロトタイプ宣言も追加する。

diff --git a/src/evalfunc.c b/src/evalfunc.c
index 99527029e..8fcdaaf60 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -194,6 +194,7 @@ static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
 static void f_windowsversion(typval_T *argvars, typval_T *rettv);
 static void f_wordcount(typval_T *argvars, typval_T *rettv);
 static void f_xor(typval_T *argvars, typval_T *rettv);
+static void f_add_num(typval_T *argvars, typval_T *rettv);
 
 
 /*
@@ -12131,3 +12131,26 @@ add_num(int x, int y)
 {
     return x + y;
 }
+
+/*
+ * "add_num(number, number)" function
+ */
+    static void
+f_add_num(typval_T *argvars, typval_T *rettv)
+{
+    // argvars[] の第一引数と第二引数の型チェック
+    if (in_vim9script()
+           && (check_for_number_arg(argvars, 0) == FAIL
+               || check_for_number_arg(argvars, 1) == FAIL))
+       return;
+
+    // argvars[] から第一引数と第二引数を取得
+    int x = tv_get_number_chk(&argvars[0], NULL);
+    int y = tv_get_number_chk(&argvars[1], NULL);
+
+    // 戻り値に計算結果を格納
+    rettv->vval.v_number = add_num(x, y);
+
+    return;
+}
+

エントリーポイント定義の追加

evalfunc.c:

1758 行目くらいからあるエントリーポイントの定義に、今回実装したエントリーポイントの定義を追加する。

diff --git a/src/evalfunc.c b/src/evalfunc.c
index 99527029e..d51b6ac1f 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -1758,6 +1758,8 @@ static funcentry_T global_functions[] =
                        ret_float,          f_acos},
     {"add",            2, 2, FEARG_1,      arg2_listblobmod_item,
                        ret_first_arg,      f_add},
+    {"add_num",        2, 2, 0,            arg2_number,
+                       ret_number,         f_add_num},
     {"and",            2, 2, FEARG_1,      arg2_number,
                        ret_number,         f_and},
     {"append",         2, 2, FEARG_2,      arg2_setline,

各定義は以下の通り。

  1. 関数名
  2. 最小引数数
  3. 最大引数数
  4. メソッドとして利用できる引数の位置
  5. 引数の組み合わせ
  6. 戻り値の型
  7. 実際に呼び出すエントリーポイント

ドキュメントを追加

関数の説明を追加

runtime/doc/builtin.txt に関数のドキュメントを辞書順になるように追加する。

diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index d0f0c7b03..7370091a0 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -26,6 +26,7 @@ USAGE                         RESULT  DESCRIPTION     ~
 abs({expr})                    Float or Number  absolute value of {expr}
 acos({expr})                   Float   arc cosine of {expr}
 add({object}, {item})          List/Blob   append {item} to {object}
+add_num({number}, {number})    Number  add two number
 and({expr}, {expr})            Number  bitwise AND
 append({lnum}, {text})         Number  append {text} below line {lnum}
 appendbufline({buf}, {lnum}, {text})
@@ -833,6 +834,12 @@ add({object}, {expr})                                      *add()*
                |Blob|
 
 
+add_num({number}, {number})                            *add_num()*
+               Add two {number}.
+
+               Return type: |Number|
+
+
 and({expr}, {expr})                                    *and()*
                Bitwise AND on the two arguments.  The arguments are converted
                to a number.  A List, Dict or Float argument causes an error.

タグを追加

runtime/doc/tags に関数のドキュメントのタグを辞書順になるように追加する。

diff --git a/runtime/doc/tags b/runtime/doc/tags
index f33988020..f92a144df 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -5995,6 +5995,7 @@ ada-extra-plugins ft_ada.txt      /*ada-extra-plugins*
 ada-reference  ft_ada.txt      /*ada-reference*
 ada.vim        ft_ada.txt      /*ada.vim*
 add()  builtin.txt     /*add()*
+add_num()      builtin.txt     /*add_num()*
 add-filetype-plugin    usr_05.txt      /*add-filetype-plugin*
 add-global-plugin      usr_05.txt      /*add-global-plugin*
 add-local-help usr_05.txt      /*add-local-help*

関数リストに追加

runtime/doc/usr_41.tx に関数定義を辞書順になるように追加。

diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 36907d249..29e6d2ffc 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -808,6 +808,7 @@ List manipulation:                                  *list-functions*
        empty()                 check if List is empty
        insert()                insert an item somewhere in a List
        add()                   append an item to a List
+       add_num()               add two number
        extend()                append a List to a List
        extendnew()             make a new List and append items
        remove()                remove one or more items from a List

関数のテストを実装

今回は、ただの関数なので src/testdir/test_functions.vim にテスト関数を追加する。

diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
index 8b2518f2b..9167b2952 100644
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -4206,4 +4206,9 @@ func Test_getcellpixels_gui()
   endif
 endfunc
 
+func Test_add_num()
+  let result = add_num(1, 2)
+  call assert_equal(3, result)
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab

make test_functions で、このファイル内のテストのみを実行できる。

参考資料

0 件のコメント:

コメントを投稿