= WeeChat スクリプト作成ガイド
:author: Sébastien Helleu
:email: flashcode@flashtux.org
:lang: ja
:toc: left
:toclevels: 3
:toc-title: 目次
:sectnums:
:docinfo1:


翻訳者:

* Ryuunosuke Ayanokouzi <i38w7i3@yahoo.co.jp>, 2012-2019


このマニュアルは WeeChat チャットクライアントについて説明しており、WeeChat の一部です。

このマニュアルの最新版は以下のページを参照してください:
https://weechat.org/doc


[[introduction]]
== イントロダクション

WeeChat (Wee Enhanced Environment for Chat)
はフリー、高速、軽量な多くのオペレーティングシステムで動くチャットクライアントです。

このマニュアル文書は以下のスクリプト言語を利用して WeeChat
用のスクリプトを製作する方法を解説しています:

* Python
* Perl
* Ruby
* Lua
* Tcl
* Guile (Scheme)
* JavaScript
* PHP

[NOTE]
この文書に含まれるほぼすべての例は Python
で書かれていますが API は他の言語でも共通です。

[[scripts_in_weechat]]
== WeeChat のスクリプト

[[weechat_architecture]]
=== WeeChat のアーキテクチャ

WeeChat はシングルスレッドで、この点はスクリプトも同じです。

スクリプトのコードは以下の場合に実行されます:

* スクリプトを読み込んだ時: 通常これは
  <<register_function,register function>> 関数を呼び出すことを意味します。
* WeeChat がフックコールバックを呼び出した時 (<<hooks,フック>>を参照してください)。

スクリプトのコードが実行されると、WeeChat
は一時停止し、実行の完了を待ってから再開します。このため、スクリプトは操作をブロックしては
*絶対にいけません*。ネットワークを呼び出す等の場合には、`hook_process` 等の専用 API 関数を使ってください。

[IMPORTANT]
WeeChat がクラッシュするため、スクリプトで fork したりスレッドを作ることは *禁止*
されています。これが必要な場合には専用 API 関数を使ってください。 +
どうしてもバックグラウンド実行を避けられない場合には `hook_process`
関数を使ってください。<<hook_process,バックグラウンドプロセスの実行>>の例および
link:weechat_plugin_api.ja.html#_hook_process[WeeChat プラグイン API リファレンス]内の
`hook_process` 関数の文書を参照してください。

[[languages_specificities]]
=== 言語仕様

==== Python

* 必ず `import weechat` を使ってください。
* python では `+print*+` 系の関数は `+prnt*+` と書きます
  (_print_ は予約済みキーワードなので)。
* 関数は `weechat.xxx(arg1, arg2, ...)` のように呼び出してください。

==== Perl

* 関数は `weechat::xxx(arg1, arg2, ...);` のように呼び出してください。

==== Ruby

* _weechat_init_ を定義して、内部で _register_ を呼び出してください。
* 関数は `Weechat.xxx(arg1, arg2, ...)` のように呼び出してください。
* Ruby では関数に渡せる引数の数が最大 15 個に制限されているため、`Weechat.config_new_option`
  関数はコールバック用の引数群を 6 個の文字列からなる 1 個の配列で受け取ります (3 個のコールバック
  + 3 個のデータ文字列)、したがって `Weechat.config_new_option` 関数を呼び出すには以下のようにしてください:

[source,ruby]
----
Weechat.config_new_option(config, section, "name", "string", "description of option", "", 0, 0,
                          "value", "value", 0, ["check_cb", "", "change_cb", "", "delete_cb", ""])
----

==== Lua

* 関数は `weechat.xxx(arg1, arg2, ...)` のように呼び出してください。

==== Tcl

* 関数は `weechat::xxx arg1 arg2 ...` のように呼び出してください。

==== Guile (Scheme)

* 関数は `(weechat:xxx arg1 arg2 ...)` のように呼び出してください。
* 以下の関数は引数のリストをひとつだけ取ります
  (他の関数のように多くの引数を取れません)、この理由は引数の個数が
  Guile で利用できる引数の数を超えるからです。
** config_new_section
** config_new_option
** bar_new

==== JavaScript

* 関数は `weechat.xxx(arg1, arg2, ...);` のように呼び出してください。

==== PHP

* 関数は `weechat_xxx(arg1, arg2, ...);` のように呼び出してください。

[[register_function]]
=== 関数の登録

全ての WeeChat スクリプトは WeeChat
に自分自身を「登録」し、登録はスクリプトの最初で行われなければいけません。

プロトタイプ:

[source,python]
----
weechat.register(name, author, version, license, description, shutdown_function, charset)
----

引数:

* _name_: 文字列型、スクリプトの内部名
* _author_: 文字列型、作者名
* _version_: 文字列型、スクリプトのバージョン
* _license_: 文字列型、スクリプトのライセンス
* _description_: 文字列型、スクリプトの短い説明
* _shutdown_function_: 文字列型、スクリプトがアンロードされた際に呼び出される関数の名前
  (空文字列でも可)
