= WeeChat водич за скриптовање
:author: Sébastien Helleu
:email: flashcode@flashtux.org
:lang: sr
:toc: left
:toclevels: 4
:toc-title: Садржај
:sectnums:
:sectnumlevels: 3
:docinfo1:

Превод:

* Иван Пешић (<ivan.pesic@gmail.com>), 2021.


Ово упутство описује WeeChat чет клијент и део је програма WeeChat.

Последња верзија овог документа може да се нађе на следећој страници: https://weechat.org/doc


[[introduction]]
== Увод

WeeChat (Wee Enhanced Environment for Chat) је бесплатни чет клијент, једноставан и брз, дизајниран за многе оперативне системе.

Ово упутство документује начин писања скрипти за програм WeeChat употребом једног од подржаних скрипт језика:

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

[NOTE]
Almost all examples in this doc are written in Python, but API is the same for other languages.

[[scripts_in_weechat]]
== Скрипте у програму WeeChat

[[weechat_architecture]]
=== Архитектура програма WeeChat

Програм WeeChat се извршава у једној нити, па се то применњује и на скрипте.

Кôд скрипте се извршава:

* када се скрипта учита: типично позивом <<register_function,функција за регистрацију>>
* када програм WeeChat позове функцију повратног позива куке (погледајте поглавље <<hooks,Куке>>).

Док се кôд скрипте извршава, програм WeeChat чека на крај извршавања пре него што настави. Тако да скрипте *НЕ СМЕЈУ* да извршавају блокирајуће операције као што су мрежни позиви без употребе одређених API функција као што је `+hook_process+`.

[IMPORTANT]
Скрипта *НИКАДА* не сме да се рачва или да креира нити без употребе одговарајуће API функције, то може да сруши програм WeeChat. +
Ако нешто мора да се извршава у позадини, употребите функцију `+hook_process+`. Погледајте пример у поглављу <<hook_process,Покретање процеса у позадини>> као и документацију функције `+hook_process+` у link:weechat_plugin_api.sr.html#_hook_process[WeeChat референтном приручнику API додатака].

[[languages_specificities]]
=== Језичке специфичности

[[language_python]]
==== Python

[[python_module]]
===== Модул

Програм WeeChat дефинише `weechat` модул који мора да се увезе командом `import weechat`. +
Python стаб за WeeChat API је соступан у репозиторијуму: https://raw.githubusercontent.com/weechat/weechat/master/src/plugins/python/weechat.pyi[weechat.pyi].

[[python_functions]]
===== Функције

Функције се позивају са `+weechat.xxx(арг1, арг2, ...)+`.

Функције `+print*+` се у језику python зову `+prnt*+` (јер је `print` била резервисана реч у Python 2).

[[python_strings]]
===== Стрингови који се примају у функцијама повратног позива

У Python 3 и у програму WeeChat верзије ≥ 2.7, стрингови који се примају у функцијама повратног позива имају тип `str` ако стринг садржи важеће UTF-8 податке (што је најчешћи случај), или `bytes` ако стринг није важећи UTF-8. Тако да би функција повратног позива морала да води рачуна о овом типу у случају да је могућ пријем неважећег UTF-8 садржаја.

Неважећи UTF-8 подаци могу да се приме у следећим случајевима, тако да функције повратног позива могу да приме стринг типа `str` или `bytes` (ова листа није потпуна):

[width="100%", cols="3m,3m,3m,8", options="header"]
|===
| API фунцкија | Аргументи | Примери | Опис

| hook_modifier |
  irc_in_yyy |
  pass:[irc_in_privmsg] +
  pass:[irc_in_notice] |
  Порука која се прими у IRC додатку, пре него што се декодира у UTF-8 (користи
  се интерно). +
  +
  Препоручује се да се уместо ње користи модификатор `+irc_in2_yyy+`, примљени
  стринг је увек валидан UTF-8. +
  Погледајте функцију `+hook_modifier+` у
  link:weechat_plugin_api.sr.html#_hook_modifier[WeeChat референтном приручнику API додатака].

