= Poradnik pisania skryptów WeeChat :author: Sébastien Helleu :email: flashcode@flashtux.org :lang: pl :toc: left :toclevels: 3 :toc-title: Spis treści :sectnums: :docinfo1: Tłumaczenie: * Krzysztof Korościk , 2009-2016 Ten dokument opisuje klienta rozmów WeeChat, który jest częścią WeeChat. Najnowsza wersja tego dokumentu znajduje się na tej stronie: https://weechat.org/doc [[introduction]] == Wprowadzenie WeeChat (Wee Enhanced Environment for Chat) jest darmowym klientem rozmów, szybkim i lekkim, zaprojektowanym dla wielu systemów operacyjnych. Ten dokument przedstawia sposób pisania skryptów dla WeeChat z użyciem jednego ze wspieranych języków skryptowych: * Python * Perl * Ruby * Lua * Tcl * Guile (Scheme) * Javascript * PHP [NOTE] Prawie wszystkie przykłady umieszczone w tym dokumencie są napisane w Pythonie, ale API jest takie same dla wszystkich języków. [[scripts_in_weechat]] == Skrypty w WeeChat [[languages_specificities]] === Specyfika języków ==== Python * Należy wykonać `import weechat` * Funkcje `+print*+` są nazwane `+prnt*+` w pythonie (ponieważ _print_ jest zastrzeżonym słowem kluczowym) * Funkcje są wywoływane za pomocą `weechat.xxx(arg1, arg2, ...)` ==== Perl * Funkcje są wywoływane za pomocą `weechat::xxx(arg1, arg2, ...);` ==== Ruby * Trzeba zdefiniować _weechat_init_ i wywołać _register_ wewnątrz * Funkcje są wywoływane za pomocą `Weechat.xxx(arg1, arg2, ...)` * W związku z ograniczeniami Ruby (maksymalnie 15 argumentów dla funkcji), funkcja `Weechat.config_new_option` otrzymuje callbacki w postaci tablicy 6 ciągów (3 callbacki + 3 ciągi danych), wywołanie tej funkcji wygląda następująco: [source,ruby] ---- Weechat.config_new_option(config, section, "nazwa", "ciąg", "opis opcji", "", 0, 0, "wartość", "wartość", 0, ["check_cb", "", "change_cb", "", "delete_cb", ""]) ---- ==== Lua * Funkcje są wywoływane za pomocą `weechat.xxx(arg1, arg2, ...)` ==== Tcl * Funkcje są wywoływane za pomocą `weechat::xxx arg1 arg2 ...` ==== Guile (Scheme) * Funkcje są wywoływane za pomocą `(weechat:xxx arg1 arg2 ...)` * Następujące funkcje przyjmują pojedynczą listę argumentów (zamiast wielu argumentów dla innych funkcji), ponieważ ilość argumentów przekracza ilość argumentów dozwolonych w Guile: ** config_new_section ** config_new_option ** bar_new ==== Javascript * Funkcje są wywoływane za pomocą `weechat.xxx(arg1, arg2, ...);` ==== PHP * Funkcje są wywoływane za pomocą `weechat_xxx(arg1, arg2, ...);` [[register_function]] === Funkcja rejestrująca Wszystkie skrypty WeeChat muszą się "zarejestrować" w WeeChat, musi to być pierwsza z funkcji WeeChat wywołana w skrypcie. Prototyp: [source,python] ---- weechat.register(nazwa, autor, wersja, licencja, opis, funkcja_wyłączająca, kodowanie) ---- Argumenty: * _nazwa_: string, wewnętrzna nazwa skryptu * _autor_: string, autor skryptu * _wersja_: string, wersja * _licencja_: string, licencja * _opis_: string, krótki opis skryptu * _funkcja_wyłączająca_: string, nazwa funkcji wywoływanej podczas wyładowania skryptu (może być pusty ciąg) * _kodowanie_: string, kodowane skryptu (jeśli skrypt jest napisany w UTF-8 można nie podawać tej wartości - UTF-8 to domyślne kodowanie) Przykład dla skryptu w każdym z języków: * Python: [source,python] ---- import weechat weechat.register("test_python", "FlashCode", "1.0", "GPL3", "Skrypt testowy", "", "") weechat.prnt("", "Witaj z pythonowego skryptu!") ---- * Perl: [source,perl] ---- weechat::register("test_perl", "FlashCode", "1.0", "GPL3", "Skrypt testowy", "", ""); weechat::print("", "Witaj z perlowego skryptu!"); ---- * Ruby: [source,ruby] ---- def weechat_init Weechat.register("test_ruby", "FlashCode", "1.0", "GPL3", "Skrypt testowy", "", "") Weechat.print("", "Witaj ze skryptu ruby!") return Weechat::WEECHAT_RC_OK end ---- * Lua: [source,lua] ---- weechat.register("test_lua", "FlashCode", "1.0", "GPL3", "Skrypt testowy", "", "") weechat.print("", "Witaj ze skryptu lua!") ---- * Tcl: [source,tcl] ---- weechat::register "test_tcl" "FlashCode" "1.0" "GPL3" "Skrypt testowy" "" "" weechat::print "" "Witaj ze skryptu tcl!" ---- * Guile (Scheme): [source,lisp] ---- (weechat:register "test_scheme" "FlashCode" "1.0" "GPL3" "Skrypt testowy" "" "") (weechat:print "" "Witaj ze skryptu scheme!") ---- * Javascript: [source,javascript] ---- weechat.register("test_js", "FlashCode", "1.0", "GPL3", "Skrypt testowy", "", ""); weechat.print("", "Witaj ze skryptu javascript!"); ---- * PHP: [source,php] ---- >). Przykłady: [source,python] ---- # wyświetl "witaj" w głównym buforze weechat.prnt("", "witaj") # wyświetl "witaj" w głównym buforze, ale nie zapisuj tego do pliku z logiem # (tylko wersje >= 0.3.3) weechat.prnt_date_tags("", 0, "no_log", "witaj") # wyświetl "==>" przed wiadomością "witaj" w obecnym buforze # (przedrostek i wiadomość muszą być oddzielone znakiem tabulacji) weechat.prnt(weechat.current_buffer(), "==>\twitaj") # wyświetla wiadomość o błędzie w głównym buforze (z przedrostkiem błąd) weechat.prnt("", "%szłe argumenty" % weechat.prefix("błąd")) # wyświetl wiadomość z kolorem w głównym buforze weechat.prnt("", "text %sżółty na niebieskim" % weechat.color("yellow,blue")) # przeszuka bufor i wyświetli wiadomość # (pełna nazwa bufora to wtyczka.nazwa, na przykład: "irc.freenode.#weechat") buffer = weechat.buffer_search("irc", "freenode.#weechat") weechat.prnt(buffer, "wiadomość na kanale #weechat") # inne rozwiązanie na znalezienie bufora IRC (lepsze) # (zauważ, że serwer i kanał są oddzielone przecinkiem) buffer = weechat.info_get("irc_buffer", "freenode,#weechat") weechat.prnt(buffer, "wiadomość na kanale #weechat") ---- [NOTE] Funkcja drukująca nazywa się `print` w Perl/Ruby/Lua/Tcl/Guile/Javascript i `prnt` w Pythonie. [[buffers_send_text]] ==== Wysyłanie tekstu do bufora Możesz wysłać tekst lub komendę do bufora. Dokładnie tak jakby wpisać tekst w linii poleceń i wcisnąć [Enter]. Przykłady: [source,python] ---- # wykona polecenie "/help" w obecnym buforze (wyświetli się w głównym buforze) weechat.command("", "/help") # wyśle "witaj" na kanał #weechat (użytkownicy na kanale zobaczą wiadomość) buffer = weechat.info_get("irc_buffer", "freenode,#weechat") weechat.command(buffer, "witaj") ---- [[buffers_new]] ==== Tworzenie nowego buforu Możesz stworzyć nowy bufor w skrypcie, następnie użyć go do wyświetlania wiadomości. Dwa callbacki mogą zostać wywołane (są opcjonalne): jeden dla danych wejściowych (kiedy wpiszesz tekst i naciśniesz [Enter] w buforze), drugi jest wywoływany podczas zamykania bufora (na przykład przez `/buffer close`). Przykłady: [source,python] ---- # callback dla danych otrzymanych na wejściu def buffer_input_cb(data, buffer, input_data): # ... return weechat.WEECHAT_RC_OK # callback wywoływany przy zamknięciu bufora def buffer_close_cb(data, buffer): # ... return weechat.WEECHAT_RC_OK # tworzenie bufora buffer = weechat.buffer_new("mybuffer", "buffer_input_cb", "", "buffer_close_cb", "") # ustawianie tytułu weechat.buffer_set(buffer, "title", "To jest tytuł mojego buforu.") # wyłącza logowanie, przez ustawienie zmiennej lokalnej "no_log" na "1" weechat.buffer_set(buffer, "localvar_set_no_log", "1") ---- [[buffers_properties]] ==== Właściwości buforów Możesz odczytać właściwości buforów jako ciąg, liczbę lub wskaźnik. Przykłady: [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") ---- Możliwe jest dodanie, odczytanie lub kasowanie lokalnych zmiennych dla buforów: [source,python] ---- # dodanie zmiennej lokalnej weechat.buffer_set(buffer, "localvar_set_myvar", "my_value") # odczyt zmiennej lokalnej myvar = weechat.buffer_get_string(buffer, "localvar_myvar") # kasowanie zmiennej lokalnej weechat.buffer_set(buffer, "localvar_del_myvar", "") ---- Aby zobaczyć lokalne zmienne danego bufora, należy wykonać tą komendę w WeeChat: ---- /buffer localvar ---- [[hooks]] === Hooks [[hook_command]] ==== Dodanie nowej komendy Aby dodać nową komendę należy użyć `hook_command`. Można użyć własnego szablonu dopełnień dla uzupełniania argumentów własnej komendy. Przykład: [source,python] ---- def my_command_cb(data, buffer, args): # ... return weechat.WEECHAT_RC_OK hook = weechat.hook_command("myfilter", "opis 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", "") ---- Następnie w WeeChat: ---- /help myfilter /myfilter argumenty... ---- [[hook_timer]] ==== Dodanie timera Do dodania timera służy `hook_timer`. Przykład: [source,python] ---- def timer_cb(data, remaining_calls): # ... return weechat.WEECHAT_RC_OK # timer wywoływany co minutę, kiedy liczba sekund wynosi 00 weechat.hook_timer(60 * 1000, 60, 0, "timer_cb", "") ---- [[hook_process]] ==== Wykonuje proces w tle Do wykonywania procesów w tle służy `hook_process`. Twoje callbacki zostaną wywołane, kiedy dane będą gotowe. Może zostać wywołane wiele razy. Dla ostatniego wykonania Twojego callbacku _rc_ jest ustawiane na 0, lub wartość dodatnią, jest to kod zwracany przez komendę. Przykład: [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]] ==== Transfer URL _Nowe w wersji 0.3.7._ Aby pobrać URL (albo wysłać do URL), należy użyć funkcji `hook_process`, lub `hook_process_hashtable` jeśli konieczne jest przekazanie parametrów. Przykład transferu URL bez opcji: strona HTML jest otrzymywana jako "out" (standardowe wyjście procesu): [source,python] ---- # Wyświetla aktualną stabilną wersję 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("", "Obecna wersja stabilna WeeChat: %s" % weechat_version) return weechat.WEECHAT_RC_OK weechat.hook_process("url:https://weechat.org/dev/info/stable/", 30 * 1000, "weechat_process_cb", "") ---- [TIP] Wszystkie informacje o WeeChat dostępne są na stronie https://weechat.org/dev/info Przykładowy transfer URL z opcją: pobranie najnowszej wersji rozwojowej WeeChat do pliku _/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", "") ---- Więcej informacji o transferach URL i dostępnych opcjach dla funkcji `hook_process` oraz `hook_process_hashtable` można znaleźć w link:weechat_plugin_api.en.html#_hook_process[Opisu API wtyczek WeeChat] (Angielski). [[config_options]] === Konfiguracja / opcje [[config_options_set_script]] ==== Ustawianie opcji dla skryptu Funkcja `config_is_set_plugin` używana jest do sprawdzenia czy opcja jest ustawiona, `config_set_plugin` ustawia opcję. Example: [source,python] ---- script_options = { "opcja1" : "wartość1", "opcja2" : "wartość2", "opcja3" : "wartość3", } 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]] ==== Wykrywanie zmian Do wykrywania zmian opcji skryptu służy `hook_config`. Przykład: [source,python] ---- SCRIPT_NAME = "myscript" # ... def config_cb(data, option, value): """Callback called when a script option is changed.""" # na przykład, odczyt wszystkich opcji skryptu... # ... return weechat.WEECHAT_RC_OK # ... weechat.hook_config("plugins.var.python." + SCRIPT_NAME + ".*", "config_cb", "") # dla innych języków, zmień "python" na swój język (perl/ruby/lua/tcl/guile/javascript) ---- [[config_options_weechat]] ==== Odczyt opcji WeeChat Funkcja `config_get` zwraca wskaźnik do opcji. Następnie, w zależności od typu opcji, należy wywołać `config_string`, `config_boolean`, `config_integer` lub `config_color`. [source,python] ---- # string weechat.prnt("", "wartość opcji weechat.look.item_time_format to: %s" % (weechat.config_string(weechat.config_get("weechat.look.item_time_format")))) # boolean weechat.prnt("", "wartość opcji weechat.look.day_change to: %d" % (weechat.config_boolean(weechat.config_get("weechat.look.day_change")))) # integer weechat.prnt("", "wartość opcji weechat.look.scroll_page_percent to: %d" % (weechat.config_integer(weechat.config_get("weechat.look.scroll_page_percent")))) # color weechat.prnt("", "wartość opcji weechat.color.chat_delimiters to: %s" % (weechat.config_color(weechat.config_get("weechat.color.chat_delimiters")))) ---- [[irc]] === IRC [[irc_catch_messages]] ==== Przechwytywanie wiadomości Wtyczka IRC wysyła dwa sygnały dla otrzymanej wiadomości (`xxx` jest wewnętrzną nazwą serwera IRC, `yyy` to komenda IRC jak JOIN, QUIT, PRIVMSG, 301, ..): xxxx,irc_in_yyy:: sygnał wysłany przed przetworzeniem wiadomości xxx,irc_in2_yyy:: sygnał wysłany po przetworzeniu wiadomości [source,python] ---- def join_cb(data, sygnał, signal_data): # sygnał to na przykład: "freenode,irc_in2_join" # signal_data to wiadomość IRC, na przykład: ":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 # przydatne jest użycie "*" jako serwera, aby złapać wiadomość JOIN na wszystkich # serwerach IRC weechat.hook_signal("*,irc_in2_join", "join_cb", "") ---- [[irc_modify_messages]] ==== Modyfikowanie wiadomości Wtyczka IRC wysyła "modyfikator" nazwany "irc_in_xxx" ("xxx" to komenda IRC) dla otrzymanej wiadomości, żeby można było ją zmodyfikować. [source,python] ---- def modifier_cb(data, modifier, modifier_data, string): # dodaje nazwę serwera do wszystkich otrzymanych wiadomości # (nie jest to może bardzo przydatne, ale to tylko przykład!) return "%s %s" % (string, modifier_data) weechat.hook_modifier("irc_in_privmsg", "modifier_cb", "") ---- [WARNING] Zniekształcone wiadomości mogą uszkodzić WeeChat, lub spowodować wiele problemów! [[irc_message_parse]] ==== Przetwarzanie wiadomości _Nowe w wersji 0.3.4._ Można przetwarzać wiadomości IRC za pomocą info_hashtable zwanej "irc_message_parse". Wynik jest tabela hashy z następującymi kluczami (przykładowe wartości zostały uzyskane za pomocą wiadomości: `@time=2015-06-27T16:40:35.000Z :nick!user@host PRIVMSG #weechat :hello!`): [width="100%",cols="1,^2,10,8",options="header"] |=== | Klucz | Wersja WeeChat | Opis | Przykład | tags | ≥ 0.4.0 | Tagi w wiadomości (mogą byc puste). | `time=2015-06-27T16:40:35.000Z` | message_without_tags | ≥ 0.4.0 | Wiadomość bez tagów (jeśli nie ma tagów jest to to samo co wiadomość). | `:nick!user@host PRIVMSG #weechat :hello!` | nick | ≥ 0.3.4 | Nick żródła. | `nick` | host | ≥ 0.3.4 | Host żródła (zawiera nick). | `nick!user@host` | command | ≥ 0.3.4 | Komenda (_PRIVMSG_, _NOTICE_, ...). | `PRIVMSG` | channel | ≥ 0.3.4 | Docelowy kanał. | `#weechat` | arguments | ≥ 0.3.4 | Argumenty komendy (zawierają kanał). | `#weechat :hello!` | text | ≥ 1.3 | Tekst (na przykład wiadomość użytkownika). | `hello!` | pos_command | ≥ 1.3 | The index of _command_ in message ("-1" if _command_ was not found). | `47` | pos_arguments | ≥ 1.3 | The index of _arguments_ in message ("-1" if _arguments_ was not found). | `55` | pos_channel | ≥ 1.3 | The index of _channel_ in message ("-1" if _channel_ was not found). | `55` | pos_text | ≥ 1.3 | The index of _text_ in message ("-1" if _text_ was not found). | `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]] === Informacje [[infos_weechat_version]] ==== Wersja WeeChat Najprostszym sposobem na sprawdzenie wersji to pozyskanie "version_number" i wykonanie porównania między liczbą całkowitą a heksadecymalnym numerem wersji. Przykład: [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] Wersje ≤ 0.3.1.1 zwracają pusty ciąg dla _info_get("version_number")_ należy sprawdzić, czy zwracana wartość *nie* jest pusta. Aby otrzymać ciąg z numerem wersji: [source,python] ---- # wyświetli to na przykład "Version 0.3.2" weechat.prnt("", "Version %s" % weechat.info_get("version", "")) ---- [[infos_other]] ==== Inne informacje [source,python] ---- # katalog domowy WeeChat, na przykład: "/home/xxxx/.weechat" weechat.prnt("", "Katalog domowy WeeChat: %s" % weechat.info_get("weechat_dir", "")) # nieaktywność klawiatury weechat.prnt("", "Nieaktywny od %s sekund" % weechat.info_get("inactivity", "")) ---- [[infolists]] === Infolisty [[infolists_read]] ==== Odczytanie infolisty Można odczytać infolisty wbudowane w WeeChat lub inne wtyczki. Przykład: [source,python] ---- # odczyta infolistę "buffer", aby otrzymać listę buforów 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] Nie zapomnij wywołać `infolist_free`, aby zwolnić pamięć użyta przez infolistę, ponieważ WeeChat nie zwolni automatycznie tej pamięci.