* _charset_: 文字列型、スクリプトの文字コード (UTF-8
  はデフォルトの文字コードなので、スクリプトが UTF-8 で書かれている場合、空文字列を指定してください)

各言語で書かれたスクリプトの例:

* Python:

[source,python]
----
import weechat

weechat.register("test_python", "FlashCode", "1.0", "GPL3", "Test script", "", "")
weechat.prnt("", "Hello, from python script!")
----

* Perl:

[source,perl]
----
weechat::register("test_perl", "FlashCode", "1.0", "GPL3", "Test script", "", "");
weechat::print("", "Hello, from perl script!");
----

* Ruby:

[source,ruby]
----
def weechat_init
  Weechat.register("test_ruby", "FlashCode", "1.0", "GPL3", "Test script", "", "")
  Weechat.print("", "Hello, from ruby script!")
  return Weechat::WEECHAT_RC_OK
end
----

* Lua:

[source,lua]
----
weechat.register("test_lua", "FlashCode", "1.0", "GPL3", "Test script", "", "")
weechat.print("", "Hello, from lua script!")
----

* Tcl:

[source,tcl]
----
weechat::register "test_tcl" "FlashCode" "1.0" "GPL3" "Test script" "" ""
weechat::print "" "Hello, from tcl script!"
----

* Guile (Scheme):

[source,lisp]
----
(weechat:register "test_scheme" "FlashCode" "1.0" "GPL3" "Test script" "" "")
(weechat:print "" "Hello, from scheme script!")
----

* JavaScript:

[source,javascript]
----
weechat.register("test_js", "FlashCode", "1.0", "GPL3", "Test script", "", "");
weechat.print("", "Hello, from javascript script!");
----

* PHP:

[source,php]
----
weechat_register('test_php', 'FlashCode', '1.0', 'GPL3', 'Test script', '', '');
weechat_print('', 'Hello, from PHP script!');
----

[[load_script]]
=== スクリプトのロード

スクリプトをロードするには "script" プラグインを使うことを推奨します。例:

----
/script load script.py
/script load script.pl
/script load script.rb
/script load script.lua
/script load script.tcl
/script load script.scm
/script load script.js
/script load script.php
----

プログラミング言語ごとの固有コマンドを利用することもできます:

----
/python load script.py
/perl load script.pl
/ruby load script.rb
/lua load script.lua
/tcl load script.tcl
/guile load script.scm
/javascript load script.js
/php load script.php
----

WeeChat の開始時にスクリプトを自動ロードするには
_language/autoload_ ディレクトリ内にリンクを作ってください。

例えば Python の場合:

----
$ cd ~/.weechat/python/autoload
$ ln -s ../script.py
----

[NOTE]
`/script install` コマンドでスクリプトをインストールした場合、_autoload_
ディレクトリ内にリンクが自動的に作成されます。

[[differences_with_c_api]]
== C API との違い

スクリプト API は C 言語プラグイン API とほぼ同じです。API
に含まれる各関数の詳細 (プロトタイプ、引数、戻り値、例) については
link:weechat_plugin_api.ja.html[WeeChat プラグイン API リファレンス]を参照してください。

_プラグイン_ と _スクリプト_ の違いを理解することは重要です:
_プラグイン_ とはコンパイル済みバイナリファイルで `/plugin` コマンドを使ってロードします、これに対して
_スクリプト_ とはテキストファイルで例えば _python_ プラグインであれば `/python`
コマンドを使ってロードします。

例えば _test.py_ スクリプトが WeeChat API 関数を呼び出す場合、以下の順に呼び出されます:

// PLEASE DO NOT TRANSLATE
....
               ┌──────────────────────┐        ╔══════════════════╗
               │     python plugin    │        ║  WeeChat "core"  ║
               ├────────────┬─────────┤        ╟─────────┐        ║
test.py ─────► │ script API │  C API  │ ─────► ║  C API  │        ║
               └────────────┴─────────┘        ╚═════════╧════════╝
....

WeeChat が _test.py_
スクリプトで定義されたコールバックを呼び出す場合、順番は逆になります:

// PLEASE DO NOT TRANSLATE
....
╔══════════════════╗        ┌──────────────────────┐
║  WeeChat "core"  ║        │     python plugin    │
║        ┌─────────╢        ├─────────┬────────────┤
║        │  C API  ║ ─────► │  C API  │ script API │ ─────► test.py
╚════════╧═════════╝        └─────────┴────────────┘
....

[[pointers]]
=== ポインタ

ご存知かもしれませんが、スクリプトには本当の意味での「ポインタ」はありません。このため
API 関数がポインタを返す場合、スクリプトでは文字列に変換されます。