| hook_signal |
  xxx,irc_out_yyy +
  xxx,irc_outtags_yyy |
  pass:[*,irc_out_privmsg] +
  pass:[*,irc_out_notice] +
  pass:[*,irc_outtags_privmsg] +
  pass:[*,irc_outtags_notice] |
  Порука коју шаље IRC додатак, након што се кодира у `encode` скуп карактера
  који је дефинисао корисник (у случају да се разликује од подразумеваног `UTF-8`). +
  +
  Препоручује се да се уместо њега користи сигнал `+xxx,irc_out1_yyy+`, стринг који
  се прима је увек валидан UTF-8. +
  Погледајте функцију `+hook_signal+` у
  link:weechat_plugin_api.sr.html#_hook_signal[WeeChat референтном приручнику API додатака].

| hook_process +
  hook_process_hashtable |
  - |
  - |
  Излаз команде који се шаље функцији повратног позива може да садржи неважеће UTF-8 податке.

|===

У Python 2, који је сад превазиђен и више не би требало да се употребљава, стрингови који се шаљу функцијама повратног позива су увек били типа `str`, и у случајевима који су поменути изнад, могли су да садрже неважеће UTF-8 податке.

[[language_perl]]
==== Perl

[[perl_functions]]
===== Функције

Функције се позивају са `+weechat::xxx(арг1, арг2, ...);+`.

[[language_ruby]]
==== Ruby

[[ruby_init]]
===== Иницијализација

Морате да дефинишете _weechat_init_ и да у њој позовете _register_.

[[ruby_functions]]
===== Функције

Функције се позивају са `+Weechat.xxx(арг1, арг2, ...)+`.

Услед ограничења језика Ruby (функција може да има максимално 15 аргумената), функција `+Weechat.config_new_option+` прихвата функције повратног позива у низу од 6 стрингова (3 повратна позива + 3 стринга са подацима), тако да позив ове функције изгледа овако:

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

И функција `+Weechat.bar_new+` прима боје у низу од 4 стринга (color_fg, color_delim, color_bg, color_bg_inactive), тако да позив ове функције изгледа овако:

[source,ruby]
----
Weechat.bar_new("name", "off", "0", "window", "", "left", "vertical", "vertical", "0", "0",
                ["default", "default", "default", "default"], "0", "items")
----

[[language_lua]]
==== Lua

[[lua_functions]]
===== Функције

Функције се позивају са `+weechat.xxx(арг1, арг2, ...)+`.

[[language_tcl]]
==== Tcl

[[tcl_functions]]
===== Функције

Функције се позивају са `+weechat::xxx арг1 арг2 ...+`.

Пошто Tcl има само стринг типове, не постоји null тип који се прослеђује као
аргумент када функција прихвата null вредности. Ако то желите да заобиђете,
употребите константу `$::weechat::WEECHAT_NULL` која се има улогу null вредности.
Ова константа је дефинисана као `\uFFFF\uFFFF\uFFFFWEECHAT_NULL\uFFFF\uFFFF\uFFFF`,
тако да је скоро немогуће да се појави без намере.

[[language_guile]]
==== Guile (Scheme)

[[guile_functions]]
===== Функције

Функције се позивају са `+(weechat:xxx арг1 арг2 ...)+`.

Следеће функције узимају једну листу аргумената (уместо више аргумената као код осталих функција), јер број аргумената прелази дозвољен максимални број аргумената у језику Guile:

* config_new_section
* config_new_option
* bar_new

[[language_javascript]]
==== JavaScript

[[javascript_functions]]
===== Функције

Функције се позивају са `+weechat.xxx(арг1, арг2, ...);+`.

[[language_php]]
==== PHP

[[php_functions]]
===== Функције

Функције се позивају са `+weechat_xxx(арг1, арг2, ...);+`.

[[register_function]]
=== Функција за регистрацију

Све WeeChat скрипте морају да се „пријаве” програму WeeChat, и то мора да буде прва WeeChat функција која се позива у скрипти.

Прототип (Python):

[source,python]
----
def register(name: str, author: str, version: str, license: str, description: str, shutdown_function: str, charset: str) -> int: ...
----

Аргументи:

* _име_: стринг, интерно име скрипте
* _аутор_: стринг, име аутора
* _верзија_: стринг, верзија скрипте
* _лиценца_: стринг, лиценца скрипте
* _опис_: стринг, кратак опис скрипте
* _искључ_функција_: стринг, име функције која се позива када се скрипте уклања из меморије (може бити и празан стринг)
* _скуп_кар_: стринг, скуп карактера скрипте (ако је ваша скрипта UTF-8, овде можете да користите празну вредности, јер је UTF-8 подразумевани скуп карактера)

Пример скрипте, за сваки језик:

* Python:

[source,python]
----
import weechat

weechat.register("test_python", "FlashCode", "1.0", "GPL3", "Test script", "", "")
weechat.prnt("", "Поздрав од python скрипте!")
----

* Perl:

[source,perl]
----
weechat::register("test_perl", "FlashCode", "1.0", "GPL3", "Test script", "", "");
weechat::print("", "Поздрав од perl скрипте!");
----

* Ruby:

[source,ruby]
----
def weechat_init
  Weechat.register("test_ruby", "FlashCode", "1.0", "GPL3", "Test script", "", "")
  Weechat.print("", "Поздрав од ruby скрипте!")
  return Weechat::WEECHAT_RC_OK
end
----

* Lua:

[source,lua]
----
weechat.register("test_lua", "FlashCode", "1.0", "GPL3", "Test script", "", "")
weechat.print("", "Поздрав од lua скрипте!")
----

* Tcl:

[source,tcl]
----
weechat::register "test_tcl" "FlashCode" "1.0" "GPL3" "Test script" "" ""
weechat::print "" "Поздрав од tcl скрипте!"
----

* Guile (Scheme):

[source,lisp]
----
(weechat:register "test_scheme" "FlashCode" "1.0" "GPL3" "Test script" "" "")
(weechat:print "" "Поздрав од scheme скрипте!")
----

* JavaScript:

[source,javascript]
----
weechat.register("test_js", "FlashCode", "1.0", "GPL3", "Test script", "", "");
weechat.print("", "Поздрав од javascript скрипте!");
----

* PHP:

[source,php]
----
weechat_register('test_php', 'FlashCode', '1.0', 'GPL3', 'Test script', '', '');
weechat_print('', 'Поздрав од PHP скрипте!');
----