例えば、関数がポインタ 0x1234ab56 を返した場合、スクリプトは
"0x1234ab56" という文字列を受け取ることになります。

API 関数の引数にポインタを与える場合、スクリプトではポインタを文字列型として渡さなければいけません。C
言語 API 関数を呼び出す前に C
言語プラグインがこれを本来のポインタ型に変換します。

空文字列や "0x0" を使うことも許されています。これらは C 言語で言うところの NULL
と解釈されます。例えば、データをコアバッファ (WeeChat メインバッファ) に表示する場合、以下のようになります:

[source,python]
----
weechat.prnt("", "hi!")
----

[WARNING]
WeeChat の多くのスクリプト API
関数は計算量を減らすために、ポインタの値が正当なものか否かの確認を行いません。ポインタの正当性を確認することはプログラマが行わなければいけません。不正なポインタを利用した場合、細かなクラッシュレポートを目にすることになるでしょう
;)

[[callbacks]]
=== コールバック

ほとんど全ての WeeChat コールバックは WEECHAT_RC_OK または WEECHAT_RC_ERROR
を返さなければいけません (modifier コールバックは例外で、これは文字列を返します)。

C 言語コールバックはポインタ型の "data" 引数を利用します。スクリプト API
では、"data" は文字列型で任意の値を取れます (ポインタ型ではありません)。

各プログラミング言語でコールバックを利用する例:

* Python:

[source,python]
----
def timer_cb(data, remaining_calls):
    weechat.prnt("", "timer! data=%s" % data)
    return weechat.WEECHAT_RC_OK

weechat.hook_timer(1000, 0, 1, "timer_cb", "test")
----

* Perl:

[source,perl]
----
sub timer_cb {
    my ($data, $remaining_calls) = @_;
    weechat::print("", "timer! data=$data");
    return weechat::WEECHAT_RC_OK;
}

weechat::hook_timer(1000, 0, 1, "timer_cb", "test");
----

* Ruby:

[source,ruby]
----
def timer_cb(data, remaining_calls)
  Weechat.print("", "timer! data=#{data}");
  return Weechat::WEECHAT_RC_OK
end

Weechat.hook_timer(1000, 0, 1, "timer_cb", "test");
----

* Lua:

[source,lua]
----
function timer_cb(data, remaining_calls)
    weechat.print("", "timer! data="..data)
    return weechat.WEECHAT_RC_OK
end

weechat.hook_timer(1000, 0, 1, "timer_cb", "test")
----

* Tcl:

[source,tcl]
----
proc timer_cb { data remaining_calls } {
    weechat::print {} "timer! data=$data"
    return $::weechat::WEECHAT_RC_OK
}

weechat::hook_timer 1000 0 1 timer_cb test
----

* Guile (Scheme):

[source,lisp]
----
(define (timer_cb data remaining_calls)
  (weechat:print "" (string-append "timer! data=" data))
  weechat:WEECHAT_RC_OK
)

(weechat:hook_timer 1000 0 1 "timer_cb" "test")
----

* JavaScript:

[source,javascript]
----
function timer_cb(data, remaining_calls) {
    weechat.print("", "timer! data=" + data);
    return weechat.WEECHAT_RC_OK;
}

weechat.hook_timer(1000, 0, 1, "timer_cb", "test");
----

* PHP:

[source,php]
----
$timer_cb = function ($data, $remaining_calls) {
    weechat_print('', 'timer! data=' . $data);
    return WEECHAT_RC_OK;
};

weechat_hook_timer(1000, 0, 1, $timer_cb, 'test');
----

[[script_api]]
== スクリプト API

API に含まれる関数の詳しい情報は
link:weechat_plugin_api.ja.html[WeeChat プラグイン API リファレンス]を参照してください。

[[script_api_functions]]
=== 関数

スクリプト API に含まれる関数のリスト:

[width="75%",cols="1,3",options="header"]
|===
| カテゴリ | 関数

| 一般 |
  register

| プラグイン |
  plugin_get_name

| 設定 |
  charset_set +
  iconv_to_internal +
  iconv_from_internal +
  gettext +
  ngettext +
  strlen_screen +
  string_match +
  string_match_list +
  string_has_highlight +
  string_has_highlight_regex +
  string_mask_to_regex +
  string_format_size +
  string_remove_color +
  string_is_command_char +
  string_input_for_buffer +
  string_eval_expression +
  string_eval_path_home

| ディレクトリ操作 |
  mkdir_home +
  mkdir +
  mkdir_parents

| ソート済みリスト |
  list_new +
  list_add +
  list_search +
  list_search_pos +
  list_casesearch +
  list_casesearch_pos +
  list_get +
  list_set +
  list_next +
  list_prev +
  list_string +
  list_size +
  list_remove +
  list_remove_all +
  list_free

| 設定ファイル |
  config_new +
  config_new_section +
  config_search_section +
  config_new_option +
  config_search_option +
  config_string_to_boolean +
  config_option_reset +
  config_option_set +
  config_option_set_null +
  config_option_unset +
  config_option_rename +
  config_option_is_null +
  config_option_default_is_null +
  config_boolean +
  config_boolean_default +
  config_integer +
  config_integer_default +
  config_string +
  config_string_default +
  config_color +
  config_color_default +
  config_write_option +
  config_write_line +
  config_write +
  config_read +
  config_reload +
  config_option_free +
  config_section_free_options +
  config_section_free +
  config_free +
  config_get +
  config_get_plugin +
  config_is_set_plugin +
  config_set_plugin +
  config_set_desc_plugin +
  config_unset_plugin

| キー割り当て |
  key_bind +
  key_unbind

| 表示 |
  prefix +
  color +
  print (python では prnt) +
  print_date_tags (python では prnt_date_tags) +
  print_y (python では prnt_y) +
  log_print

| フック |
  hook_command +
  hook_command_run +
  hook_timer +
  hook_fd +
  hook_process +
  hook_process_hashtable +
  hook_connect +
  hook_line +
  hook_print +
  hook_signal +
  hook_signal_send +
  hook_hsignal +
  hook_hsignal_send +
  hook_config +
  hook_completion +
  hook_completion_get_string +
  hook_completion_list_add +
  hook_modifier +
  hook_modifier_exec +
  hook_info +
  hook_info_hashtable +
  hook_infolist +
  hook_focus +
  hook_set +
  unhook +
  unhook_all

| バッファ |
  buffer_new +
  current_buffer +
  buffer_search +
  buffer_search_main +
  buffer_clear +
  buffer_close +
  buffer_merge +
  buffer_unmerge +
  buffer_get_integer +
  buffer_get_string +
  buffer_get_pointer +
  buffer_set +
  buffer_string_replace_local_var +
  buffer_match_list

| ウィンドウ |
  current_window +
  window_search_with_buffer +
  window_get_integer +
  window_get_string +
  window_get_pointer +
  window_set_title

| ニックネームリスト |
  nicklist_add_group +
  nicklist_search_group +
  nicklist_add_nick +
  nicklist_search_nick +
  nicklist_remove_group +
  nicklist_remove_nick +
  nicklist_remove_all +
  nicklist_group_get_integer +
  nicklist_group_get_string +
  nicklist_group_get_pointer +
  nicklist_group_set +
  nicklist_nick_get_integer +
  nicklist_nick_get_string +
  nicklist_nick_get_pointer +
  nicklist_nick_set

| バー |
  bar_item_search +
  bar_item_new +
  bar_item_update +
  bar_item_remove +
  bar_search +
  bar_new +
  bar_set +
  bar_update +
  bar_remove

| コマンド |
  command +
  command_options

| インフォ |
  info_get +
  info_get_hashtable

| インフォリスト |
  infolist_new +
  infolist_new_item +
  infolist_new_var_integer +
  infolist_new_var_string +
  infolist_new_var_pointer +
  infolist_new_var_time +
  infolist_get +
  infolist_next +
  infolist_prev +
  infolist_reset_item_cursor +
  infolist_search_var +
  infolist_fields +
  infolist_integer +
  infolist_string +
  infolist_pointer +
  infolist_time +
  infolist_free

| hdata |
  hdata_get +
  hdata_get_var_offset +
  hdata_get_var_type_string +
  hdata_get_var_array_size +
  hdata_get_var_array_size_string +
  hdata_get_var_hdata +
  hdata_get_list +
  hdata_check_pointer +
  hdata_move +
  hdata_search +
  hdata_char +
  hdata_integer +
  hdata_long +
  hdata_string +
  hdata_pointer +
  hdata_time +
  hdata_hashtable +
  hdata_compare +
  hdata_update +
  hdata_get_string

| アップグレード |
  upgrade_new +
  upgrade_write_object +
  upgrade_read +
  upgrade_close
|===

[[script_api_constants]]
=== 定数

スクリプト API に含まれる定数のリスト:

[width="75%",cols="1,3",options="header"]
|===
| カテゴリ            | 定数

| リターンコード |
  WEECHAT_RC_OK +
  WEECHAT_RC_OK_EAT +
  WEECHAT_RC_ERROR

| 設定ファイル |
  WEECHAT_CONFIG_READ_OK +
  WEECHAT_CONFIG_READ_MEMORY_ERROR +
  WEECHAT_CONFIG_READ_FILE_NOT_FOUND +
  WEECHAT_CONFIG_WRITE_OK +
  WEECHAT_CONFIG_WRITE_ERROR +
  WEECHAT_CONFIG_WRITE_MEMORY_ERROR +
  WEECHAT_CONFIG_OPTION_SET_OK_CHANGED +
  WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE +
  WEECHAT_CONFIG_OPTION_SET_ERROR +
  WEECHAT_CONFIG_OPTION_SET_OPTION_NOT_FOUND +
  WEECHAT_CONFIG_OPTION_UNSET_OK_NO_RESET +
  WEECHAT_CONFIG_OPTION_UNSET_OK_RESET +
  WEECHAT_CONFIG_OPTION_UNSET_OK_REMOVED +
  WEECHAT_CONFIG_OPTION_UNSET_ERROR