[[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
----

Можете направити линк у директоријуму _language/autoload_ ако желите да се скрипта аутоматски учитава када се програм WeeChat покреће.

На пример, са језиком Python:

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

[NOTE]
Када се скрипта инсталира командом `/script install`, линк у _autoload_ директоријуму се аутоматски креира.

[[differences_with_c_api]]
== Разлике у односу на C API

API скриптовања је скоро у потпуности исти као и API C додатака. Можете да погледате следећи линк: weechat_plugin_api.sr.html[WeeChat референца API додатака] у вези детаља сваке функције у API: прототип, аргументи, повратне вредности, примери.

Важно је да се направи разлика између _додатка_ и _скрипте_: _додатак_ је бинарни фајл који се компајлира и учитава командом `/plugin`, док је _скрипта_ текст фајл који се учитава додатком као што је _python_ командом `/python`.

Када ваша скрипта _test.py_ позива WeeChat API функцију, путања је оваква:

....
               ┌──────────────────────┐        ╔══════════════════╗
               │    python додатак    │        ║ WeeChat „језгро” ║
               ├────────────┬─────────┤        ╟─────────┐        ║
test.py ─────► │ script API │  C API  │ ─────► ║  C API  │        ║
               └────────────┴─────────┘        ╚═════════╧════════╝
....

Када WeeChat позове функцију повратног позива у вашој скрипти _test.py_, путања бити обрнута у односу на претходну путању:

....
╔══════════════════╗        ┌──────────────────────┐
║ WeeChat „језгро” ║        │    python додатак    │
║        ┌─────────╢        ├─────────┬────────────┤
║        │  C API  ║ ─────► │  C API  │ script API │ ─────► test.py
╚════════╧═════════╝        └─────────┴────────────┘
....

[[pointers]]
=== Показивачи

Као што вероватно већ знате, у скриптама нема правих „показивача”. Тако да када API функције врате показивач, он се за потребе скрипте конвертује у стринг.

На пример, ако функција врати показивач 0x1234ab56, скрипта ће примити стринг „0x1234ab56”.

А када API функција очекује показивач у аргументима, скрипта мора да проследи ту стринг вредност. C додатак ће да га конвертује у реални показивач пре него што позове C API функцију.

Дозвољени су празни стрингови или „0x0”. На пример, ако желите да испишете податке у бафер језгра (главни WeeChat бафер), можете урадити следеће:

[source,python]
----
weechat.prnt("", "здраво!")
----

[WARNING]
Из разлога брзине, програм WeeChat у многим функцијама не проверава исправност вашег показивача. Ваш посао је да проверите да ли прослеђујете важећи показивач, у супротном бисте могли видети фин извештај о краху ;)

[[callbacks]]
=== Функције повратног позива

Скоро све WeeChat функције повратног позива морају да врате WEECHAT_RC_OK или WEECHAT_RC_ERROR (изузетак од овог правила је функција повратног позива модификатора, она враћа стринг).

C функције повратног позива користе „callback_pointer” и „callback_data” аргументе, и то су показивачи. У API скриптовања постоји само „callback_data” (или „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.sr.html[WeeChat референтни приручник API додатака].

[[script_api_functions]]
=== Функције

Листа функција у API скриптовања:

[width="100%", cols="1,5", 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_color_code_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) +
  print_y_date_tags (за python: prnt_y_date_tags) +
  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_modifier +
  hook_modifier_exec +
  hook_info +
  hook_info_hashtable +
  hook_infolist +
  hook_focus +
  hook_set +
  unhook +
  unhook_all

| бафери |
  buffer_new +
  buffer_new_props +
  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

| довршавање |
  completion_new +
  completion_search +
  completion_get_string +
  completion_list_add +
  completion_free

| infos |
  info_get +
  info_get_hashtable

| infolists |
  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="100%", cols="1,5", 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` (стринг)

| кука process |
  `WEECHAT_HOOK_PROCESS_RUNNING` (цео број) +
  `WEECHAT_HOOK_PROCESS_ERROR` (цео број)

| кука connect |
  `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` (цео број)

| кука signal |
  `WEECHAT_HOOK_SIGNAL_STRING` (стринг) +
  `WEECHAT_HOOK_SIGNAL_INT` (стринг) +
  `WEECHAT_HOOK_SIGNAL_POINTER` (стринг)
|===

[[common_tasks]]
== Уобичајени задаци

Ово поглавље приказује неке уобичајене задатке, уз примере. Овде се користе само делимичне ствари из API, за потпуно упутство, погледајте link:weechat_plugin_api.sr.html[WeeChat референтни приручник API додатака].

[[buffers]]
=== Бафери

[[buffers_display_messages]]
==== Приказ порука

Празан стринг се често користи за рад са WeeChat бафером језгра. За остале бафере, морате навести показивач (као стринг, погледајте <<pointers,показивачи>>).

Примери:

[source,python]
----
# приказ „здраво” у баферу језгра
weechat.prnt("", "здраво")

# приказ „здраво” у баферу језгра, али без уписа у лог фајл
# (само у верзијама ≥ 0.3.3)
weechat.prnt_date_tags("", 0, "no_log", "здраво")

# приказ префикса „==>” и поруке „здраво” у текућем баферу
# (префикс и порука су раздвојени таб карактером)
weechat.prnt(weechat.current_buffer(), "==>\tздраво")

# приказ поруке о грешки у баферу језгра (са префиксом грешка)
weechat.prnt("", "%sпогрешни аргументи" % weechat.prefix("грешка"))

# приказ поруке са бојом у баферу језгра
weechat.prnt("", "текст %sжуто на плавом" % weechat.color("yellow,blue"))

# претрага бафера и приказ поруке
# (пуно име бафера је додатак.име, на пример: „irc.libera.#weechat”)
buffer = weechat.buffer_search("irc", "libera.#weechat")
weechat.prnt(buffer, "порука на #weechat каналу")

# још једно решење за проналажење IRC бафера (боље)
# (приметите да су сервер и канал раздвојени запетом)
buffer = weechat.info_get("irc_buffer", "libera,#weechat")
weechat.prnt(buffer, "порука на #weechat каналу")
----

[NOTE]
Print функција се назива `prnt` у Python, а `print` у осталим језицима.

[[buffers_send_text]]
==== Слање текста у бафер

Текст или команду можете да пошаљете у бафер. Ово је потпуно исто као да откуцате текст на командној линији и притиснете [Ентер].

Примери:

[source,python]
----
# извршавање команде „/help” у текућем баферу (резултат иде у бафер језгра)
weechat.command("", "/help")

# слање „hello” на #weechat IRC канал (корисници на каналу ће видети поруку)
buffer = weechat.info_get("irc_buffer", "libera,#weechat")
weechat.command(buffer, "hello")
----

[[buffers_new]]
==== Креирање новог бафера

У својој скрипти можете креирати нови бафер, па да га затим користите за приказ порука.

Могу да се позову две функције повратног позива (нису обавезне): једна за улазне податке (када откуцате неки текст и притиснете [Ентер] у баферу), друга се позива када се бафер затвори (на пример, са `/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", "Ово је наслов мог бафера.")

# искључивање логовања, постављањем локалне променљиве „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")
----

Могyће је додавање, читање или брисање локалних променњивих у баферу:

[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 listvar
----

[[hooks]]
=== Куке

[[hook_command]]
==== Додавање нове команде

Нову команду додајете са `+hook_command+`. Можете да употребите шаблон прилагођеног довршавања за довршавање аргумената ваше команде.

Пример:

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

hook = weechat.hook_command("мојфилтер", "опис за мојфилтер",
    "[list] | [enable|disable|toggle [име]] | [add име plugin.buffer tags regex] | [del име|-all]",
    "опис аргумената...",
    "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 мојфилтер

/мојфилтер аргументи...
----

[[hook_timer]]
==== Додавање тајмера

Тајмер се додаје са `+hook_timer+`.

Пример:

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

# тајмер се позива сваког минута када су секунде 00
weechat.hook_timer(60 * 1000, 60, 0, "timer_cb", "")
----

[[hook_process]]
==== Покретање процеса у позадини

Процес можете да покренете у позадини са `+hook_process+`. Ваша функција повратног позива ће се позвати онда када подаци буду спремни. Може да се позива више пута.

У последњем позиву ваше функције повратног позива, _return_code_ се поставља на 0 или позитивну вредност, то је повратни кôд команде.

Пример:

[source,python]
----
def my_process_cb(data, command, return_code, out, err):
    if return_code == weechat.WEECHAT_HOOK_PROCESS_ERROR:
        weechat.prnt("", "Error with command '%s'" % command)
        return weechat.WEECHAT_RC_OK
    if return_code >= 0:
        weechat.prnt("", "return_code = %d" % return_code)
    if out:
        weechat.prnt("", "stdout: %s" % out)
    if err:
        weechat.prnt("", "stderr: %s" % err)
    return weechat.WEECHAT_RC_OK

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

Уместо спољне команде, такође можете директно да позовете скрипт функцију
која ради нешто што блокира:

[source,python]
----
def get_status(data):
    # do something blocking...
    # ...
    return "this is the result"

def my_process_cb(data, command, return_code, out, err):
    if return_code == weechat.WEECHAT_HOOK_PROCESS_ERROR:
        weechat.prnt("", "Error with command '%s'" % command)
        return weechat.WEECHAT_RC_OK
    if return_code >= 0:
        weechat.prnt("", "return_code = %d" % return_code)
    if out:
        weechat.prnt("", "stdout: %s" % out)
    if err:
        weechat.prnt("", "stderr: %s" % err)
    return weechat.WEECHAT_RC_OK

hook = weechat.hook_process("func:get_status", 5000, "my_process_cb", "")
----

[[url_transfer]]
==== URL пренос

_Ново у верзији 0.3.7._

Ако желите да преузмете URL (или пошаљете на URL), морате да употребите функцију `+hook_process+`, или `+hook_process_hashtable+` ако је потребно да поставите опције URL преноса.

Пример URL преноса без опције: HTML страница ће се примити као „out” у функцији повратног позива (стандардни излаз процеса):

[source,python]
----
# Приказује последњу стабилну верзију WeeChat.
weechat_latest_version = ""

def weechat_process_cb(data, command, return_code, out, err):
    global weechat_latest_version
    if out:
        weechat_latest_version += out
    if return_code >= 0:
        weechat.prnt("", "Последња WeeChat верзија: %s" % weechat_latest_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, return_code, out, err):
    if return_code >= 0:
        weechat.prnt("", "Крај преноса (return code = %d)" % return_code)
    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 преноса, као и за доступне опције, погледајте функције `+hook_process+` и `+hook_process_hashtable+` у link:weechat_plugin_api.sr.html#_hook_process[WeeChat референтни приручник API додатака].

[[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]
----
# string
weechat.prnt("", "вредност опције weechat.look.item_time_format је: %s"
                 % (weechat.config_string(weechat.config_get("weechat.look.item_time_format"))))

# boolean
weechat.prnt("", "вредност опције weechat.look.day_change је: %d"
                 % (weechat.config_boolean(weechat.config_get("weechat.look.day_change"))))

# integer
weechat.prnt("", "вредност опције weechat.look.scroll_page_percent је: %d"
                 % (weechat.config_integer(weechat.config_get("weechat.look.scroll_page_percent"))))

# color
weechat.prnt("", "вредност опције weechat.color.chat_delimiters је: %s"
                 % (weechat.config_color(weechat.config_get("weechat.color.chat_delimiters"))))
----

[[irc]]
=== IRC

[[irc_catch_messages]]
==== Хватање порука

IRC додатак шаље четири сигнала за примљену поруку (`xxx` је IRC интерно име сервера, `yyy` је IRC име команде као што је JOIN, QUIT, PRIVMSG, 301, ...):

xxx,irc_in_yyy::
    сигнал који се шаље пре обраде поруке, само ако се порука *не* игнорише

xxx,irc_in2_yyy::
    сигнал који се шаље након обраде поруке, само ако се порука *не* игнорише

xxx,irc_raw_in_yyy::
    сигнал који се шаље пре обраде поруке, чак и ако се порука игнорише

xxx,irc_raw_in2_yyy::
    сигнал који се шаље након обраде поруке, чак и ако се порука игнорише

[source,python]
----
def join_cb(data, signal, signal_data):
    # сигнал је на пример: „libera,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) се придружио овом каналу!" % (msg["nick"], msg["host"]))
    return weechat.WEECHAT_RC_OK

# овде је корисни да се као сервер употреби „*”, како би се хватале JOIN поруке
# на свим IRC серверима
weechat.hook_signal("*,irc_in2_join", "join_cb", "")
----

[[irc_modify_messages]]
==== Измена порука

IRC додатак шаље два „модификатора” за сваку примљену поруку („xxx” је IRC команда), тако да можете да је измените:

irc_in_xxx::
    модификатор који се шаље пре декодирања у скуп карактера: користите уз опрез, стринг може да садржи неважеће UTF-8 податке; користите само за сирове операције над поруком

irc_in2_xxx::
    модификатор који се шаље након декодирања у скуп карактера, тако да је примљени стринг увек важећи UTF-8 (*препоручује се*)

[source,python]
----
def modifier_cb(data, modifier, modifier_data, string):
    # у све примљене поруке се додаје име сервера
    # (OK ово и није баш корисно, али то је само пример!)
    return "%s %s" % (string, modifier_data)

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

[WARNING]
Неправилно формирана порука би могла да сруши програм WeeChat или да изазове озбиљне проблеме!

[[irc_message_parse]]
==== Парсирање поруке

_Ново у верзији 0.3.4._

IRC поруку можете да парсирате са info_hashtable под именом „irc_message_parse”.

Резултат је хеш табела са следећим кључевима (вредности за пример су изграђене из следеће поруке: `+@time=2015-06-27T16:40:35.000Z :nick!user@host PRIVMSG #weechat :здраво!+`):

[width="100%", cols="3,^2,10,7", options="header"]
|===
| Кључ | Од WeeChat ^(1)^ | Опис | Пример

| tags | 0.4.0 |
  Ознаке у поруци (може бити празно). |
  `+time=2015-06-27T16:40:35.000Z+`

| tag_xxx | 3.3 |
  Неозначена вредност ознаке "xxx" (један кључ по ознаци). |
  `+2015-06-27T16:40:35.000Z+`

| message_without_tags | 0.4.0 |
  Порука без ознака (иста као оригинална ако нема ознака у њој). |
  `+:nick!user@host PRIVMSG #weechat :здраво!+`

| nick | 0.3.4 |
  Надимак порекла. |
  `+nick+`

| user | 2.7 |
  Корисник порекла. |
  `+user+`

| host | 0.3.4 |
  Хост порекла (укључујући и надимак). |
  `+nick!user@host+`

| command | 0.3.4 |
  Команда (_PRIVMSG_, _NOTICE_, ...). |
  `+PRIVMSG+`

| channel | 0.3.4 |
  Циљни канал. |
  `+#weechat+`

| arguments | 0.3.4 |
  Аргументи команде (укључујући и канал). |
  `+#weechat :здраво!+`

| text | 1.3 |
  Текст (на пример, корисникова порука). |
  `+здраво!+`

| pos_command | 1.3 |
  Индекс _command_ у поруци („-1” ако се _command_ не пронађе). |
  `+47+`

| pos_arguments | 1.3 |
  Индекс _arguments_ у поруци („-1” ако се _arguments_ не пронађе). |
  `+55+`

| pos_channel | 1.3 |
  Индекс _channel_ у поруци („-1” ако се _channel_ не пронађе). |
  `+55+`

| pos_text | 1.3 |
  Индекс _text_ у поруци („-1” ако се  _text_ не пронађе). |
  `+65+`
|===

[NOTE]
^(1)^ Овај кључ је уведен у наведеној верзији програма WeeChat

[source,python]
----
dict = weechat.info_get_hashtable(
    "irc_message_parse",
    {"message": "@time=2015-06-27T16:40:35.000Z;tag2=value\\sspace :nick!user@host PRIVMSG #weechat :здраво!"})

# dict == {
#     "tags": "time=2015-06-27T16:40:35.000Z;tag2=value\\sspace",
#     "tag_time": "2015-06-27T16:40:35.000Z",
#     "tag_tag2": "value space",
#     "message_without_tags": ":nick!user@host PRIVMSG #weechat :здраво!",
#     "nick": "nick",
#     "user": "user",
#     "host": "nick!user@host",
#     "command": "PRIVMSG",
#     "channel": "#weechat",
#     "arguments": "#weechat :здраво!",
#     "text": "hello!",
#     "pos_command": "65",
#     "pos_arguments": "73",
#     "pos_channel": "73",
#     "pos_text": "83",
# }
----

[[infos]]
=== Информације

[[infos_weechat_version]]
==== Верзија програма WeeChat

Најбољи начин да се провери верзија је да се затражи „version_number”, па да се уради целобројно поређење са хексадецималним бројем верзије.

Пример:

[source,python]
----
version = weechat.info_get("version_number", "") or 0
if int(version) >= 0x00030200:
    weechat.prnt("", "Ово је WeeChat 0.3.2 или новији")
else:
    weechat.prnt("", "Ово је WeeChat 0.3.1 или старији")
----

[NOTE]
Верзије ≤ 0.3.1.1 враћају празан стринг за _info_get("version_number")_ тако да морате проверити да враћена вредност *није* празна.

Да бисте добили верзију као стринг:

[source,python]
----
# ово ће да испише на пример „Верзија 0.3.2”
weechat.prnt("", "Верзија %s" % weechat.info_get("version", ""))
----

[[infos_other]]
==== Остале информације

[source,python]
----
# WeeChat конфиг директоријум, на пример: „/home/user/.config/weechat”
weechat.prnt("", "WeeChat конфиг дир: %s" % weechat.info_get("weechat_dir", ""))

# неактивност тастатуре
weechat.prnt("", "Неактивно је %s секунди" % weechat.info_get("inactivity", ""))
----

[[infolists]]
=== Инфолисте

[[infolists_read]]
==== Читање инфолисте

Можете да читате инфолисту коју изгради WeeChat или остали додаци.

Пример:

[source,python]
----
# читање infolist „buffer”, како би се добила листа бафера
infolist = weechat.infolist_get("buffer", "", "")
if infolist:
    while weechat.infolist_next(infolist):
        name = weechat.infolist_string(infolist, "name")
        weechat.prnt("", "бафер: %s" % name)
    weechat.infolist_free(infolist)
----

[IMPORTANT]
Не заборавите да позовете `+infolist_free+` како бисте ослободите меморију коју користи infolist, јер програм WeeChat неће аутоматски ослободити меморију.