| ソート済みリスト |
  WEECHAT_LIST_POS_SORT +
  WEECHAT_LIST_POS_BEGINNING +
  WEECHAT_LIST_POS_END

| ホットリスト |
  WEECHAT_HOTLIST_LOW +
  WEECHAT_HOTLIST_MESSAGE +
  WEECHAT_HOTLIST_PRIVATE +
  WEECHAT_HOTLIST_HIGHLIGHT

| プロセスのフック |
  WEECHAT_HOOK_PROCESS_RUNNING +
  WEECHAT_HOOK_PROCESS_ERROR

| 接続のフック |
  WEECHAT_HOOK_CONNECT_OK +
  WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND +
  WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND +
  WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED +
  WEECHAT_HOOK_CONNECT_PROXY_ERROR +
  WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR +
  WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR +
  WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR +
  WEECHAT_HOOK_CONNECT_MEMORY_ERROR +
  WEECHAT_HOOK_CONNECT_TIMEOUT +
  WEECHAT_HOOK_CONNECT_SOCKET_ERROR

| シグナルのフック |
  WEECHAT_HOOK_SIGNAL_STRING +
  WEECHAT_HOOK_SIGNAL_INT +
  WEECHAT_HOOK_SIGNAL_POINTER
|===

[[common_tasks]]
== 良くあるタスク

この章ではいくつかの良くあるタスクを例を交えて紹介します。ここでは
API の一部の機能を使っています。完全なリファレンスは
link:weechat_plugin_api.ja.html[WeeChat プラグイン API リファレンス]を参照してください。

[[buffers]]
=== バッファ

[[buffers_display_messages]]
==== メッセージの表示

WeeChat コアバッファに対して操作する場合、空文字列を使うことが多いです。他のバッファに対して操作する場合には、ポインタ
(文字列型、<<pointers,ポインタ>> を参照) を与える必要があります。

例:

[source,python]
----
# "hello" をコアバッファに表示
weechat.prnt("", "hello")

# "hello" をコアバッファに表示するが、ログファイルには書き込まない
# (WeeChat バージョン 0.3.3 以上で利用可)
weechat.prnt_date_tags("", 0, "no_log", "hello")

# プレフィックス "==>" とメッセージ "hello" を現在のバッファに表示
# (プレフックストメッセージはタブで区切ってください)
weechat.prnt(weechat.current_buffer(), "==>\thello")

# コアバッファにエラーメッセージを表示 (エラープレフィックスを利用)
weechat.prnt("", "%swrong arguments" % weechat.prefix("error"))

# コアバッファに色付きメッセージを表示
weechat.prnt("", "text %syellow on blue" % weechat.color("yellow,blue"))

# バッファを検索してメッセージを表示
# (バッファの完全な名前は plugin.name のような形です、例えば: "irc.freenode.#weechat")
buffer = weechat.buffer_search("irc", "freenode.#weechat")
weechat.prnt(buffer, "message on #weechat channel")

# ある IRC バッファを見つける他の方法 (推奨)
# (サーバとチャンネルはコンマで区切ってください。)
buffer = weechat.info_get("irc_buffer", "freenode,#weechat")
weechat.prnt(buffer, "message on #weechat channel")
----

[NOTE]
Print 関数は Python では `prnt`、その他の言語では `print` と呼ばれます。

[[buffers_send_text]]
==== バッファにテキストを送信

テキストやコマンドをバッファに送信できます。これはテキストやコマンドをタイプして
[Enter] を押すことに対応します。

例:

[source,python]
----
# 現在のバッファでコマンド "/help" を実行 (結果は core バッファに出力されます)
weechat.command("", "/help")

# テキスト "hello" を #weechat IRC チャンネルに送信 (このチャンネルにいるユーザにはメッセージが見えます。)
buffer = weechat.info_get("irc_buffer", "freenode,#weechat")
weechat.command(buffer, "hello")
----

[[buffers_new]]
==== 新規バッファの作成

スクリプトを使って新しいバッファを作成し、このバッファにメッセージを表示させることができます。

2 つのコールバックを定義できます (任意): データの入力時に呼び出されるもの
(バッファでテキストを入力して [Enter] を押した時) と、バッファが閉じられたときに呼び出されるもの
(例えば `/buffer close` した時等) です。

例:

[source,python]
----
# データの入力時に呼び出されるコールバック
def buffer_input_cb(data, buffer, input_data):
    # ...
    return weechat.WEECHAT_RC_OK

# バッファが閉じられた時に呼び出されるコールバック
def buffer_close_cb(data, buffer):
    # ...
    return weechat.WEECHAT_RC_OK

# バッファの作成
buffer = weechat.buffer_new("mybuffer", "buffer_input_cb", "", "buffer_close_cb", "")

# タイトルの設定
weechat.buffer_set(buffer, "title", "This is title for my buffer.")

# ローカル変数 "no_log" に "1" を設定することでログ保存を無効化
weechat.buffer_set(buffer, "localvar_set_no_log", "1")
----

[[buffers_properties]]
==== バッファプロパティ

文字列、整数、ポインタ型のバッファプロパティを読むことができます。

例:

[source,python]
----
buffer = weechat.current_buffer()

number = weechat.buffer_get_integer(buffer, "number")
name = weechat.buffer_get_string(buffer, "name")
short_name = weechat.buffer_get_string(buffer, "short_name")
----

バッファに対するローカル変数を追加、ロード、削除することができます:

[source,python]
----
# ローカル変数の追加
weechat.buffer_set(buffer, "localvar_set_myvar", "my_value")

# ローカル変数のロード
myvar = weechat.buffer_get_string(buffer, "localvar_myvar")

# ローカル変数の削除
weechat.buffer_set(buffer, "localvar_del_myvar", "")
----

バッファに対するローカル変数を見るには、WeeChat で以下のコマンドを実行してください:

----
/buffer localvar
----

[[hooks]]
=== フック

[[hook_command]]
==== 新しいコマンドの追加

カスタムコマンドを追加するには `hook_command`
を使ってください。追加したコマンドに対してカスタム補完テンプレートを定義できます。

例:

[source,python]
----
def my_command_cb(data, buffer, args):
    # ...
    return weechat.WEECHAT_RC_OK

hook = weechat.hook_command("myfilter", "description of myfilter",
    "[list] | [enable|disable|toggle [name]] | [add name plugin.buffer tags regex] | [del name|-all]",
    "description of arguments...",
    "list"
    " || enable %(filters_names)"
    " || disable %(filters_names)"
    " || toggle %(filters_names)"
    " || add %(filters_names) %(buffers_plugins_names)|*"
    " || del %(filters_names)|-all",
    "my_command_cb", "")
----

上で定義したコマンドを WeeChat で以下のように使うことができます:

----
/help myfilter

/myfilter arguments...
----

[[hook_timer]]
==== タイマーの追加

タイマーを追加するには `hook_timer` を使ってください。

例:

[source,python]
----
def timer_cb(data, remaining_calls):
    # ...
    return weechat.WEECHAT_RC_OK

# 1 分毎に (秒が 00 になった時に) 呼び出されるタイマー
weechat.hook_timer(60 * 1000, 60, 0, "timer_cb", "")
----

[[hook_process]]
==== バックグラウンドプロセスの実行

バックグラウンドプロセスを実行するには `hook_process`
を使います。コールバックはデータの準備が整った時点で呼び出されます。複数回呼び出されることもあります。

コールバックの最後の呼び出しでは _rc_ が 0
か正の値に設定されています。これはコマンドのリターンコードになります。

例:

[source,python]
----
process_output = ""

def my_process_cb(data, command, rc, out, err):
    global process_output
    if out != "":
        process_output += out
    if int(rc) >= 0:
        weechat.prnt("", process_output)
    return weechat.WEECHAT_RC_OK

weechat.hook_process("/bin/ls -l /etc", 10 * 1000, "my_process_cb", "")
----

[[url_transfer]]
==== URL 転送

_WeeChat バージョン 0.3.7 以上で利用可。_

URL をダウンロードする (または URL にポストする) には、関数 `hook_process` または URL
転送にオプションが必要な場合は `hook_process_hashtable` を使わなければいけません。

オプション無しの URL 転送の例: HTML ページの内容はコールバックの
"out" 引数 (プロセスの標準出力) を通して渡されます。

[source,python]
----
# 現在の WeeChat 安定版のバージョンを表示。
weechat_version = ""

def weechat_process_cb(data, command, rc, out, err):
    global weechat_version
    if out != "":
        weechat_version += out
    if int(rc) >= 0:
        weechat.prnt("", "Current WeeChat stable is: %s" % weechat_version)
    return weechat.WEECHAT_RC_OK

weechat.hook_process("url:https://weechat.org/dev/info/stable/",
                     30 * 1000, "weechat_process_cb", "")
----

[TIP]
WeeChat に関して利用できる情報は全て https://weechat.org/dev/info にあります

オプション有りの URL 転送の例: 最新の WeeChat 開発パッケージをファイル
_/tmp/weechat-devel.tar.gz_ にダウンロード:

[source,python]
----
def my_process_cb(data, command, rc, out, err):
    if int(rc) >= 0:
        weechat.prnt("", "End of transfer (rc=%s)" % rc)
    return weechat.WEECHAT_RC_OK

weechat.hook_process_hashtable("url:https://weechat.org/files/src/weechat-devel.tar.gz",
                               {"file_out": "/tmp/weechat-devel.tar.gz"},
                               30 * 1000, "my_process_cb", "")
----

URL 転送に関するより詳しい情報と利用可能なオプションは
link:weechat_plugin_api.ja.html#_hook_process[WeeChat プラグイン API リファレンス]の
`hook_process` と `hook_process_hashtable` を参照してください。

[[config_options]]
=== 設定 / オプション

[[config_options_set_script]]
==== スクリプトのオプションを設定

オプションが設定されているかどうかを確認するには `config_is_set_plugin`
関数、オプションを設定するには `config_set_plugin` 関数を使います。

例:

[source,python]
----
script_options = {
    "option1": "value1",
    "option2": "value2",
    "option3": "value3",
}
for option, default_value in script_options.items():
    if not weechat.config_is_set_plugin(option):
        weechat.config_set_plugin(option, default_value)
----

[[config_options_detect_changes]]
==== 変更の検出

ユーザがスクリプトオプションを変更したことを検出するには `hook_config` を使わなければいけません。

例:

[source,python]
----
SCRIPT_NAME = "myscript"

# ...

def config_cb(data, option, value):
    """スクリプトオプションが変更されたときに呼び出されるコールバック"""
    # 例えば、スクリプト変数に対する全てのスクリプトオプションを読み込む等...
    # ...
    return weechat.WEECHAT_RC_OK

# ...

weechat.hook_config("plugins.var.python." + SCRIPT_NAME + ".*", "config_cb", "")
# 他のスクリプト言語の場合は "python" を適当なもの (perl/ruby/lua/tcl/guile/javascript) に変更してください
----

[[config_options_weechat]]
==== WeeChat オプションのロード

`config_get` 関数はオプションへのポインタを返します。オプションの型に従って
`config_string`、`config_boolean`、`config_integer`、`config_color`
を呼び出さなければいけません。

[source,python]
----
# 文字列型の場合
weechat.prnt("", "value of option weechat.look.item_time_format is: %s"
                 % (weechat.config_string(weechat.config_get("weechat.look.item_time_format"))))

# ブール型の場合
weechat.prnt("", "value of option weechat.look.day_change is: %d"
                 % (weechat.config_boolean(weechat.config_get("weechat.look.day_change"))))

# 整数型の場合
weechat.prnt("", "value of option weechat.look.scroll_page_percent is: %d"
                 % (weechat.config_integer(weechat.config_get("weechat.look.scroll_page_percent"))))

# 色型の場合
weechat.prnt("", "value of option weechat.color.chat_delimiters is: %s"
                 % (weechat.config_color(weechat.config_get("weechat.color.chat_delimiters"))))
----

[[irc]]
=== IRC

[[irc_catch_messages]]
==== メッセージのキャッチ

メッセージを受信すると IRC プラグインは 2 つのシグナルを送信します (`xxx`
は IRC 内部サーバ名で、`yyy` は JOIN、QUIT、PRIVMSG、301 等の IRC コマンド名です):

xxxx,irc_in_yyy::
    メッセージの処理が行われる前に送信されるシグナル

xxx,irc_in2_yyy::
    メッセージの処理が行われた後に送信されるシグナル

[source,python]
----
def join_cb(data, signal, signal_data):
    # シグナル、例えば: "freenode,irc_in2_join"
    # signal_data は IRC メッセージ、例えば: ":nick!user@host JOIN :#channel"
    server = signal.split(",")[0]
    msg = weechat.info_get_hashtable("irc_message_parse", {"message": signal_data})
    buffer = weechat.info_get("irc_buffer", "%s,%s" % (server, msg["channel"]))
    if buffer:
        weechat.prnt(buffer, "%s (%s) has joined this channel!" % (msg["nick"], msg["host"]))
    return weechat.WEECHAT_RC_OK

# 全ての IRC サーバに対する JOIN メッセージをキャッチするにはサーバの指定に
# "*" を使うと便利です。
weechat.hook_signal("*,irc_in2_join", "join_cb", "")
----

[[irc_modify_messages]]
==== メッセージの修正

メッセージを受信すると IRC プラグインは "irc_in_xxx" ("xxx" は IRC コマンド)
と呼ばれる "modifier" を送信します。メッセージを修正するにはこのシグナルを使います。

[source,python]
----
def modifier_cb(data, modifier, modifier_data, string):
    # 全てのメッセージにサーバ名を追加する
    # (これは役に立ちませんが、例として!)
    return "%s %s" % (string, modifier_data)

weechat.hook_modifier("irc_in_privmsg", "modifier_cb", "")
----

[WARNING]
不正なメッセージは WeeChat をクラッシュさせ、深刻な問題を引き起こします!

[[irc_message_parse]]
==== メッセージの構文解析

_WeeChat バージョン 0.3.4 以上で利用可。_

"irc_message_parse" と呼ばれる info_hashtable を使って IRC メッセージを構文解析できます。

結果は以下のキーを持つハッシュテーブルです
(例の値は以下のメッセージから作られました:
`@time=2015-06-27T16:40:35.000Z :nick!user@host PRIVMSG #weechat :hello!`):

[width="100%",cols="1,^2,10,8",options="header"]
|===
| キー | WeeChat バージョン | 説明 | 例

| tags | 0.4.0 以上 |
  メッセージに付けられたタグ (空にすることも可) |
  `time=2015-06-27T16:40:35.000Z`

| message_without_tags | 0.4.0 以上 |
  タグを除いたメッセージ (タグが付けられていなければメッセージと同じ) |
  `:nick!user@host PRIVMSG #weechat :hello!`

| nick | 0.3.4 以上 |
  発信者のニックネーム |
  `nick`

| host | 0.3.4 以上 |
  発信者のホスト (ニックネームを含む) |
  `nick!user@host`

| command | 0.3.4 以上 |
  コマンド (_PRIVMSG_、_NOTICE_、...) |
  `PRIVMSG`

| channel | 0.3.4 以上 |
  送信先チャンネル |
  `#weechat`

| arguments | 0.3.4 以上 |
  コマンド引数 (チャンネルを含む) |
  `#weechat :hello!`

| text | 1.3 以上 |
  テキスト (ユーザメッセージなど) |
  `hello!`

| pos_command | 1.3 以上 |
  メッセージ内における _command_ のインデックス (_command_ が見つからない場合 "-1") |
  `47`

| pos_arguments | 1.3 以上 |
  メッセージ内における _arguments_ のインデックス (_arguments_ が見つからない場合 "-1") |
  `55`

| pos_channel | 1.3 以上 |
  メッセージ内における _channel_ のインデックス (_channel_ が見つからない場合 "-1") |
  `55`

| pos_text | 1.3 以上 |
  メッセージ内における _text_ のインデックス (_text_ が見つからない場合 "-1") |
  `65`
|===

[source,python]
----
dict = weechat.info_get_hashtable(
    "irc_message_parse",
    {"message": "@time=2015-06-27T16:40:35.000Z :nick!user@host PRIVMSG #weechat :hello!"})

# dict == {
#     "tags": "time=2015-06-27T16:40:35.000Z",
#     "message_without_tags": ":nick!user@host PRIVMSG #weechat :hello!",
#     "nick": "nick",
#     "host": "nick!user@host",
#     "command": "PRIVMSG",
#     "channel": "#weechat",
#     "arguments": "#weechat :hello!",
#     "text": "hello!",
#     "pos_command": "47",
#     "pos_arguments": "55",
#     "pos_channel": "55",
#     "pos_text": "65",
# }
----

[[infos]]
=== 情報

[[infos_weechat_version]]
==== WeeChat のバージョン

バージョンを確認する最良の方法は "version_number"
を参照し、16 進数のバージョン番号と整数値比較することです。

例:

[source,python]
----
version = weechat.info_get("version_number", "") or 0
if int(version) >= 0x00030200:
    weechat.prnt("", "This is WeeChat 0.3.2 or newer")
else:
    weechat.prnt("", "This is WeeChat 0.3.1 or older")
----

[NOTE]
バージョン 0.3.1.1 以下の場合 _info_get("version_number")_
は空文字列を返すため、値が空でないことを確認しなければいけません。

文字列でバージョンを使うには:

[source,python]
----
# 例えば "Version 0.3.2" のような出力が得られます。
weechat.prnt("", "Version %s" % weechat.info_get("version", ""))
----

[[infos_other]]
==== その他の情報

[source,python]
----
# WeeChat ホームディレクトリ、例えば: "/home/xxxx/.weechat"
weechat.prnt("", "WeeChat home dir: %s" % weechat.info_get("weechat_dir", ""))

# キーボードの不使用時間
weechat.prnt("", "Inactivity since %s seconds" % weechat.info_get("inactivity", ""))
----

[[infolists]]
=== インフォリスト

[[infolists_read]]
==== インフォリストのロード

WeeChat や他のプラグインによって作られたインフォリストを読み込むことができます。

例:

[source,python]
----
# バッファのリストを得るために "buffer" インフォリストを読み込む
infolist = weechat.infolist_get("buffer", "", "")
if infolist:
    while weechat.infolist_next(infolist):
        name = weechat.infolist_string(infolist, "name")
        weechat.prnt("", "buffer: %s" % name)
    weechat.infolist_free(infolist)
----

[IMPORTANT]
WeeChat は自動的にメモリを解放しません、インフォリストによって使われたメモリを解放するには、`infolist_free`
を呼び出すことを忘れないでください。
