pax_global_header00006660000000000000000000000064135474010700014513gustar00rootroot0000000000000052 comment=6384e13179fef12638ad9cf9ab71c2c7156b0c57 weechat-scripts-20191009/000077500000000000000000000000001354740107000150675ustar00rootroot00000000000000weechat-scripts-20191009/guile/000077500000000000000000000000001354740107000161745ustar00rootroot00000000000000weechat-scripts-20191009/guile/emote.scm000066400000000000000000000054621354740107000200200ustar00rootroot00000000000000; Copyright (c) 2014 by csmith ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 3 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . ; ; ; (this script requires WeeChat 0.4.1 or newer) ; ; History: ; 2017-02-18, nycatelos ; version 0.3: added more emotes ; 2016-06-03, nycatelos ; version 0.2: added additional emotes ; 2014-05-03, csmith ; version 0.1: initial release (use-modules (srfi srfi-69)) (weechat:register "emote" "Caleb Smith" "0.3" "GPL" "Emote" "" "") ; Mappings of words with their emoticons (define patterns (alist->hash-table '( ("tableflip" . "(╯° °)╯︵ ┻━┻)") ("rageflip" . "(ノಠ益ಠ)ノ彡┻━┻") ("doubleflip" . "┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻") ("disapproval" . "ಠ_ಠ") ("sun" . "☼") ("kitaa" . "キタ━━━(゜∀゜)━━━!!!!!") ("joy" . "◕‿◕") ("nyancat" . "~=[,,_,,]:3") ("lenny" . "( ͡° ͜ʖ ͡°)") ("shrug" . "¯\\_(ツ)_/¯") ("denko" . "(・ω・)") ("tableplace" . "┬─┬ ノ( ゜-゜ノ)") ("gface" . "( ≖‿≖)") ("facepalm" . "(-‸ლ)") ("tehe" . "☆~(◡﹏◕✿)") ("angry" . "(╬ ಠ益ಠ)") ("umu" . "( ̄ー ̄)") ("toast" . "( ^_^)o自自o(^_^ )") ("yay" . "ヽ(´ー`)ノ") ))) ; Derive the tab completion string for the subcommands. (define tab-completions (apply string-append (map (lambda (i) (string-append "|| " i)) (hash-table-keys patterns)))) ; Hook main function up to the /emote command (weechat:hook_command "emote" "Emote" "/emote phrase" (string-append "" "\nUse `/emote phrase`. Words in phrase will be replaced with their" "\nemoticons:" "\n" "\nExamples:" "\n /emote tableflip - (╯° °)╯︵ ┻━┻)" "\n /emote look - ಠ_ಠ") tab-completions "main" "") ; Handle the IRC command given by the user. Sets input buffer as a side-effect (define (main data buffer command) (weechat:buffer_set buffer "input" (apply string-append (map (lambda (c) (string-append (hash-table-ref/default patterns c c) " ")) (string-tokenize command)))) weechat:WEECHAT_RC_OK) weechat-scripts-20191009/guile/gateway_rename.scm000066400000000000000000000262541354740107000217010ustar00rootroot00000000000000;; -*- geiser-scheme-implementation: 'guile -*- ;; Copyright 2017 by Zephyr Pellerin ;; ------------------------------------------------------------ ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;; History: ;; 1.2 - Use weechat plugin configuration data to match IRC gateways ;; 0.9 - Lookup correct servername in /VERSION ;; 0.8 - Barebones, contained list of translations (use-modules ((srfi srfi-1) #:select (any fold))) (use-modules ((srfi srfi-26) #:select (cut))) (use-modules (ice-9 regex)) (use-modules (ice-9 hash-table)) (use-modules (ice-9 match)) (define *weechat/script-name* "gateway_rename") (define *weechat/script-author* "zv ") (define *weechat/script-version* "1.2.1") (define *weechat/script-license* "GPL3") (define *weechat/script-description* "Convert usernames of gateway connections their real names") ;; A test-harness for checking if we are inside weechat (define-syntax if-weechat (syntax-rules () ((_ conseq alt) (if (defined? 'weechat:register) conseq alt)) ((_ conseq) (if (defined? 'weechat:register) conseq)))) (if-weechat (weechat:register *weechat/script-name* *weechat/script-author* *weechat/script-version* *weechat/script-license* *weechat/script-description* "" "")) ;; `user-prefix' is a distinguishing username prefix for 'fake' users (define *user-prefix* "^") (define *gateway-config* "gateways") (define *default-irc-gateways* "(freenode #radare r2tg ) (freenode #test-channel zv-test NICK:)") (define (print . msgs) (if (defined? 'weechat:print) (weechat:print "" (apply format (cons #f msgs))))) ;; A regular expression must have the gateway username in the first matchgroup, ;; the "real" username in the 3rd, and the real-username along with it's enclosing ;; brackets in the 2nd (define *gateway-regexps* (make-hash-table)) (define (process-network-infolist) "Convert the internal user-defined servername to the 'true' servername returned during /version" (define il (weechat:infolist_get "irc_server" "" "")) ;; pull the network field out of the list of /VERSION results (define (extract-network result) (if (null? result) #f (match (string-split (car result) #\=) [("NETWORK" network) network] [_ (extract-network (cdr result))]))) ;; pull out a '(name network-name) pair from an infolist str (define (process return-code) (if (= return-code 0) '() (let* ((name (weechat:infolist_string il "name")) (isupport (weechat:infolist_string il "isupport")) (reply (string-split isupport #\space)) (network (or (extract-network reply) ;; if no network, use local name name))) (cons (cons name network) (process (weechat:infolist_next il)))))) (process (weechat:infolist_next il))) ;; This is a table that maps a weechat network 'name' to it's IRC-style hostname (define *hostname-table* (alist->hash-table '(("freenode" . "freenode")))) (if-weechat (set! *hostname-table* (alist->hash-table (process-network-infolist)))) (define (replace-privmsg msg gateways) "A function to replace the PRIVMSG sent by by a gateway " (let* ((match? (cut regexp-exec <> msg)) (result (any match? gateways))) (if result (let* ([nth-match (cut match:substring result <>)] ;; take everything after username before message [username (nth-match 1)] [real-username (nth-match 3)] ;; Extract everything after the gateway-user mask [raw-message (string-copy msg (match:end result 2) (string-length msg))] ;; .. and be sure to strip any preceding characters [message (string-trim raw-message)] ;; extract everything before the message but after the username [hostmask (string-copy msg (match:end result 1) (match:start result 2))]) (string-append ":" *user-prefix* real-username hostmask message)) msg))) (define (server->gateways server) (hash-ref *gateway-regexps* (hash-ref *hostname-table* server))) (define (privmsg-modifier data modifier-type server msg) "The hook for all PRIVMSGs in Weechat" (let ((gateways (server->gateways server))) (if gateways (replace-privmsg msg gateways) msg))) (define* (make-gateway-regexp gateway-nick channel mask #:optional emit-string) "Build a regular expression that will match the nick, channel and \"\"-style mask" (let* ([mask-regexp ;; replace with <(\\S*?)> (regexp-substitute/global #f "NICK" mask 'pre "(\\S*?)" 'post "")] [composed-str (format #f ":(~a)!\\S* PRIVMSG ~a :(~a)" gateway-nick (if (equal? "*" channel) "\\S*" channel) mask-regexp)]) (if emit-string composed-str (make-regexp composed-str)))) (define (extract-gateway-fields str) "This is a hack around Guile's non-greedy matchers. # Example scheme@(guile-user)> (extract-gateway-fields \"(freenode #radare r2tg )\") $1 = (\"freenode\" \"#radare\" \"r2tg\" \"\")" (let* ((range-end (λ (range) (+ 1 (cdr range)))) (find-space (λ (end) (string-index str #\space end))) ;; opening (first) and closing (last) parenthesis (opening-par (string-index str #\()) (closing-par (string-index str #\))) ;; extract the range of each (server (cons (+ 1 opening-par) (find-space 0))) (channel (cons (range-end server) (find-space (range-end server)))) (gateway-nick (cons (range-end channel) (find-space (range-end channel)))) (mask (cons (range-end gateway-nick) closing-par))) ;; and then get the strings (map (λ (window) (substring str (car window) (cdr window))) (list server channel gateway-nick mask)))) (define* (process-weechat-option opt #:optional emit-string) "Takes in the application-define weechat-options and emits a server and matching regular expression. The optional parameter `emit-string' controls if a string or a compiled regular expression is returned. # Example scheme@(guile-user)> (process-weechat-option \"(freenode #radare r2tg )\") $1 = '(\"freenode\" . (make-regexp \":(r2tg)!\\S* PRIVMSG #radare :(<(\\S*?)>) .*\")))" (let* ((fields (extract-gateway-fields opt)) (server (list-ref fields 0)) (channel (list-ref fields 1)) (gateway-nick (list-ref fields 2)) (mask (list-ref fields 3))) (cons server (make-gateway-regexp gateway-nick channel mask emit-string)))) (define (split-gateways config) "Push our elts onto the stack to extract our configs # Example scheme@(guile-user)> (split-gateways \"(freenode #radare r2tg )(* * slack-irc-bot NICK:)\") $1 = (\"(freenode #radare r2tg )\" \"(* * slack-irc-bot NICK:)\") " (define (process stk current rest) (if (string-null? rest) (cons current '()) (let* ((head (string-ref rest 0)) (nrest (string-drop rest 1)) (ncurrent (string-append current (string head)))) (cond [(and (null? stk) (not (string-null? current))) (cons current (process stk "" rest))] [(eq? head #\() (process (cons #\( stk) ncurrent nrest)] [(eq? head #\)) (process (cdr stk) ncurrent nrest)] ;; skip characters if our stk is empty [(null? stk) (process stk current nrest)] [else (process stk ncurrent nrest)])))) (process '() "" config)) (define (fetch-weechat-gateway-config) "Extract the gateway configuration string" (if-weechat (weechat:config_get_plugin *gateway-config*) *default-irc-gateways*)) (define (assign-gateways-regex) "Fetch our weechat gateway configuration and assign it to our local regexps" (let* ((config_str (fetch-weechat-gateway-config)) (config_lst (split-gateways config_str)) (gateways (map process-weechat-option config_lst))) ;; for each gateway, add it to our `*gateway-regexps*' ht (for-each (λ (gt) (let* ((server (car gt)) (new-regex (cdr gt)) (server-regexps (hash-ref *gateway-regexps* server '()))) (hash-set! *gateway-regexps* server (cons new-regex server-regexps)))) gateways))) ;; Initialize our weechat settings & privmsg hook (define (renamer_command_cb data buffer args) weechat::WEECHAT_RC_OK) (if-weechat (begin (if (not (= 1 (weechat:config_is_set_plugin *gateway-config*))) (weechat:config_set_plugin *gateway-config* *default-irc-gateways*)) (weechat:hook_modifier "irc_in_privmsg" "privmsg-modifier" "") (weechat:hook_command *weechat/script-name* *weechat/script-description* "" ;; arguments " There are many IRC gateway programs that, rather than sending as if they were another user, simply prepend the name of the user that is using that gateway to the messages they are sending. For example: `slack-irc-bot` might send a message to #weechat: slack-irc-bot: How about them Yankees? gateway_rename intercepts that message and converts it to: ^zv: How about them Yankees? (gateway_rename prefixes the `^' (caret) symbol to each message to prevent message spoofing) Adding a Renamer: Which servers, channels, users and nickname templates are renamed can all be modified in `plugins.var.guile.gateway_rename.gateways' Two gateways are matched by default, but are primarily intended to serve as a template for you to add others. Each gateway renamer is placed inside of a set of parenthesis and contain four fields respectively: 1. IRC server name (use the same name that weechat uses) 2. Channel 3. Gateway's nick/user name 4. The last field is a template for how to match the nickname of the 'real user' For example, if you wanted to convert the message 'gateway-bot: zv: Yes' into 'zv: Yes' You would set the last field to 'NICK:' because each NICK at the beginning of the message is suffixed with a `:' " "" "renamer_command_cb" ""))) ;; Setup our gateways->regex map (assign-gateways-regex) ;;(print "Gateway Nickconverter by zv ") weechat-scripts-20191009/guile/karmastorm.scm000066400000000000000000000030711354740107000210610ustar00rootroot00000000000000; Copyright (c) 2014 by msoucy ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 3 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . ; ; ; (this script requires WeeChat 0.4.1 or newer) ; (weechat:register "karmastorm" "Matt Soucy" "0.3" "GPL3" "KarmaStorm" "" "") ; Hook main function up to the /emote command (weechat:hook_command "karmastorm" "Karma Storm" "/karmastorm num names..." "Increment karma for the given names" "" "main" "") ; Increments karma for all users provided (define (main data buffer command) (letrec ((toked (string-tokenize command)) (incr (lambda (n) (weechat:command buffer (string-append n "++")))) (lp (lambda (num) (if (not (zero? num)) (begin (map incr (cdr toked)) (lp (- num 1)) )))) (err (lambda () ((weechat:print "" "Expected arguments for karmastorm"))))) (if (null? toked) err (lp (string->number (car toked))))) weechat:WEECHAT_RC_OK) weechat-scripts-20191009/guile/weechataboo.scm000066400000000000000000000143041354740107000211630ustar00rootroot00000000000000; WeeChat-Script to replace emotion-tags with random emoticons. ; Copyright (C) 2017-2018 Alvar ; ; This program is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . ; ; For usage see `/help weechataboo` (use-modules (srfi srfi-1)) ; -> List ; Returns a list of available emotions. (define (emotion-categories) (string-split (weechat:config_get_plugin "emotions") #\,)) ; String -> String ; Returns an emoticon for a known emotion. (define (emotion->emoticon emo) (let ((emotions (string-split (weechat:config_get_plugin emo) #\,)) (random-emotion (lambda (l) (list-ref l (random (length l)))))) (random-emotion emotions))) ; String -> String ; Replaces in the given string every ~~EMOTION with a fitting emoticon. (define (emoticonize-line line) (let* ((as-tag (lambda (emo) (string-append "~~" emo))) (has-emotions? (lambda (txt) (any (lambda (emo) (number? (string-contains txt (as-tag emo)))) (emotion-categories)))) (replace (lambda (emo txt) (let ((pos (string-contains txt (as-tag emo)))) (if (number? pos) (string-replace txt (emotion->emoticon emo) pos (+ (string-length (as-tag emo)) pos)) txt)))) (new-line (fold replace line (emotion-categories)))) (if (has-emotions? new-line) (emoticonize-line new-line) new-line))) ; Pointer ? ? String -> String ; This function was registered to be called when an input was submitted and ; will try to replace ~~EMOTIONs to emoticons. (define (weechataboo-hook data modifier modifier-data msg) (emoticonize-line msg)) ; Pointer String List -> Weechat-Return ; Function which tells you to RTFM. (define (weechataboo-func data buffer args) (weechat:print "" "See /help weechataboo") weechat:WEECHAT_RC_OK) ; -> () ; Function to be executed when there is no config yet. Creates a dummy one. (define (initial-setup) (let* ; Some defaults which may be useful‥ ((emotions '(("aggressive" "o(-`д´- 。),凸ಠ益ಠ)凸,' ̿'̵͇̿̿з=(◕_◕)=ε/̵͇̿̿/'̿'̿ ̿,O=('-'Q),。゜(`Д´)゜。,┌∩┐(ಠ_ಠ)┌∩┐") ("angry" "눈_눈,(¬_¬),(`ε´),(¬▂¬),(▽д▽),ಠ_ರೃ,(⋋▂⋌),(‡▼益▼),(*`へ´*)") ("blush" "(´ω`*),(‘-’*),(/ε\*),(*゚∀゚*),(*´ェ`*)") ("cat" "≋≋≋≋≋̯̫⌧̯̫(ˆ•̮ ̮•ˆ)") ("cry" "(;へ:),(πーπ),(iДi),(;Д;),(╥_╥),ಥ╭╮ಥ") ("dance" "ヾ(^^ゞ),(ノ^o^)ノ,⌎⌈╹우╹⌉⌍,└|゚ε゚|┐,┌|゚з゚|┘,(〜 ̄△ ̄)〜") ("drink" "(^-^)_日,(*^◇^)_旦,(  ゜Д゜)⊃旦,~~旦_(-ω-`。)") ("excited" "(≧∇≦*),ヽ(^Д^)ノ,(* >ω<)") ("gross" "(咒),( ≖ิ‿≖ิ ),ʅ(◔౪◔ ) ʃ") ("happy" "≖‿≖,(^ω^),(^ω^),ヽ(ヅ)ノ,(¬‿¬),(◡‿◡✿),(❀◦‿◦),(⁎⚈᷀᷁ᴗ⚈᷀᷁⁎)") ("heart" "♡^▽^♡,✿♥‿♥✿,(。♥‿♥。),ヽ(o♡o)/,(◍•ᴗ•◍)❤,(˘︶˘).。.:*♡,❣◕ ‿ ◕❣") ("hug" "⊂(・﹏・⊂),(っ´▽`)っ,(づ ̄ ³ ̄)づ,⊂(´・ω・`⊂)") ("kiss" "|°з°|,(*^3^),(´ε`*),(っ˘з(˘⌣˘ ),(*^3^)/~♡") ("lenny" "( ͡ ͜ʖ ͡ ),( ͡~ ͜ʖ ͡°),( ͡~ ͜ʖ ͡~),ヽ( ͝° ͜ʖ͡°)ノ,(つ ͡° ͜ʖ ͡°)つ,( ͝סּ ͜ʖ͡סּ),") ("magic" "(っ・ω・)っ≡≡≡≡≡≡☆,ヽ༼ຈل͜ຈ༽⊃─☆*:・゚") ("sheep" "@^ェ^@,@・ェ・@") ("shock" "(゚д゚;)") ("shrug" "┐(´д`)┌,╮(╯∀╰)╭,┐(´∀`)┌,ʅ(́◡◝)ʃ,ヽ(~~~ )ノ,ヽ(。_°)ノ,¯\(◉◡◔)/¯,◔_◔") ("shy" "(/ω\),(‘-’*),(´~`ヾ),(〃´∀`)") ("smug" "( ̄ω ̄),( ̄ー ̄),( ̄ー ̄),(^~^)") ("sword" "╰(◕ヮ◕)つ¤=[]———,╰(⇀︿⇀)つ-]═───,∩(˵☯‿☯˵)つ¤=[]:::::>") ("wink" "ヾ(^∇^),ヾ(☆▽☆),(。-ω-)ノ,( ・ω・)ノ"))) (names (string-join (map car emotions) ","))) (and (weechat:config_set_plugin "emotions" names) (for-each (lambda (emo) (weechat:config_set_plugin (car emo) (cadr emo))) emotions)))) ; -> Weechat-Return ; Function to be called when the plugin is unloaded. Will hopefully clean ; up all settings. (define (clean-up) (for-each weechat:config_unset_plugin (emotion-categories)) (weechat:config_unset_plugin "emotions") weechat:WEECHAT_RC_OK) (weechat:register "weechataboo" "Alvar" "0.1.2" "GPL3" "Replace emotion-tags with random emoticons" "clean-up" "") (and (eq? (weechat:config_is_set_plugin "emotions") 0) (initial-setup)) (weechat:hook_modifier "irc_out1_privmsg" "weechataboo-hook" "") (weechat:hook_command "weechataboo" (string-append "This script automatically replaces written emotion-keywords\n" "with a random emoticon from a list of matching ones. The\n" "keyword must have two tildes (~~) as a prefix.\n" "Example: ~~wink\n\n" "All values are comma separated. Please make sure that every\n" "emotion in the `emotions`-list has its own entry!\n\n" "→ Keywords: /set plugins.var.guile.weechataboo.emotions\n" "→ Emoticons: /set plugins.var.guile.weechataboo.$EMOTION\n") "" "" "" "weechataboo-func" "") weechat-scripts-20191009/javascript/000077500000000000000000000000001354740107000172355ustar00rootroot00000000000000weechat-scripts-20191009/javascript/autospurdo.js000066400000000000000000000071441354740107000220060ustar00rootroot00000000000000/* +Copyright (c) 2015 by installgen2 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty ofh +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see +*/ weechat.register("autospurdo", "installgen2", "1.0", "GPL3", "Speak in spurdo", "", ""); weechat.hook_command("spurdosay", "Say message in spurdo", "", "", "", "spurdoSay", ""); weechat.hook_command("togglespurdo", "Toggle automatic spurdo conversion", "", "", "", "toggleSpurdo", ""); weechat.hook_command_run("/input return", "spurdoModifier", ""); function spurdoSay (data, buffer, args) { var message = toSpurdo(args); weechat.command("", "/say " + message) return weechat.WEECHAT_RC_OK; } var spurdoEnabled = false; function spurdoModifier (data, buffer, command) { if (!spurdoEnabled || command != "/input return") return weechat.WEECHAT_RC_OK; text = weechat.buffer_get_string(buffer, "input"); if (text[0] == "/") return weechat.WEECHAT_RC_OK; weechat.buffer_set(buffer, "input", toSpurdo(text)) return weechat.WEECHAT_RC_OK; } function toggleSpurdo (data, buffer, args) { if (spurdoEnabled) { spurdoEnabled = false; weechat.print("", "Disabled automatic spurdo"); } else { spurdoEnabled = true; weechat.print("", "Enabled automatic spurdo"); } return weechat.WEECHAT_RC_OK; } // The following shit is from https://github.com/installgen2/libspurdo // Return a random ebin face var ebinFaces = [":D", ":DD", ":DDD", ":-D", ":-DD", "XD", "XXD", "XDD", "XXDD"]; function getEbinFace () { return ebinFaces[Math.floor(Math.random() * ebinFaces.length)]; } // define replacements var replacements = [ ["wh", "w"], ["th", "d"], ["af", "ab"], ["ap", "ab"], ["ca", "ga"], ["ck", "gg"], ["co", "go"], ["ev", "eb"], ["ex", "egz"], ["et", "ed"], ["iv", "ib"], ["it", "id"], ["ke", "ge"], ["nt", "nd"], ["op", "ob"], ["ot", "od"], ["po", "bo"], ["pe", "be"], ["pi", "bi"], ["up", "ub"], ["va", "ba"], ["ck", "gg"], ["cr", "gr"], ["kn", "gn"], ["lt", "ld"], ["mm", "m"], ["nt", "dn"], ["pr", "br"], ["ts", "dz"], ["tr", "dr"], ["bs", "bz"], ["ds", "dz"], ["es", "es"], ["fs", "fz"], ["gs", "gz"], [" is", " iz"], ["ls", "lz"], ["ms", "mz"], ["ns", "nz"], ["rs", "rz"], ["ss", "sz"], ["ts", "tz"], ["us", "uz"], ["ws", "wz"], ["ys", "yz"], ["alk", "olk"], ["ing", "ign"], ["ic", "ig"], ["ng", "nk"], ["kek", "geg"], ["epic", "ebin"], ["some", "sum"], ["meme", "maymay"], ]; function toSpurdo (string) { // Convert to lowercase (TODO: add upercase handling) string = string.toLowerCase(); // apply replacements replacements.forEach(function(filter) { var replaceFrom = new RegExp(filter[0], "gm"), replaceTo = filter[1]; string = string.replace(replaceFrom, replaceTo); }); // Replace "," and "." with ebin faces while (string.match(/\.|,(?=\s|$)/m)) { string = string.replace(/\.|,(?=\s|$)/m, " " + getEbinFace()); } // append an ebin face if not found var ebinFaceFound = false; ebinFaces.forEach(function (face) { if (string.indexOf(face) != -1) { ebinFaceFound = true; } }); if (!ebinFaceFound) { string += " " + getEbinFace(); } // return spurdo'd text return string; } weechat-scripts-20191009/javascript/opall.js000066400000000000000000000037021354740107000207040ustar00rootroot00000000000000name = "opall"; author = "gagz@riseup.net"; version = "0.2"; license = "wtfpl"; description = "op people using chanserv instead of /mode"; shutdown_function = ""; charset = ""; weechat.register(name, author, version, license, description, shutdown_function, charset); weechat.hook_command("opall", "OP everybody on the channel, using chanserv instead of /mode", "", "", "", "chanserv_op_all", ""); function chanserv_op_all() { var buffer = weechat.current_buffer() var chan = weechat.buffer_get_string(buffer, "localvar_channel") // we must be sure to be on an IRC buffer if( weechat.buffer_get_string(buffer, "plugin") != "irc" ) { weechat.print("", "Works only on IRC channels") return weechat.WEECHAT_RC_ERROR } // lets get the nicklist of the current buffer var nicklist = weechat.infolist_get("nicklist", buffer, ""); // and walk through it while( weechat.infolist_next(nicklist) ) { var type = weechat.infolist_string(nicklist, "type"); var visible = weechat.infolist_integer(nicklist, "visible"); var prefix = weechat.infolist_string(nicklist, "prefix"); // we are only interested in actual non-op visible nicks // TODO: find a more reliable way to op non-op users (ie. prefix // can be changed in the settings and might not be "@") // TODO: check the IRC server/services version to talk with // chanserv correctly. This works with charybdis/atheme. if( type == "nick" && visible == 1 && prefix != "@") { var nick = weechat.infolist_string(nicklist, "name"); var command = "/msg chanserv op " + chan + " " + nick; weechat.print("", command); weechat.command(buffer, command); } } weechat.infolist_free(nicklist); return weechat.WEECHAT_RC_OK; } weechat-scripts-20191009/lua/000077500000000000000000000000001354740107000156505ustar00rootroot00000000000000weechat-scripts-20191009/lua/emoji.lua000066400000000000000000001114361354740107000174640ustar00rootroot00000000000000-- Copyright 2016 xt -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- --[[ Emoji output/input shortcode helper for WeeChat. Usage: Type :emojiname: from http://www.emoji-cheat-sheet.com/ or :partial match Changelog: version 4, 2017-10-12, massa1240 * add support of :+1: and :-1: version 3, 2016-11-04, xt * add a slack specific shortcode version 2, 2016-10-31, xt * some cleanup * ability replace incoming version 1, 2016-02-29, xt * initial version EMOJI CONVERSION SCRIPT: import json e = json.loads(open('emoji.json').read()) print "emoji = {" emojis = [] for k, v in e.items(): shortname = v['shortname'].strip(':') ubytes = [] cps = v['unicode'].split('-') for c in cps: ubytes.append(unichr(int(c, 16))) if shortname in ['end', 'repeat']: shortname = '["%s"]' %shortname elif '-' in shortname: shortname = '["%s"]' %shortname elif shortname[0].isdigit(): shortname = '["%s"]' %shortname else: try: shortname = int(shortname) shortname = '["%s"]' %shortname except: pass emojis.append((shortname+'="'+u"".join(ubytes)+'",').encode('UTF-8')) print "".join(emojis) print "}" --]] local SCRIPT_NAME = "emoji" local SCRIPT_AUTHOR = "xt " local SCRIPT_VERSION = "4" local SCRIPT_LICENSE = "GPL3" local SCRIPT_DESC = "Emoji output helper" -- luacheck: ignore weechat local w = weechat local emoji = { four="4⃣",kiss_ww="👩❤💋👩",maple_leaf="🍁",waxing_gibbous_moon="🌔",bike="🚲",recycle="♻",family_mwgb="👨👩👧👦",flag_dk="🇩🇰",thought_balloon="💭",oncoming_automobile="🚘",guardsman_tone5="💂🏿",tickets="🎟",school="🏫",house_abandoned="🏚",blue_book="📘",video_game="🎮",triumph="😤",suspension_railway="🚟",umbrella="☔",levitate="🕴",cactus="🌵",monorail="🚝",stars="🌠",new="🆕",herb="🌿",pouting_cat="😾",blue_heart="💙",["100"]="💯",leaves="🍃",family_mwbb="👨👩👦👦",information_desk_person_tone2="💁🏼",dragon_face="🐲",track_next="⏭",cloud_snow="🌨",flag_jp="🇯🇵",children_crossing="🚸",information_desk_person_tone1="💁🏻",arrow_up_down="↕",mount_fuji="🗻",massage_tone1="💆🏻",flag_mq="🇲🇶",massage_tone3="💆🏽",massage_tone2="💆🏼",massage_tone5="💆🏿",flag_je="🇯🇪",flag_jm="🇯🇲",flag_jo="🇯🇴",red_car="🚗",hospital="🏥",red_circle="🔴",princess="👸",tm="™",curly_loop="➰",boy_tone5="👦🏿",pouch="👝",boy_tone3="👦🏽",boy_tone1="👦🏻",izakaya_lantern="🏮",fist_tone5="✊🏿",fist_tone4="✊🏾",fist_tone1="✊🏻",fist_tone3="✊🏽",fist_tone2="✊🏼",arrow_lower_left="↙",game_die="🎲",pushpin="📌",dividers="🗂",dolphin="🐬",night_with_stars="🌃",cruise_ship="🛳",white_medium_small_square="◽",kissing_closed_eyes="😚",earth_americas="🌎",["end"]="🔚",mouse="🐭",rewind="⏪",beach="🏖",pizza="🍕",briefcase="💼",customs="🛃",heartpulse="💗",sparkler="🎇",sparkles="✨",hand_splayed_tone1="🖐🏻",snowman2="☃",tulip="🌷",speaking_head="🗣",ambulance="🚑",office="🏢",clapper="🎬",keyboard="⌨",japan="🗾",post_office="🏣",dizzy_face="😵",imp="👿",flag_ve="🇻🇪",coffee="☕",flag_vg="🇻🇬",flag_va="🇻🇦",flag_vc="🇻🇨",flag_vn="🇻🇳",flag_vi="🇻🇮",open_mouth="😮",flag_vu="🇻🇺",page_with_curl="📃",bank="🏦",bread="🍞",oncoming_police_car="🚔",capricorn="♑",point_left="👈",tokyo_tower="🗼",fishing_pole_and_fish="🎣",thumbsdown="👎",telescope="🔭",spider="🕷",u7121="🈚",camera_with_flash="📸",lifter="🏋",sweet_potato="🍠",lock_with_ink_pen="🔏",ok_woman_tone2="🙆🏼",ok_woman_tone3="🙆🏽",smirk="😏",baggage_claim="🛄",cherry_blossom="🌸",sparkle="❇",zap="⚡",construction_site="🏗",dancers="👯",flower_playing_cards="🎴",hatching_chick="🐣",free="🆓",bullettrain_side="🚄",poultry_leg="🍗",grapes="🍇",smirk_cat="😼",lollipop="🍭",water_buffalo="🐃",black_medium_small_square="◾",atm="🏧",gift_heart="💝",older_woman_tone5="👵🏿",older_woman_tone4="👵🏾",older_woman_tone1="👵🏻",older_woman_tone3="👵🏽",older_woman_tone2="👵🏼",scissors="✂",woman_tone2="👩🏼",basketball="🏀",hammer_pick="⚒",top="🔝",clock630="🕡",raising_hand_tone5="🙋🏿",railway_track="🛤",nail_care="💅",crossed_flags="🎌",minibus="🚐",white_sun_cloud="🌥",shower="🚿",smile_cat="😸",dog2="🐕",loud_sound="🔊",kaaba="🕋",runner="🏃",ram="🐏",writing_hand="✍",rat="🐀",rice_scene="🎑",milky_way="🌌",vulcan_tone5="🖖🏿",necktie="👔",kissing_cat="😽",snowflake="❄",paintbrush="🖌",crystal_ball="🔮",mountain_bicyclist_tone4="🚵🏾",mountain_bicyclist_tone3="🚵🏽",mountain_bicyclist_tone2="🚵🏼",mountain_bicyclist_tone1="🚵🏻",koko="🈁",flag_it="🇮🇹",flag_iq="🇮🇶",flag_is="🇮🇸",flag_ir="🇮🇷",flag_im="🇮🇲",flag_il="🇮🇱",flag_io="🇮🇴",flag_in="🇮🇳",flag_ie="🇮🇪",flag_id="🇮🇩",flag_ic="🇮🇨",ballot_box_with_check="☑",mountain_bicyclist_tone5="🚵🏿",metal="🤘",dog="🐶",pineapple="🍍",no_good_tone3="🙅🏽",no_good_tone2="🙅🏼",no_good_tone1="🙅🏻",scream="😱",no_good_tone5="🙅🏿",no_good_tone4="🙅🏾",flag_ua="🇺🇦",bomb="💣",flag_ug="🇺🇬",flag_um="🇺🇲",flag_us="🇺🇸",construction_worker_tone1="👷🏻",radio="📻",flag_uy="🇺🇾",flag_uz="🇺🇿",person_with_blond_hair_tone1="👱🏻",cupid="💘",mens="🚹",rice="🍚",point_right_tone1="👉🏻",point_right_tone3="👉🏽",point_right_tone2="👉🏼",sunglasses="😎",point_right_tone4="👉🏾",watch="⌚",frowning="😦",watermelon="🍉",wedding="💒",person_frowning_tone4="🙍🏾",person_frowning_tone5="🙍🏿",person_frowning_tone2="🙍🏼",person_frowning_tone3="🙍🏽",person_frowning_tone1="🙍🏻",flag_gw="🇬🇼",flag_gu="🇬🇺",flag_gt="🇬🇹",flag_gs="🇬🇸",flag_gr="🇬🇷",flag_gq="🇬🇶",flag_gp="🇬🇵",flag_gy="🇬🇾",flag_gg="🇬🇬",flag_gf="🇬🇫",microscope="🔬",flag_gd="🇬🇩",flag_gb="🇬🇧",flag_ga="🇬🇦",flag_gn="🇬🇳",flag_gm="🇬🇲",flag_gl="🇬🇱",japanese_ogre="👹",flag_gi="🇬🇮",flag_gh="🇬🇭",man_with_turban="👳",star_and_crescent="☪",writing_hand_tone3="✍🏽",dromedary_camel="🐪",hash="#⃣",hammer="🔨",hourglass="⌛",postbox="📮",writing_hand_tone5="✍🏿",writing_hand_tone4="✍🏾",wc="🚾",aquarius="♒",couple_with_heart="💑",ok_woman="🙆",raised_hands_tone4="🙌🏾",cop="👮",raised_hands_tone1="🙌🏻",cow="🐮",raised_hands_tone3="🙌🏽",white_large_square="⬜",pig_nose="🐽",ice_skate="⛸",hotsprings="♨",tone5="🏿",three="3⃣",beer="🍺",stadium="🏟",airplane_departure="🛫",heavy_division_sign="➗",flag_black="🏴",mushroom="🍄",record_button="⏺",vulcan="🖖",dash="💨",wind_chime="🎐",anchor="⚓",seven="7⃣",flag_hr="🇭🇷",roller_coaster="🎢",pen_ballpoint="🖊",sushi="🍣",flag_ht="🇭🇹",flag_hu="🇭🇺",flag_hk="🇭🇰",dizzy="💫",flag_hn="🇭🇳",flag_hm="🇭🇲",arrow_forward="▶",violin="🎻",orthodox_cross="☦",id="🆔",heart_decoration="💟",first_quarter_moon="🌓",satellite="📡",tone3="🏽",christmas_tree="🎄",unicorn="🦄",broken_heart="💔",ocean="🌊",hearts="♥",snowman="⛄",person_with_blond_hair_tone4="👱🏾",person_with_blond_hair_tone5="👱🏿",person_with_blond_hair_tone2="👱🏼",person_with_blond_hair_tone3="👱🏽",yen="💴",straight_ruler="📏",sleepy="😪",green_apple="🍏",white_medium_square="◻",flag_fr="🇫🇷",grey_exclamation="❕",innocent="😇",flag_fm="🇫🇲",flag_fo="🇫🇴",flag_fi="🇫🇮",flag_fj="🇫🇯",flag_fk="🇫🇰",menorah="🕎",yin_yang="☯",clock130="🕜",gift="🎁",prayer_beads="📿",stuck_out_tongue="😛",om_symbol="🕉",city_dusk="🌆",massage_tone4="💆🏾",couple_ww="👩❤👩",crown="👑",sparkling_heart="💖",clubs="♣",person_with_pouting_face="🙎",newspaper2="🗞",fog="🌫",dango="🍡",large_orange_diamond="🔶",flag_tn="🇹🇳",flag_to="🇹🇴",point_up="☝",flag_tm="🇹🇲",flag_tj="🇹🇯",flag_tk="🇹🇰",flag_th="🇹🇭",flag_tf="🇹🇫",flag_tg="🇹🇬",corn="🌽",flag_tc="🇹🇨",flag_ta="🇹🇦",flag_tz="🇹🇿",flag_tv="🇹🇻",flag_tw="🇹🇼",flag_tt="🇹🇹",flag_tr="🇹🇷",eight_spoked_asterisk="✳",trophy="🏆",black_small_square="▪",o="⭕",no_bell="🔕",curry="🍛",alembic="⚗",sob="😭",waxing_crescent_moon="🌒",tiger2="🐅",two="2⃣",sos="🆘",compression="🗜",heavy_multiplication_x="✖",tennis="🎾",fireworks="🎆",skull_crossbones="☠",astonished="😲",congratulations="㊗",grey_question="❔",arrow_upper_left="↖",arrow_double_up="⏫",triangular_flag_on_post="🚩",gemini="♊",door="🚪",ship="🚢",point_down_tone3="👇🏽",point_down_tone4="👇🏾",point_down_tone5="👇🏿",movie_camera="🎥",ng="🆖",couple_mm="👨❤👨",football="🏈",asterisk="*⃣",taurus="♉",articulated_lorry="🚛",police_car="🚓",flushed="😳",spades="♠",cloud_lightning="🌩",wine_glass="🍷",clock830="🕣",punch_tone2="👊🏼",punch_tone3="👊🏽",punch_tone1="👊🏻",department_store="🏬",punch_tone4="👊🏾",punch_tone5="👊🏿",crocodile="🐊",white_square_button="🔳",hole="🕳",boy_tone2="👦🏼",mountain_cableway="🚠",melon="🍈",persevere="😣",trident="🔱",head_bandage="🤕",u7a7a="🈳",cool="🆒",high_brightness="🔆",deciduous_tree="🌳",white_flower="💮",gun="🔫",flag_sk="🇸🇰",flag_sj="🇸🇯",flag_si="🇸🇮",flag_sh="🇸🇭",flag_so="🇸🇴",flag_sn="🇸🇳",flag_sm="🇸🇲",flag_sl="🇸🇱",flag_sc="🇸🇨",flag_sb="🇸🇧",flag_sa="🇸🇦",flag_sg="🇸🇬",flag_tl="🇹🇱",flag_se="🇸🇪",arrow_left="⬅",flag_sz="🇸🇿",flag_sy="🇸🇾",small_orange_diamond="🔸",flag_ss="🇸🇸",flag_sr="🇸🇷",flag_sv="🇸🇻",flag_st="🇸🇹",file_folder="📁",flag_td="🇹🇩",["1234"]="🔢",smiling_imp="😈",surfer_tone2="🏄🏼",surfer_tone3="🏄🏽",surfer_tone4="🏄🏾",surfer_tone5="🏄🏿",amphora="🏺",baseball="⚾",boy="👦",flag_es="🇪🇸",raised_hands="🙌",flag_eu="🇪🇺",flag_et="🇪🇹",heavy_plus_sign="➕",bow="🙇",flag_ea="🇪🇦",flag_ec="🇪🇨",flag_ee="🇪🇪",light_rail="🚈",flag_eg="🇪🇬",flag_eh="🇪🇭",massage="💆",man_with_gua_pi_mao_tone4="👲🏾",man_with_gua_pi_mao_tone3="👲🏽",outbox_tray="📤",clock330="🕞",projector="📽",sake="🍶",confounded="😖",angry="😠",iphone="📱",sweat_smile="😅",aries="♈",ear_of_rice="🌾",mouse2="🐁",bicyclist_tone4="🚴🏾",bicyclist_tone5="🚴🏿",guardsman="💂",bicyclist_tone1="🚴🏻",bicyclist_tone2="🚴🏼",bicyclist_tone3="🚴🏽",envelope="✉",money_with_wings="💸",beers="🍻",heart_exclamation="❣",notepad_spiral="🗒",cat="🐱",running_shirt_with_sash="🎽",ferry="⛴",spy="🕵",chart_with_upwards_trend="📈",green_heart="💚",confused="😕",angel_tone4="👼🏾",scorpius="♏",sailboat="⛵",elephant="🐘",map="🗺",disappointed_relieved="😥",flag_xk="🇽🇰",motorway="🛣",sun_with_face="🌞",birthday="🎂",mag="🔍",date="📅",dove="🕊",man="👨",octopus="🐙",wheelchair="♿",truck="🚚",sa="🈂",shield="🛡",haircut="💇",last_quarter_moon_with_face="🌜",rosette="🏵",currency_exchange="💱",mailbox_with_no_mail="📭",bath="🛀",clock930="🕤",bowling="🎳",turtle="🐢",pause_button="⏸",construction_worker="👷",unlock="🔓",anger_right="🗯",beetle="🐞",girl="👧",sunrise="🌅",exclamation="❗",flag_dz="🇩🇿",family_mmgg="👨👨👧👧",factory="🏭",flag_do="🇩🇴",flag_dm="🇩🇲",flag_dj="🇩🇯",mouse_three_button="🖱",flag_dg="🇩🇬",flag_de="🇩🇪",star_of_david="✡",reminder_ribbon="🎗",grimacing="😬",thumbsup_tone3="👍🏽",thumbsup_tone2="👍🏼",thumbsup_tone1="👍🏻",musical_note="🎵",thumbsup_tone5="👍🏿",thumbsup_tone4="👍🏾",high_heel="👠",green_book="📗",headphones="🎧",flag_aw="🇦🇼",stop_button="⏹",yum="😋",flag_aq="🇦🇶",warning="⚠",cheese="🧀",ophiuchus="⛎",revolving_hearts="💞",one="1⃣",ring="💍",point_right="👉",sheep="🐑",bookmark="🔖",spider_web="🕸",eyes="👀",flag_ro="🇷🇴",flag_re="🇷🇪",flag_rs="🇷🇸",sweat_drops="💦",flag_ru="🇷🇺",flag_rw="🇷🇼",middle_finger="🖕",race_car="🏎",evergreen_tree="🌲",biohazard="☣",girl_tone3="👧🏽",scream_cat="🙀",computer="💻",hourglass_flowing_sand="⏳",flag_lb="🇱🇧",tophat="🎩",clock1230="🕧",tractor="🚜",u6709="🈶",u6708="🈷",crying_cat_face="😿",angel="👼",ant="🐜",information_desk_person="💁",anger="💢",mailbox_with_mail="📬",pencil2="✏",wink="😉",thermometer="🌡",relaxed="☺",printer="🖨",credit_card="💳",checkered_flag="🏁",family_mmg="👨👨👧",pager="📟",family_mmb="👨👨👦",radioactive="☢",fried_shrimp="🍤",link="🔗",walking="🚶",city_sunset="🌇",shopping_bags="🛍",hockey="🏒",arrow_up="⬆",gem="💎",negative_squared_cross_mark="❎",worried="😟",walking_tone5="🚶🏿",walking_tone1="🚶🏻",hear_no_evil="🙉",convenience_store="🏪",seat="💺",girl_tone1="👧🏻",cloud_rain="🌧",girl_tone2="👧🏼",girl_tone5="👧🏿",girl_tone4="👧🏾",parking="🅿",pisces="♓",calendar="📆",loudspeaker="📢",camping="🏕",bicyclist="🚴",label="🏷",diamonds="♦",older_man_tone1="👴🏻",older_man_tone3="👴🏽",older_man_tone2="👴🏼",older_man_tone5="👴🏿",older_man_tone4="👴🏾",microphone2="🎙",raising_hand="🙋",hot_pepper="🌶",guitar="🎸",tropical_drink="🍹",upside_down="🙃",restroom="🚻",pen_fountain="🖋",comet="☄",cancer="♋",jeans="👖",flag_qa="🇶🇦",boar="🐗",turkey="🦃",person_with_blond_hair="👱",oden="🍢",stuck_out_tongue_closed_eyes="😝",helicopter="🚁",control_knobs="🎛",performing_arts="🎭",tiger="🐯",foggy="🌁",sound="🔉",flag_cz="🇨🇿",flag_cy="🇨🇾",flag_cx="🇨🇽",speech_balloon="💬",seedling="🌱",flag_cr="🇨🇷",envelope_with_arrow="📩",flag_cp="🇨🇵",flag_cw="🇨🇼",flag_cv="🇨🇻",flag_cu="🇨🇺",flag_ck="🇨🇰",flag_ci="🇨🇮",flag_ch="🇨🇭",flag_co="🇨🇴",flag_cn="🇨🇳",flag_cm="🇨🇲",u5408="🈴",flag_cc="🇨🇨",flag_ca="🇨🇦",flag_cg="🇨🇬",flag_cf="🇨🇫",flag_cd="🇨🇩",purse="👛",telephone="☎",sleeping="😴",point_down_tone1="👇🏻",frowning2="☹",point_down_tone2="👇🏼",muscle_tone4="💪🏾",muscle_tone5="💪🏿",synagogue="🕍",muscle_tone1="💪🏻",muscle_tone2="💪🏼",muscle_tone3="💪🏽",clap_tone5="👏🏿",clap_tone4="👏🏾",clap_tone1="👏🏻",train2="🚆",clap_tone2="👏🏼",oil="🛢",diamond_shape_with_a_dot_inside="💠",barber="💈",metal_tone3="🤘🏽",ice_cream="🍨",rowboat_tone4="🚣🏾",burrito="🌯",metal_tone1="🤘🏻",joystick="🕹",rowboat_tone1="🚣🏻",taxi="🚕",u7533="🈸",racehorse="🐎",snowboarder="🏂",thinking="🤔",wave_tone1="👋🏻",wave_tone2="👋🏼",wave_tone3="👋🏽",wave_tone4="👋🏾",wave_tone5="👋🏿",desktop="🖥",stopwatch="⏱",pill="💊",skier="⛷",orange_book="📙",dart="🎯",disappointed="😞",grin="😁",place_of_worship="🛐",japanese_goblin="👺",arrows_counterclockwise="🔄",laughing="😆",clap="👏",left_right_arrow="↔",japanese_castle="🏯",nail_care_tone4="💅🏾",nail_care_tone5="💅🏿",nail_care_tone2="💅🏼",nail_care_tone3="💅🏽",nail_care_tone1="💅🏻",raised_hand_tone4="✋🏾",raised_hand_tone5="✋🏿",raised_hand_tone1="✋🏻",raised_hand_tone2="✋🏼",raised_hand_tone3="✋🏽",point_left_tone3="👈🏽",point_left_tone2="👈🏼",tanabata_tree="🎋",point_left_tone5="👈🏿",point_left_tone4="👈🏾",o2="🅾",knife="🔪",volcano="🌋",kissing_heart="😘",on="🔛",ok="🆗",package="📦",island="🏝",arrow_right="➡",chart_with_downwards_trend="📉",haircut_tone3="💇🏽",wolf="🐺",ox="🐂",dagger="🗡",full_moon_with_face="🌝",syringe="💉",flag_by="🇧🇾",flag_bz="🇧🇿",flag_bq="🇧🇶",flag_br="🇧🇷",flag_bs="🇧🇸",flag_bt="🇧🇹",flag_bv="🇧🇻",flag_bw="🇧🇼",flag_bh="🇧🇭",flag_bi="🇧🇮",flag_bj="🇧🇯",flag_bl="🇧🇱",flag_bm="🇧🇲",flag_bn="🇧🇳",flag_bo="🇧🇴",flag_ba="🇧🇦",flag_bb="🇧🇧",flag_bd="🇧🇩",flag_be="🇧🇪",flag_bf="🇧🇫",flag_bg="🇧🇬",satellite_orbital="🛰",radio_button="🔘",arrow_heading_down="⤵",rage="😡",whale2="🐋",vhs="📼",hand_splayed_tone3="🖐🏽",strawberry="🍓",["non-potable_water"]="🚱",hand_splayed_tone5="🖐🏿",star2="🌟",toilet="🚽",ab="🆎",cinema="🎦",floppy_disk="💾",princess_tone4="👸🏾",princess_tone5="👸🏿",princess_tone2="👸🏼",nerd="🤓",telephone_receiver="📞",princess_tone1="👸🏻",arrow_double_down="⏬",clock1030="🕥",flag_pr="🇵🇷",flag_ps="🇵🇸",poop="💩",flag_pw="🇵🇼",flag_pt="🇵🇹",flag_py="🇵🇾",pear="🍐",m="Ⓜ",flag_pa="🇵🇦",flag_pf="🇵🇫",flag_pg="🇵🇬",flag_pe="🇵🇪",flag_pk="🇵🇰",flag_ph="🇵🇭",flag_pn="🇵🇳",flag_pl="🇵🇱",flag_pm="🇵🇲",mask="😷",hushed="😯",sunrise_over_mountains="🌄",partly_sunny="⛅",dollar="💵",helmet_with_cross="⛑",smoking="🚬",no_bicycles="🚳",man_with_gua_pi_mao="👲",tv="📺",open_hands="👐",rotating_light="🚨",information_desk_person_tone4="💁🏾",information_desk_person_tone5="💁🏿",part_alternation_mark="〽",pray_tone5="🙏🏿",pray_tone4="🙏🏾",pray_tone3="🙏🏽",pray_tone2="🙏🏼",pray_tone1="🙏🏻",smile="😄",large_blue_circle="🔵",man_tone4="👨🏾",man_tone5="👨🏿",fax="📠",woman="👩",man_tone1="👨🏻",man_tone2="👨🏼",man_tone3="👨🏽",eye_in_speech_bubble="👁🗨",blowfish="🐡",card_box="🗃",ticket="🎫",ramen="🍜",twisted_rightwards_arrows="🔀",swimmer_tone4="🏊🏾",swimmer_tone5="🏊🏿",swimmer_tone1="🏊🏻",swimmer_tone2="🏊🏼",swimmer_tone3="🏊🏽",saxophone="🎷",bath_tone1="🛀🏻",notebook_with_decorative_cover="📔",bath_tone3="🛀🏽",ten="🔟",raising_hand_tone4="🙋🏾",tea="🍵",raising_hand_tone1="🙋🏻",raising_hand_tone2="🙋🏼",raising_hand_tone3="🙋🏽",zero="0⃣",ribbon="🎀",santa_tone1="🎅🏻",abc="🔤",clock="🕰",purple_heart="💜",bow_tone1="🙇🏻",no_smoking="🚭",flag_cl="🇨🇱",surfer="🏄",newspaper="📰",busstop="🚏",new_moon="🌑",traffic_light="🚥",thumbsup="👍",no_entry="⛔",name_badge="📛",classical_building="🏛",hamster="🐹",pick="⛏",two_women_holding_hands="👭",family_mmbb="👨👨👦👦",family="👪",rice_cracker="🍘",wind_blowing_face="🌬",inbox_tray="📥",tired_face="😫",carousel_horse="🎠",eye="👁",poodle="🐩",chestnut="🌰",slight_smile="🙂",mailbox_closed="📪",cloud_tornado="🌪",jack_o_lantern="🎃",lifter_tone3="🏋🏽",lifter_tone2="🏋🏼",lifter_tone1="🏋🏻",lifter_tone5="🏋🏿",lifter_tone4="🏋🏾",nine="9⃣",chocolate_bar="🍫",v="✌",man_with_turban_tone4="👳🏾",man_with_turban_tone5="👳🏿",man_with_turban_tone2="👳🏼",man_with_turban_tone3="👳🏽",man_with_turban_tone1="👳🏻",family_wwbb="👩👩👦👦",hamburger="🍔",accept="🉑",airplane="✈",dress="👗",speedboat="🚤",ledger="📒",goat="🐐",flag_ae="🇦🇪",flag_ad="🇦🇩",flag_ag="🇦🇬",flag_af="🇦🇫",flag_ac="🇦🇨",flag_am="🇦🇲",flag_al="🇦🇱",flag_ao="🇦🇴",flag_ai="🇦🇮",flag_au="🇦🇺",flag_at="🇦🇹",fork_and_knife="🍴",fast_forward="⏩",flag_as="🇦🇸",flag_ar="🇦🇷",cow2="🐄",flag_ax="🇦🇽",flag_az="🇦🇿",a="🅰",volleyball="🏐",dragon="🐉",wrench="🔧",point_up_2="👆",egg="🍳",small_red_triangle="🔺",soon="🔜",bow_tone4="🙇🏾",joy_cat="😹",pray="🙏",dark_sunglasses="🕶",rugby_football="🏉",soccer="⚽",dolls="🎎",monkey_face="🐵",clap_tone3="👏🏽",bar_chart="📊",european_castle="🏰",military_medal="🎖",frame_photo="🖼",rice_ball="🍙",trolleybus="🚎",older_woman="👵",information_source="ℹ",postal_horn="📯",house="🏠",fish="🐟",bride_with_veil="👰",fist="✊",lipstick="💄",fountain="⛲",cyclone="🌀",thumbsdown_tone2="👎🏼",thumbsdown_tone3="👎🏽",thumbsdown_tone1="👎🏻",thumbsdown_tone4="👎🏾",thumbsdown_tone5="👎🏿",cookie="🍪",heartbeat="💓",blush="😊",fire_engine="🚒",feet="🐾",horse="🐴",blossom="🌼",crossed_swords="⚔",station="🚉",clock730="🕢",banana="🍌",relieved="😌",hotel="🏨",park="🏞",aerial_tramway="🚡",flag_sd="🇸🇩",panda_face="🐼",b="🅱",flag_sx="🇸🇽",six_pointed_star="🔯",shaved_ice="🍧",chipmunk="🐿",mountain="⛰",koala="🐨",white_small_square="▫",open_hands_tone2="👐🏼",open_hands_tone3="👐🏽",u55b6="🈺",open_hands_tone1="👐🏻",open_hands_tone4="👐🏾",open_hands_tone5="👐🏿",baby_tone5="👶🏿",baby_tone4="👶🏾",baby_tone3="👶🏽",baby_tone2="👶🏼",baby_tone1="👶🏻",chart="💹",beach_umbrella="⛱",basketball_player_tone5="⛹🏿",basketball_player_tone4="⛹🏾",basketball_player_tone1="⛹🏻",basketball_player_tone3="⛹🏽",basketball_player_tone2="⛹🏼",mans_shoe="👞",shinto_shrine="⛩",ideograph_advantage="🉐",airplane_arriving="🛬",golf="⛳",minidisc="💽",hugging="🤗",crayon="🖍",point_down="👇",copyright="©",person_with_pouting_face_tone2="🙎🏼",person_with_pouting_face_tone3="🙎🏽",person_with_pouting_face_tone1="🙎🏻",person_with_pouting_face_tone4="🙎🏾",person_with_pouting_face_tone5="🙎🏿",busts_in_silhouette="👥",alarm_clock="⏰",couplekiss="💏",circus_tent="🎪",sunny="☀",incoming_envelope="📨",yellow_heart="💛",cry="😢",x="❌",arrow_up_small="🔼",art="🎨",surfer_tone1="🏄🏻",bride_with_veil_tone4="👰🏾",bride_with_veil_tone5="👰🏿",bride_with_veil_tone2="👰🏼",bride_with_veil_tone3="👰🏽",bride_with_veil_tone1="👰🏻",hibiscus="🌺",black_joker="🃏",raised_hand="✋",no_mouth="😶",basketball_player="⛹",champagne="🍾",no_entry_sign="🚫",older_man="👴",moyai="🗿",mailbox="📫",slight_frown="🙁",statue_of_liberty="🗽",mega="📣",eggplant="🍆",rose="🌹",bell="🔔",battery="🔋",wastebasket="🗑",dancer="💃",page_facing_up="📄",church="⛪",underage="🔞",secret="㊙",clock430="🕟",fork_knife_plate="🍽",u7981="🈲",fire="🔥",cold_sweat="😰",flag_er="🇪🇷",family_mwgg="👨👩👧👧",heart_eyes="😍",guardsman_tone1="💂🏻",guardsman_tone2="💂🏼",guardsman_tone3="💂🏽",guardsman_tone4="💂🏾",earth_africa="🌍",arrow_right_hook="↪",spy_tone2="🕵🏼",closed_umbrella="🌂",bikini="👙",vertical_traffic_light="🚦",kissing="😗",loop="➿",potable_water="🚰",pound="💷",["fleur-de-lis"]="⚜",key2="🗝",heavy_dollar_sign="💲",shamrock="☘",boy_tone4="👦🏾",shirt="👕",kimono="👘",left_luggage="🛅",meat_on_bone="🍖",ok_woman_tone4="🙆🏾",ok_woman_tone5="🙆🏿",arrow_heading_up="⤴",calendar_spiral="🗓",snail="🐌",ok_woman_tone1="🙆🏻",arrow_down_small="🔽",leopard="🐆",paperclips="🖇",cityscape="🏙",woman_tone1="👩🏻",slot_machine="🎰",woman_tone3="👩🏽",woman_tone4="👩🏾",woman_tone5="👩🏿",euro="💶",musical_score="🎼",triangular_ruler="📐",flags="🎏",five="5⃣",love_hotel="🏩",hotdog="🌭",speak_no_evil="🙊",eyeglasses="👓",dancer_tone4="💃🏾",dancer_tone5="💃🏿",vulcan_tone4="🖖🏾",bridge_at_night="🌉",writing_hand_tone1="✍🏻",couch="🛋",vulcan_tone1="🖖🏻",vulcan_tone2="🖖🏼",vulcan_tone3="🖖🏽",womans_hat="👒",sandal="👡",cherries="🍒",full_moon="🌕",flag_om="🇴🇲",play_pause="⏯",couple="👫",money_mouth="🤑",womans_clothes="👚",globe_with_meridians="🌐",bath_tone5="🛀🏿",bangbang="‼",stuck_out_tongue_winking_eye="😜",heart="❤",bamboo="🎍",mahjong="🀄",waning_gibbous_moon="🌖",back="🔙",point_up_2_tone4="👆🏾",point_up_2_tone5="👆🏿",lips="👄",point_up_2_tone1="👆🏻",point_up_2_tone2="👆🏼",point_up_2_tone3="👆🏽",candle="🕯",middle_finger_tone3="🖕🏽",middle_finger_tone2="🖕🏼",middle_finger_tone1="🖕🏻",middle_finger_tone5="🖕🏿",middle_finger_tone4="🖕🏾",heavy_minus_sign="➖",nose="👃",zzz="💤",stew="🍲",santa="🎅",tropical_fish="🐠",point_up_tone1="☝🏻",point_up_tone3="☝🏽",point_up_tone2="☝🏼",point_up_tone5="☝🏿",point_up_tone4="☝🏾",field_hockey="🏑",school_satchel="🎒",womens="🚺",baby_symbol="🚼",baby_chick="🐤",ok_hand_tone2="👌🏼",ok_hand_tone3="👌🏽",ok_hand_tone1="👌🏻",ok_hand_tone4="👌🏾",ok_hand_tone5="👌🏿",family_mmgb="👨👨👧👦",last_quarter_moon="🌗",tada="🎉",clock530="🕠",question="❓",registered="®",level_slider="🎚",black_circle="⚫",atom="⚛",penguin="🐧",electric_plug="🔌",skull="💀",kiss_mm="👨❤💋👨",walking_tone4="🚶🏾",fries="🍟",up="🆙",walking_tone3="🚶🏽",walking_tone2="🚶🏼",athletic_shoe="👟",hatched_chick="🐥",black_nib="✒",black_large_square="⬛",bow_and_arrow="🏹",rainbow="🌈",metal_tone5="🤘🏿",metal_tone4="🤘🏾",lemon="🍋",metal_tone2="🤘🏼",peach="🍑",peace="☮",steam_locomotive="🚂",oncoming_bus="🚍",heart_eyes_cat="😻",smiley="😃",haircut_tone1="💇🏻",haircut_tone2="💇🏼",u6e80="🈵",haircut_tone4="💇🏾",haircut_tone5="💇🏿",black_medium_square="◼",closed_book="📕",desert="🏜",expressionless="😑",dvd="📀",construction_worker_tone2="👷🏼",construction_worker_tone3="👷🏽",construction_worker_tone4="👷🏾",construction_worker_tone5="👷🏿",mag_right="🔎",bento="🍱",scroll="📜",flag_nl="🇳🇱",flag_no="🇳🇴",flag_ni="🇳🇮",european_post_office="🏤",flag_ne="🇳🇪",flag_nf="🇳🇫",flag_ng="🇳🇬",flag_na="🇳🇦",flag_nc="🇳🇨",alien="👽",first_quarter_moon_with_face="🌛",flag_nz="🇳🇿",flag_nu="🇳🇺",golfer="🏌",flag_np="🇳🇵",flag_nr="🇳🇷",anguished="😧",mosque="🕌",point_left_tone1="👈🏻",ear_tone1="👂🏻",ear_tone2="👂🏼",ear_tone3="👂🏽",ear_tone4="👂🏾",ear_tone5="👂🏿",eight_pointed_black_star="✴",wave="👋",runner_tone5="🏃🏿",runner_tone4="🏃🏾",runner_tone3="🏃🏽",runner_tone2="🏃🏼",runner_tone1="🏃🏻",railway_car="🚃",notes="🎶",no_good="🙅",trackball="🖲",spaghetti="🍝",love_letter="💌",clipboard="📋",baby_bottle="🍼",bird="🐦",card_index="📇",punch="👊",leo="♌",house_with_garden="🏡",family_wwgg="👩👩👧👧",family_wwgb="👩👩👧👦",see_no_evil="🙈",metro="🚇",popcorn="🍿",apple="🍎",scales="⚖",sleeping_accommodation="🛌",clock230="🕝",tools="🛠",cloud="☁",honey_pot="🍯",ballot_box="🗳",frog="🐸",camera="📷",crab="🦀",video_camera="📹",pencil="📝",thunder_cloud_rain="⛈",mountain_bicyclist="🚵",tangerine="🍊",train="🚋",rabbit="🐰",baby="👶",palm_tree="🌴",capital_abcd="🔠",put_litter_in_its_place="🚮",coffin="⚰",abcd="🔡",lock="🔒",pig2="🐖",family_mwg="👨👩👧",point_right_tone5="👉🏿",trumpet="🎺",film_frames="🎞",six="6⃣",leftwards_arrow_with_hook="↩",earth_asia="🌏",heavy_check_mark="✔",notebook="📓",taco="🌮",tomato="🍅",robot="🤖",mute="🔇",symbols="🔣",motorcycle="🏍",thermometer_face="🤒",paperclip="📎",moneybag="💰",neutral_face="😐",white_sun_rain_cloud="🌦",snake="🐍",kiss="💋",blue_car="🚙",confetti_ball="🎊",tram="🚊",repeat_one="🔂",smiley_cat="😺",beginner="🔰",mobile_phone_off="📴",books="📚",["8ball"]="🎱",cocktail="🍸",flag_ge="🇬🇪",horse_racing_tone2="🏇🏼",flag_mh="🇲🇭",flag_mk="🇲🇰",flag_mm="🇲🇲",flag_ml="🇲🇱",flag_mo="🇲🇴",flag_mn="🇲🇳",flag_ma="🇲🇦",flag_mc="🇲🇨",flag_me="🇲🇪",flag_md="🇲🇩",flag_mg="🇲🇬",flag_mf="🇲🇫",flag_my="🇲🇾",flag_mx="🇲🇽",flag_mz="🇲🇿",mountain_snow="🏔",flag_mp="🇲🇵",flag_ms="🇲🇸",flag_mr="🇲🇷",flag_mu="🇲🇺",flag_mt="🇲🇹",flag_mw="🇲🇼",flag_mv="🇲🇻",timer="⏲",passport_control="🛂",small_blue_diamond="🔹",lion_face="🦁",white_check_mark="✅",bouquet="💐",track_previous="⏮",monkey="🐒",tone4="🏾",closed_lock_with_key="🔐",family_wwb="👩👩👦",family_wwg="👩👩👧",tone1="🏻",crescent_moon="🌙",shell="🐚",gear="⚙",tone2="🏼",small_red_triangle_down="🔻",nut_and_bolt="🔩",umbrella2="☂",unamused="😒",fuelpump="⛽",bed="🛏",bee="🐝",round_pushpin="📍",flag_white="🏳",microphone="🎤",bus="🚌",eight="8⃣",handbag="👜",medal="🏅",arrows_clockwise="🔃",urn="⚱",bookmark_tabs="📑",new_moon_with_face="🌚",fallen_leaf="🍂",horse_racing="🏇",chicken="🐔",ear="👂",wheel_of_dharma="☸",arrow_lower_right="↘",man_with_gua_pi_mao_tone5="👲🏿",scorpion="🦂",waning_crescent_moon="🌘",man_with_gua_pi_mao_tone2="👲🏼",man_with_gua_pi_mao_tone1="👲🏻",bug="🐛",virgo="♍",libra="♎",angel_tone1="👼🏻",angel_tone3="👼🏽",angel_tone2="👼🏼",angel_tone5="👼🏿",sagittarius="♐",bear="🐻",information_desk_person_tone3="💁🏽",no_mobile_phones="📵",hand_splayed="🖐",motorboat="🛥",calling="📲",interrobang="⁉",oncoming_taxi="🚖",flag_lt="🇱🇹",flag_lu="🇱🇺",flag_lr="🇱🇷",flag_ls="🇱🇸",flag_ly="🇱🇾",bellhop="🛎",arrow_down="⬇",flag_lc="🇱🇨",flag_la="🇱🇦",flag_lk="🇱🇰",flag_li="🇱🇮",ferris_wheel="🎡",hand_splayed_tone2="🖐🏼",large_blue_diamond="🔷",cat2="🐈",icecream="🍦",tent="⛺",joy="😂",hand_splayed_tone4="🖐🏾",file_cabinet="🗄",key="🔑",weary="😩",bath_tone2="🛀🏼",flag_lv="🇱🇻",low_brightness="🔅",rowboat_tone5="🚣🏿",rowboat_tone2="🚣🏼",rowboat_tone3="🚣🏽",four_leaf_clover="🍀",space_invader="👾",cl="🆑",cd="💿",bath_tone4="🛀🏾",flag_za="🇿🇦",swimmer="🏊",wavy_dash="〰",flag_zm="🇿🇲",flag_zw="🇿🇼",raised_hands_tone5="🙌🏿",two_hearts="💕",bulb="💡",cop_tone4="👮🏾",cop_tone5="👮🏿",cop_tone2="👮🏼",cop_tone3="👮🏽",cop_tone1="👮🏻",open_file_folder="📂",homes="🏘",raised_hands_tone2="🙌🏼",fearful="😨",grinning="😀",bow_tone5="🙇🏿",santa_tone3="🎅🏽",santa_tone2="🎅🏼",santa_tone5="🎅🏿",santa_tone4="🎅🏾",bow_tone2="🙇🏼",bow_tone3="🙇🏽",bathtub="🛁",ping_pong="🏓",u5272="🈹",rooster="🐓",vs="🆚",bullettrain_front="🚅",airplane_small="🛩",white_circle="⚪",balloon="🎈",cross="✝",princess_tone3="👸🏽",speaker="🔈",zipper_mouth="🤐",u6307="🈯",whale="🐳",pensive="😔",signal_strength="📶",muscle="💪",rocket="🚀",camel="🐫",boot="👢",flashlight="🔦",spy_tone4="🕵🏾",spy_tone5="🕵🏿",ski="🎿",spy_tone3="🕵🏽",musical_keyboard="🎹",spy_tone1="🕵🏻",rolling_eyes="🙄",clock1="🕐",clock2="🕑",clock3="🕒",clock4="🕓",clock5="🕔",clock6="🕕",clock7="🕖",clock8="🕗",clock9="🕘",doughnut="🍩",dancer_tone1="💃🏻",dancer_tone2="💃🏼",dancer_tone3="💃🏽",candy="🍬",two_men_holding_hands="👬",badminton="🏸",bust_in_silhouette="👤",writing_hand_tone2="✍🏼",sunflower="🌻",["e-mail"]="📧",chains="⛓",kissing_smiling_eyes="😙",fish_cake="🍥",no_pedestrians="🚷",v_tone4="✌🏾",v_tone5="✌🏿",v_tone1="✌🏻",v_tone2="✌🏼",v_tone3="✌🏽",arrow_backward="◀",clock12="🕛",clock10="🕙",clock11="🕚",sweat="😓",mountain_railway="🚞",tongue="👅",black_square_button="🔲",do_not_litter="🚯",nose_tone4="👃🏾",nose_tone5="👃🏿",nose_tone2="👃🏼",nose_tone3="👃🏽",nose_tone1="👃🏻",horse_racing_tone5="🏇🏿",horse_racing_tone4="🏇🏾",horse_racing_tone3="🏇🏽",ok_hand="👌",horse_racing_tone1="🏇🏻",custard="🍮",rowboat="🚣",white_sun_small_cloud="🌤",flag_kr="🇰🇷",cricket="🏏",flag_kp="🇰🇵",flag_kw="🇰🇼",flag_kz="🇰🇿",flag_ky="🇰🇾",construction="🚧",flag_kg="🇰🇬",flag_ke="🇰🇪",flag_ki="🇰🇮",flag_kh="🇰🇭",flag_kn="🇰🇳",flag_km="🇰🇲",cake="🍰",flag_wf="🇼🇫",mortar_board="🎓",pig="🐷",flag_ws="🇼🇸",person_frowning="🙍",arrow_upper_right="↗",book="📖",clock1130="🕦",boom="💥",["repeat"]="🔁",star="⭐",rabbit2="🐇",footprints="👣",ghost="👻",droplet="💧",vibration_mode="📳",flag_ye="🇾🇪",flag_yt="🇾🇹", } emoji['slightly_smiling_face'] = ':)' emoji['+1'] = "👍" emoji['-1'] = "👎" local function str2emoji(str) if not str then return '' end return (str:gsub(':[a-zA-Z0-9%-_+]+:', function(word) return emoji[word:match(':(.+):')] or word end)) end function emoji_replace_input_string(buffer) -- Get input contents local input_s = w.buffer_get_string(buffer, 'input') -- Skip modification of settings if input_s:match('^/set ') then return w.WEECHAT_RC_OK end w.buffer_set(buffer, 'input', str2emoji(input_s)) return w.WEECHAT_RC_OK end function emoji_input_replacer(data, buffer, command) if command == '/input return' then return emoji_replace_input_string(buffer) end return w.WEECHAT_RC_OK end function emoji_live_input_replace(data, modifier, modifier_data, msg) return str2emoji(msg) end function emoji_out_replace(data, modifier, modifier_data, msg) return str2emoji(msg) end function unshortcode_cb(data, modifier, modifier_data, msg) return str2emoji(msg) end function emoji_complete_next_cb(data, buffer, command) local input_s = w.buffer_get_string(buffer, 'input') -- Require : in word if not input_s:match(':') then return w.WEECHAT_RC_OK end local current_pos = w.buffer_get_integer(buffer, "input_pos") - 1 --local input_length = w.buffer_get_integer(buffer, "input_length") while current_pos >= 1 and input_s.sub(current_pos, current_pos) ~= ':' do current_pos = current_pos - 1 end if current_pos < 1 then current_pos = 1 end -- TODO: Support non-end-word editing local oword = input_s:sub(current_pos) local word = oword:match(':(.*)') for e, b in pairs(emoji) do if e:match(word) then local new = (input_s:gsub(":"..word, b)) w.buffer_set(buffer, 'input', new) --w.buffer_set(buffer, "input_pos", str(w.buffer_get_integer(buffer, "input_pos") + 1)) return w.WEECHAT_RC_OK_EAT end end return w.WEECHAT_RC_OK end function emoji_completion_cb(data, completion_item, buffer, completion) for k, v in pairs(emoji) do w.hook_completion_list_add(completion, ":"..k..":", 0, w.WEECHAT_LIST_POS_SORT) end return w.WEECHAT_RC_OK end function incoming_cb(data, modifier, modifier_data, msg) --local plugin, buffer_name, tags = modifier_data:match('^(.-);(.-);(.-)$') -- Only replace in incoming "messages" if modifier_data:match('nick_') then return str2emoji(msg) end return msg end function e_init() if w.register( SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, '', '') then -- Hook input enter w.hook_command_run('/input return', 'emoji_input_replacer', '') -- Hook irc out for relay clients --w.hook_modifier('input_text_for_buffer', 'emoji_out_replace', '') w.hook_modifier('irc_out1_PRIVMSG', 'emoji_out_replace', '') -- Replace while typing w.hook_modifier('input_text_display_with_cursor', 'emoji_live_input_replace', '') -- Hook tab complete w.hook_command_run("/input complete_next", "emoji_complete_next_cb", "") -- Hook for working togheter with other scripts w.hook_modifier('emoji_unshortcode', 'unshortcode_cb', '') w.hook_completion("emojis", "complete :emoji:s", "emoji_completion_cb", "") local settings = { incoming = {'on', 'Also try to replace shortcodes to emoji in incoming messages'} } -- set default settings local version = tonumber(w.info_get('version_number', '') or 0) for option, value in pairs(settings) do if w.config_is_set_plugin(option) ~= 1 then w.config_set_plugin(option, value[1]) end if version >= 0x00030500 then w.config_set_desc_plugin(option, ('%s (default: "%s")'):format( value[2], value[1])) end end -- Hook incoming message if w.config_get_plugin('incoming') == 'on' then w.hook_modifier("weechat_print", 'incoming_cb', '') end end end e_init() weechat-scripts-20191009/lua/http_item.lua000066400000000000000000000067241354740107000203610ustar00rootroot00000000000000-- HTTP bar item, using lua patterns to get content -- -- Copyright 2013 Tor Hveem -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- -- -- Usage: put [http_item] in your status bar items. (Or any other bar to your liking) -- "/set weechat.bar.status.items". -- local w = weechat SCRIPT_NAME = "http_item" SCRIPT_AUTHOR = "xt " SCRIPT_VERSION = "1" SCRIPT_LICENSE = "GPL3" SCRIPT_DESC = "Bar item with HTTP source, using lua patterns to match content" BAR_ITEM_NAME = SCRIPT_NAME -- Settings settings = { url = 'http://weechat.org/info/stable/', pattern = '(%d+%.%d+%.%d+)', message_prefix = 'Latest WeeChat: ', message_postfix = '', message_color = 'default', interval = '5', -- poll every 5 minutes } -- other globals ITEM_TEXT = nil function http_bi_cb(data, item, window) -- Return the bar item string if ITEM_TEXT then return string.format('%s%s%s%s', w.config_get_plugin('message_prefix'), w.color(w.config_get_plugin('message_color')), ITEM_TEXT, w.config_get_plugin('message_postfix') ) end return '' end function http_bi_update() -- Function to manually update the bar item w.bar_item_update(BAR_ITEM_NAME) return w.WEECHAT_RC_OK end function debug(buf, str) -- helper function for debugging local debug = false if debug and str then w.print(buf, SCRIPT_NAME .. ': ' .. str) end return w.WEECHAT_RC_OK end function init_config() -- Set defaults for option, default_value in pairs(settings) do if w.config_is_set_plugin(option) == 0 then w.config_set_plugin(option, default_value) end end -- read options from weechat into our lua table for option, default_value in pairs(settings) do settings[option] = w.config_get_plugin(option) end return w.WEECHAT_RC_OK end function start_fetch() -- Get URL using weechat API for URL local url = w.config_get_plugin('url') -- 30 seconds timeout local timeout = 30*1000 debug('', url) w.hook_process('url:'..url, timeout, 'http_fetch_cb', '') return w.WEECHAT_RC_OK end function http_fetch_cb(data, command, return_code, out, err) if #out > 0 then out = out:match(w.config_get_plugin('pattern')) ITEM_TEXT = out debug('', ITEM_TEXT) -- Update bar item since we got new data w.bar_item_update(BAR_ITEM_NAME) end return w.WEECHAT_RC_OK end if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, '', '') then init_config() -- create the bar item w.bar_item_new(BAR_ITEM_NAME, 'http_bi_cb', '') -- Initial fetch start_fetch() -- hook the fetch timer w.hook_timer( w.config_get_plugin('interval')*60*1000, 0, 0, 'start_fetch', '') end weechat-scripts-20191009/lua/mpdbitl.lua000066400000000000000000000405341354740107000200140ustar00rootroot00000000000000--[[ -- mpdbitl -- -- Script that automatically change bitlbee status message into current MPD -- track. Requires Weechat 0.3.5 or higher. -- -- Author: rumia -- License: WTFPL --]] require "socket" mpdbitl_config = { enable = true, hostname = "localhost", port = 6600, password = nil, timeout = 1, network = "localhost", channel = "&bitlbee", bitlbot = "root", accounts = "", format_playing = "", format_paused = "", format_stopped = "", format_none = "" } mpdbitl_sock = nil mpdbitl_song_id = nil mpdbitl_error = {} mpdbitl_config_file = nil mpdbitl_current_state = "stop" mpdbitl_config_file_name = "mpdbitl" mpdbitl_status_text = "" mpdbitl_timer = nil mpdbitl_caught_messages = 0 mpdbitl_msg_hook = nil -- 1: bitlbot, 2: account id/tag, 3: status message mpdbitl_status_command_normal = "/mute -all msg %s account %s set status %s" -- 1: nick/handle, 2: status message mpdbitl_status_command_alternate = "/mute -all msg %s %s" function mpdbitl_config_init() local structure = { general = { enable = { description = "Enable mpdbitl", default = true } }, mpd = { hostname = { description = "Hostname of MPD server", default = "localhost" }, port = { description = "Port used by MPD server", default = 6600, min = 1, max= 65535 }, password = { description = "Password used to authenticate to MPD server", default = "" }, timeout = { description = "Connection timeout (in seconds)", default = 3, min = 1, max = 65535 } }, bitlbee = { network = { description = "Network ID for Bitlbee server", default = "localhost" }, channel = { description = "Bitlbee main channel", default = "&bitlbee" }, accounts = { description = "Comma separated list of Bitlbee account IDs/tags/handles. " .. "To specify a handle, prefix the entry with @", default = {0} }, bitlbot = { description = "Bitlbee bot handle name", default = "root" }, format_playing = { description = "Status format when MPD is playing a song", default = "mpdbitl: {{artist}} — {{title}}" }, format_paused = { description = "Status format when MPD is paused", default = "mpdbitl (paused): {{artist}} — {{title}}" }, format_stopped = { description = "Status format when MPD is stoppedsong", default = "mpdbitl (stopped): {{artist}} — {{title}}" }, format_none = { description = "Status format when MPD is playlist is empty or MPD has reached " .. "the end of playlist and there's nothing else to play", default = "mpdbitl (not playing)" } } } mpdbitl_config_file = weechat.config_new(mpdbitl_config_file_name, "mpdbitl_config_reload", "") if mpdbitl_config_file == "" then return end for section_name, section_options in pairs(structure) do local section = weechat.config_new_section( mpdbitl_config_file, section_name, 0, 0, "", "", "", "", "", "", "", "", "", "") if section == "" then weechat.config_free(mpdbitl_config_file) return end for option, definition in pairs(section_options) do local lua_type = type(definition.default) if lua_type == "number" then mpdbitl_config[option] = weechat.config_new_option( mpdbitl_config_file, section, option, "integer", definition.description, "", (definition.min and definition.min or 0), (definition.max and definition.max or 0), definition.default, definition.default, 0, "", "", "", "", "", "") elseif lua_type == "boolean" then local default = definition.default and "on" or "off" mpdbitl_config[option] = weechat.config_new_option( mpdbitl_config_file, section, option, "boolean", definition.description, "", 0, 0, default, default, 0, "", "", "", "", "", "") elseif lua_type == "table" or lua_type == "string" then local default = definition.default if lua_type == "table" then default = table.concat( definition.default, (definition.separator and definition.separator or ",")) end mpdbitl_config[option] = weechat.config_new_option( mpdbitl_config_file, section, option, "string", definition.description, "", 0, 0, default, default, 0, "", "", "", "", "", "") end end end end function mpdbitl_config_reload(data, config_file) return weechat.config_reload(config_file) end function mpdbitl_config_read() return weechat.config_read(mpdbitl_config_file) end function mpdbitl_config_write() return weechat.config_write(mpdbitl_config_file) end function mpdbitl_msg(...) if arg and #arg > 0 then weechat.print("", string.format(unpack(arg))) end end function mpdbitl_connect() mpdbitl_sock = socket.tcp() mpdbitl_sock:settimeout(weechat.config_integer(mpdbitl_config.timeout), "t") local hostname = weechat.config_string(mpdbitl_config.hostname) local port = weechat.config_integer(mpdbitl_config.port) if not mpdbitl_sock:connect(hostname, port) then mpdbitl_msg("Could not connect to %s:%d", hostname, port) return false end local line = mpdbitl_sock:receive("*l") if not line then mpdbitl_msg("No response from MPD") return false end if not line:match("^OK MPD") then mpdbitl_msg("Unknown welcome message: %s", line) return false else local password = weechat.config_string(mpdbitl_config.password) if password and #password > 0 then password = password:gsub('\\', '\\\\') password = password:gsub('"', '\\"') local command = 'password "' .. password .. '"' if mpdbitl_send_command(command) then local response = mpdbitl_fetch_all_responses() if mpdbitl_error.message then mpdbitl_msg("MPD error: %s", mpdbitl_error.message) return false end end end return true end end function mpdbitl_disconnect() mpdbitl_send_command("close") mpdbitl_sock:close() end function mpdbitl_send_command(line) line = line .. "\n" local sent = mpdbitl_sock:send(line) return sent == #line end function mpdbitl_receive_single_response() local complete, key, value, _ local error = {} local line = mpdbitl_sock:receive("*l") if line then if line:match("^OK$") then complete = true elseif line:match("^ACK") then _, _, error.code, error.index, error.command, error.message = line:find("^ACK %[(%d+)@(%d+)%] {([^}]+)\} (.+)") complete = true else _, _, key, value = line:find("^([^:]+):%s(.+)") if key then key = string.gsub(key:lower(), "-", "_") end end end return key, value, complete, error end function mpdbitl_fetch_all_responses() local result = {} local complete, key, value repeat key, value, complete, mpdbitl_error = mpdbitl_receive_single_response() if key then result[key] = value end until complete if mpdbitl_error.message then mpdbitl_msg( "MPD Error %s (%s @ %u): %s", mpdbitl_error.code, mpdbitl_error.command, mpdbitl_error.index, mpdbitl_error.message) end return result end function mpdbitl_get_server_status() if mpdbitl_send_command("status") then return mpdbitl_fetch_all_responses() else return false end end function mpdbitl_get_current_song() if mpdbitl_send_command("currentsong") then local song = mpdbitl_fetch_all_responses() if song.time then local duration = tonumber(song.time) local hours = math.floor(duration / 3600) % 24 local minutes = math.floor(duration / 60) % 60 local seconds = duration % 60 song.time = string.format("%02d:%02d", minutes, seconds) if hours > 0 then song.time = string.format("%02d:%s", hours, song.time) end end return song else return false end end function mpdbitl_format_status_text(text, replacement) if not text or not replacement or #text < 1 or type(replacement) ~= "table" then return "" end return text:gsub("{{([^}]+)}}", function (key) if replacement[key] then return replacement[key] else return "" end end) end function mpdbitl_bar_item(data, item, window) return mpdbitl_status_text end function mpdbitl_escape_bitlbee_command_arg(arg) if type(arg) == 'number' then return arg elseif type(arg) == 'string' then return "'" .. arg:gsub("'", "\\'") .. "'" else return "''" end end function mpdbitl_catch_bitlbot_response(total_msg, modifier, msg_network, string) if not total_msg or total_msg == "" then return string end if type(total_msg) == "string" then total_msg = tonumber(total_msg) end if total_msg < 1 or mpdbitl_caught_messages >= total_msg then return string end local network = weechat.config_string(mpdbitl_config.network) if network ~= msg_network then return string end local parsed = weechat.info_get_hashtable( "irc_message_parse", {message = string}) if not parsed or type(parsed) ~= "table" then return string end local bitlbot = weechat.config_string(mpdbitl_config.bitlbot) if bitlbot ~= parsed.nick then return string end local expected_arg = string.format( "%s :status = `%s'", parsed.channel, mpdbitl_status_text) if parsed.arguments == expected_arg then mpdbitl_caught_messages = mpdbitl_caught_messages + 1 if mpdbitl_caught_messages >= total_msg then if mpdbitl_msg_hook and mpdbitl_msg_hook ~= "" then weechat.unhook(mpdbitl_msg_hook) end end return "" else return string end end function mpdbitl_change_bitlbee_status(data, remaining_calls) local network = weechat.config_string(mpdbitl_config.network) local channel = weechat.config_string(mpdbitl_config.channel) local buf_id = network .. "." .. channel local buffer = weechat.buffer_search("irc", buf_id) if buffer == "" then mpdbitl_msg("No buffer for %s", buf_id) return weechat.WEECHAT_RC_OK end local bitlbot = weechat.config_string(mpdbitl_config.bitlbot) if weechat.nicklist_search_nick(buffer, "", bitlbot) == "" then mpdbitl_msg("No such nick: %s", bitlbot) return weechat.WEECHAT_RC_ERROR end local change_status = false if mpdbitl_connect() then local server_status = mpdbitl_get_server_status() if server_status.state ~= mpdbitl_current_state or server_status.songid ~= mpdbitl_song_id then local format = "" if server_status.state == "play" then format = mpdbitl_config.format_playing elseif server_status.state == "pause" then format = mpdbitl_config.format_paused elseif server_status.state == "stop" then if not server_status.songid then format = mpdbitl_config.format_none else format = mpdbitl_config.format_stopped end else mpdbitl_msg("Unknown state: %s", server_status.state) mpdbitl_disconnect() return weechat.WEECHAT_RC_ERROR end change_status = true mpdbitl_current_state = server_status.state mpdbitl_song_id = server_status.songid mpdbitl_status_text = mpdbitl_format_status_text( weechat.config_string(format), mpdbitl_get_current_song()) end mpdbitl_disconnect() if change_status then local accounts = weechat.config_string(mpdbitl_config.accounts) local command_for_bitlbot = {} for account in accounts:gmatch("[^,]+") do local _, _, target = account:find("^@(.+)") if not target then command_for_bitlbot[#command_for_bitlbot + 1] = string.format( mpdbitl_status_command_normal, bitlbot, mpdbitl_escape_bitlbee_command_arg(account), mpdbitl_escape_bitlbee_command_arg(mpdbitl_status_text)) else weechat.command( buffer, string.format( mpdbitl_status_command_alternate, target, mpdbitl_status_text)) end end weechat.bar_item_update("mpdbitl_track") if #command_for_bitlbot > 0 then mpdbitl_caught_messages = 0 mpdbitl_msg_hook = weechat.hook_modifier( "irc_in2_PRIVMSG", "mpdbitl_catch_bitlbot_response", #command_for_bitlbot) for _, cmd in ipairs(command_for_bitlbot) do weechat.command(buffer, cmd) end end end return weechat.WEECHAT_RC_OK else return weechat.WEECHAT_RC_ERROR end end function mpdbitl_toggle() local current = weechat.config_boolean(mpdbitl_config.enable) local new_value = (current == 0 and 1 or 0) local result = weechat.config_option_set(mpdbitl_config.enable, new_value, 1) if new_value == 1 then mpdbitl_set_timer() else mpdbitl_unset_timer() end return weechat.WEECHAT_RC_OK end function mpdbitl_set_timer() if not mpdbitl_timer then mpdbitl_timer = weechat.hook_timer( 60 * 1000, 60, 0, "mpdbitl_change_bitlbee_status", "") end end function mpdbitl_unset_timer() if mpdbitl_timer then weechat.unhook(mpdbitl_timer) end end function mpdbitl_command(data, buffer, arg_string) local args = {} arg_string:gsub("([^ \t]+)", function (s) args[#args + 1] = s end) if #args < 1 then return weechat.WEECHAT_RC_OK end if args[1] == "toggle" then return mpdbitl_toggle() elseif args[1] == "change" then return mpdbitl_change_bitlbee_status() else mpdbitl_msg("Unknown command: %s", args[1]) return weechat.WEECHAT_RC_ERROR end end function mpdbitl_unload() mpdbitl_config_write() return weechat.WEECHAT_RC_OK end function mpdbitl_initialize() weechat.register( "mpdbitl", "rumia ", "1.2", "WTFPL", "Automatically change bitlbee status message into current MPD track", "mpdbitl_unload", "") mpdbitl_config_init() mpdbitl_config_read() weechat.bar_item_new("mpdbitl_track", "mpdbitl_bar_item", "") weechat.hook_command( "mpdbitl", "Change bitlbee status message into current MPD track", "toggle|change", "toggle: enable/disable script\n" .. "change: change bitlbee status immediately\n", "toggle || change", "mpdbitl_command", "") local enabled = weechat.config_boolean(mpdbitl_config.enable) if enabled == 1 then mpdbitl_set_timer() end end mpdbitl_initialize() weechat-scripts-20191009/lua/nick_complete_wrapper.lua000066400000000000000000000142171354740107000227340ustar00rootroot00000000000000--[[ Author: singalaut License: WTFPL URL: https://github.com/tomoe-mami/weechat-scripts/tree/master/nick_complete_wrapper A script for adding custom prefix and/or suffix when doing nick completion. Originally written to make nick completion in Bitlbee #twitter_* channels prepended with '@'. To use this script, set local variable `ncw_prefix` and/or `ncw_suffix` in the buffer you want with `/buffer set` command. For example: /buffer set localvar_set_ncw_prefix @ /buffer set localvar_set_ncw_suffix > To delete those variables, replace `localvar_set` with `localvar_del`. For example: /buffer set localvar_del_ncw_suffix 1 The '1' in the example above is just a dummy arg. Weechat requires 2 args after `/buffer set `. --------------------------------------------------------------------------------- For Lua < 5.3, luautf8 (https://luarocks.org/modules/xavier-wang/luautf8) module is an optional (but recommended) dependency. In Lua 5.3, the script doesn't have any dependency. --]] w, script_name = weechat, "nick_complete_wrapper" config, hooks = {}, {} function main() local reg = w.register( script_name, "singalaut ", "0.1", "WTFPL", "Wraps nick completion with prefix and/or suffix", "", "") if reg then check_utf8_support() config.nick_add_space = w.config_get("weechat.completion.nick_add_space") w.hook_command_run("9000|/input complete_*", "complete_cb", "") end end function check_utf8_support() if utf8 and type(utf8.len) == "function" then -- lua 5.3 with builtin utf8 support string_length = utf8.len else -- lua < 5.3 with [lua-]utf8 module local pkgs = { "lua-utf8", "utf8" } for _, searcher in ipairs(package.searchers or package.loaders) do for _, pkg_name in ipairs(pkgs) do local loader = searcher(pkg_name) if type(loader) == "function" then package.preload[pkg_name] = loader utf8 = require(pkg_name) if type(utf8.len) == "function" then string_length = utf8.len return end end end end end if not string_length then string_length = w.strlen_screen end end function get_completion(ptr_buffer) local t = {} local ptr_comp = w.hdata_pointer(w.hdata_get("buffer"), ptr_buffer, "completion") if ptr_comp and ptr_comp ~= "" then local h_comp = w.hdata_get("completion") t.start_pos = w.hdata_integer(h_comp, ptr_comp, "position_replace") t.word_found = w.hdata_string(h_comp, ptr_comp, "word_found") t.is_nick = w.hdata_integer(h_comp, ptr_comp, "word_found_is_nick") == 1 t.is_command = w.hdata_string(h_comp, ptr_comp, "base_command") ~= "" if not t.is_command and t.word_found == "" then local last_nick = w.buffer_get_string(ptr_buffer, "localvar_ncw_last_nick") if last_nick ~= "" then t.word_found, t.is_nick = last_nick, true t.start_pos = tonumber(w.buffer_get_string(ptr_buffer, "localvar_ncw_last_pos")) or 0 w.buffer_set(ptr_buffer, "localvar_del_ncw_last_nick", "") w.buffer_set(ptr_buffer, "localvar_del_ncw_last_pos", "") end end return t end end function get_prefix_suffix(ptr_buffer) return { prefix = w.buffer_get_string(ptr_buffer, "localvar_ncw_prefix"), suffix = w.buffer_get_string(ptr_buffer, "localvar_ncw_suffix") } end function cleanup_previous_completion(ptr_buffer) local ps = get_prefix_suffix(ptr_buffer) if ps.prefix == "" and ps.suffix == "" then return w.WEECHAT_RC_OK end local comp = get_completion(ptr_buffer) if comp and comp.is_nick and not comp.is_command then local current_pos = w.buffer_get_integer(ptr_buffer, "input_pos") local input = w.buffer_get_string(ptr_buffer, "input") local space = w.config_boolean(config.nick_add_space) and " " or "" local str_nick = ps.prefix..comp.word_found..ps.suffix..space local str_before = input:sub(1, comp.start_pos) if string_length(str_before..str_nick) == current_pos then w.buffer_set(ptr_buffer, "completion_freeze", "1") w.buffer_set(ptr_buffer, "input", str_before..comp.word_found..input:sub(comp.start_pos + #str_nick)) w.buffer_set(ptr_buffer, "input_pos", string_length(str_before..comp.word_found..space)) w.buffer_set(ptr_buffer, "completion_freeze", "0") w.buffer_set(ptr_buffer, "localvar_set_ncw_last_nick", comp.word_found) w.buffer_set(ptr_buffer, "localvar_set_ncw_last_pos", comp.start_pos) else w.buffer_set(ptr_buffer, "localvar_del_ncw_last_nick", "") w.buffer_set(ptr_buffer, "localvar_del_ncw_last_pos", "") end end end function complete_cb(_, ptr_buffer) cleanup_previous_completion(ptr_buffer) hooks[ptr_buffer] = w.hook_signal("input_text_changed", "input_changed_cb", ptr_buffer) return w.WEECHAT_RC_OK end function input_changed_cb(ptr_buffer) if not hooks[ptr_buffer] then return w.WEECHAT_RC_OK end w.unhook(hooks[ptr_buffer]) hooks[ptr_buffer] = nil local ps = get_prefix_suffix(ptr_buffer) if ps.prefix == "" and ps.suffix == "" then return w.WEECHAT_RC_OK end local comp = get_completion(ptr_buffer) if not comp or comp.is_command or not comp.is_nick then return w.WEECHAT_RC_OK end local str_nick = ps.prefix..comp.word_found..ps.suffix if str_nick ~= comp.word_found then local input = w.buffer_get_string(ptr_buffer, "input") local current_pos = w.buffer_get_integer(ptr_buffer, "input_pos") local str_before = input:sub(1, comp.start_pos) local add_space = w.config_boolean(config.nick_add_space) and 1 or 0 local str_after = input:sub(comp.start_pos + #comp.word_found + add_space) w.buffer_set(ptr_buffer, "completion_freeze", "1") w.buffer_set(ptr_buffer, "input", str_before..str_nick..str_after) w.buffer_set(ptr_buffer, "input_pos", string_length(str_before..str_nick) + add_space) w.buffer_set(ptr_buffer, "completion_freeze", "0") end return w.WEECHAT_RC_OK end main() weechat-scripts-20191009/lua/oldswarner.lua000066400000000000000000000105221354740107000205330ustar00rootroot00000000000000-- Copyright 2013 xt -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- --[[ This script will try to prevent you from posting URLs to a buffer that was recently posted, as recently as your weechat will remember lines. Usage: To get notice when trying to send old URL you will have to add a new item to your input bar. To override the default setting please run this command: /set weechat.bar.input.items "[input_prompt]+(away),[input_search],[input_paste],[input_olds],input_text" If you already have customized this setting, you will have to edit your own setting and add input_olds where you want it to be displayed. Changelog: version 2.1, 2015-08-06, boyska * FIX urls interpreted as patterns version 2, 2013-09-21, xt * Use hdata instead of infolines to improve performance version 1, 2013-09-15, xt * initial version --]] SCRIPT_NAME = "oldswarner" SCRIPT_AUTHOR = "xt " SCRIPT_VERSION = "2.1" SCRIPT_LICENSE = "GPL3" SCRIPT_DESC = "Warn user if about to paste URL already existing in buffer" ITEM_NAME = 'input_olds' ITEM_TEXT = '' local w = weechat local patterns = { -- X://Y url "^(https?://%S+)", "^", "^", "^<(https?://%S+)>", "^(https?://%S+)>", "%f[%S](https?://%S+)", -- www.X.Y url "^(www%.[%w_-%%]+%.%S+)", "%f[%S](www%.[%w_-%%]+%.%S+)", } -- return a table containing all urls in a message function findURLs(message) local urls = {} local index = 1 for split in message:gmatch('%S+') do for i=1, #patterns do local _, count = split:gsub(patterns[i], function(url) table.insert(urls, url) end) if(count > 0) then index = index + 1 break end end end return urls end function is_url_in_buffer(buffer, url) lines = weechat.hdata_pointer(weechat.hdata_get('buffer'), buffer, 'own_lines') line = weechat.hdata_pointer(weechat.hdata_get('lines'), lines, 'first_line') hdata_line = weechat.hdata_get('line') hdata_line_data = weechat.hdata_get('line_data') while #line > 0 do data = weechat.hdata_pointer(hdata_line, line, 'data') message = weechat.hdata_string(hdata_line_data, data, 'message') if message:find(url, 1, true) ~= nil then return true end line = weechat.hdata_move(hdata_line, line, 1) end return false end function oldschecker(data, buffer, command) saved_input = weechat.buffer_get_string(buffer, "input") for _,url in pairs(findURLs(saved_input)) do if is_url_in_buffer(buffer, url) and not is_being_warned() then set_item_text() return weechat.WEECHAT_RC_OK_EAT end end clear_item_text() return w.WEECHAT_RC_OK end function set_item_text() message = 'URL already in buffer. Press enter again if you are sure' color = w.color(w.config_color(w.config_get('weechat.color.input_actions'))) ITEM_TEXT = string.format('%s%s%s', color, message, w.color('reset')) w.bar_item_update(ITEM_NAME) end function clear_item_text() ITEM_TEXT = '' w.bar_item_update(ITEM_NAME) end function input_olds_cb(data, item, window) return ITEM_TEXT end function is_being_warned() if ITEM_TEXT == '' then return false end return true end function p_init() if w.register( SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, '', '') then w.hook_command_run('/input return', 'oldschecker', '') -- create the bar item w.bar_item_new(ITEM_NAME, 'input_olds_cb', '') end end p_init() weechat-scripts-20191009/lua/pastebuf.lua000066400000000000000000001264041354740107000201730ustar00rootroot00000000000000--[[ -- pastebuf -- -- A script for viewing the content of a pastebin inside Weechat buffer. -- -- Usage: -- /pastebuf [] -- -- To use syntax highlighting, set plugins.var.lua.pastebuf.syntax_highlighter to -- an external command that will highlight the text. If the command contains -- $lang, it will be replaced by the name of syntax language specified with -- /pastebuf command. For example, to use pygmentize as syntax highlighter: -- -- /set plugins.var.lua.pastebuf.syntax_highlighter "pygmentize -l $lang" -- -- See README in https://github.com/tomoe-mami/weechat-scripts/tree/master/pastebuf -- for more information. -- -- Author: tomoe-mami -- License: WTFPL -- Requires: Weechat 0.4.3+ -- URL: https://github.com/tomoe-mami/weechat-scripts/tree/master/pastebuf -- -- History: -- -- 2014-04-21 Gussi -- v0.3: * Added support for paste.is. -- It's using sticky notes. API support added. -- -- 2014-04-04 tomoe-mami -- * added `run` command inside paste buffer -- * added option to enable opening url from unsupported service -- * support url of "hidden paste" from paste.debian.net -- * added support for paste.ee -- -- 2014-01-24 tomoe-mami -- v0.2: * more supported services -- * fixed csi sgr parsing -- -- 2014-01-15 tomoe-mami -- v0.1: * initial release -- --]] local w = weechat local g = { script = { name = "pastebuf", author = "tomoe-mami ", version = "0.3", license = "WTFPL", description = "View text from various pastebin sites inside a buffer.", url = "https://github.com/tomoe-mami/weechat-scripts/tree/master/pastebuf" }, config = {}, defaults = { fetch_timeout = { value = 30000, type = "number", description = "Timeout for fetching URL (in milliseconds)" }, highlighter_timeout = { value = 3000, type = "number", description = "Timeout for syntax highlighter (in milliseconds)" }, show_line_number = { value = true, type = "boolean", description = "Show line number" }, open_unsupported_url = { value = false, type = "boolean", description = "Force open raw text of unsupported URL format" }, color_line_number = { value = "default,darkgray", type = "string", description = "Color for line number" }, color_line = { value = "default,default", type = "string", description = "Color for line content" }, syntax_highlighter = { value = "", type = "string", description = "External command that will be used as syntax highlighter. " .. "$lang will be replaced by the name of syntax language" }, shell = { value = "/bin/sh", type = "string", description = "Location of your shell or just the shell name if it's already in $PATH" }, sticky_notes_retardness_level = { value = 1, type = "number", description = "The retardness level of Sticky Notes API. Use level 0 if they " .. "somehow fixed their JSON string. Use level 1 to fix their awful " .. "JSON string first before decoding it. Use level 2 if level 1 " .. "failed fixing their JSON string. In level 2, we'll abandon their " .. "API and just fetch the raw paste. Default is 1." } }, sites = { __generic__ = { pattern = "^([^:/]+://[^/]+)(.*)$", id = "%2", raw = "%1%2" }, ["bpaste.net"] = { pattern = "^([^:/]+://[^/]+)/show/(%w+)", id = "%s", raw = "%1/raw/%2" }, ["codepad.org"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/%2/raw.php" }, ["dpaste.com"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/%2/plain/" }, ["dpaste.de"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/%2/raw" }, ["fpaste.org"] = { pattern = "^([^:/]+://[^/]+)/(%w+/?%w*)", id = "%2", raw = "%1/%2/raw" }, ["gist.github.com"] = { pattern = "^([^:/]+://[^/]+)/([^/]+/[^/]+)", id = "%2", raw = "https://gist.githubusercontent.com/%2/raw" }, ["ideone.com"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/plain/%2" }, ["paste.debian.net"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/plain/%2" }, ["paste.ee"] = { pattern = "^([^:/]+://[^/]+)/p/(%w+)", id = "%2", raw = "%1/r/%2" }, ["pastebin.ca"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/raw/%2" }, ["pastebin.com"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/raw.php?i=%2" }, ["pastebin.osuosl.org"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/%2/raw/" }, ["paste.opensuse.org"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/view/raw/%2" }, ["pastie.org"] = {}, ["sprunge.us"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/%2" }, ["vpaste.net"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/%2?raw" }, ["paste.is"] = { pattern = "^([^:/]+://[^/]+)/(%w+)", id = "%2", raw = "%1/%2/raw/" } }, keys = { normal = { ["meta2-A"] = "/window scroll -1", -- arrow up ["meta2-B"] = "/window scroll 1", -- arrow down ["meta2-C"] = "/window scroll_horiz 1", -- arrow right ["meta2-D"] = "/window scroll_horiz -1", -- arrow left ["meta-OA"] = "/window scroll -10", -- ctrl+arrow up ["meta-OB"] = "/window scroll 10", -- ctrl+arrow down ["meta-OC"] = "/window scroll_horiz 10", -- ctrl+arrow right ["meta-OD"] = "/window scroll_horiz -10", -- ctrl+arrow left ["meta2-1~"] = "/pastebuf **scroll start", -- home ["meta2-4~"] = "/pastebuf **scroll end", -- end ["meta-c"] = "/buffer close", -- alt+c } }, hide_stderr = true, buffers = {}, actions = {}, langs = { -- syntax lang aliases. none = false, plain = false, text = false, shell = "sh", markdown = false }, sgr = { attributes = { [1] = "*", -- bold [3] = "/", -- italic [4] = "_", -- underline [7] = "!" -- inverse }, colors = { [ 0] = "black", [ 1] = "red", [ 2] = "green", [ 3] = "yellow", [ 4] = "blue", [ 5] = "magenta", [ 6] = "cyan", [ 7] = "gray", [ 8] = "darkgray", [ 9] = "lightred", [10] = "lightgreen", [11] = "brown", [12] = "lightblue", [13] = "lightmagenta", [14] = "lightcyan", [15] = "white" } } } function prepare_modules(modules) local module_exists = function (name) if package.loaded[name] then return true else for _, searcher in ipairs(package.searchers or package.loaders) do local loader = searcher(name) if type(loader) == "function" then package.preload[name] = loader return true end end return false end end for alias, name in pairs(modules) do if module_exists(name) then _G[alias] = require(name) end end end function convert_plugin_option_value(opt_type, opt_value) if opt_type == "number" or opt_type == "boolean" then opt_value = tonumber(opt_value) if opt_type == "boolean" then opt_value = (opt_value ~= 0) end end return opt_value end function load_config() local shell = os.getenv("SHELL") if shell and shell ~= "" then g.defaults.shell.value = shell end for opt_name, info in pairs(g.defaults) do if w.config_is_set_plugin(opt_name) == 0 then local val if info.type == "boolean" then val = info.value and 1 or 0 elseif info.type == "number" then val = info.value or 0 else val = info.value or "" if opt_name == "syntax_highlighter" and val == "" then val = nil end end w.config_set_plugin(opt_name, val) w.config_set_desc_plugin(opt_name, info.description or "") g.config[opt_name] = val else local val = w.config_get_plugin(opt_name) g.config[opt_name] = convert_plugin_option_value(info.type, val) end end end function bind_keys(buffer, flag) local prefix = flag and "key_bind_" or "key_unbind_" for key, command in pairs(g.keys) do w.buffer_set(buffer, prefix .. key, flag and command or "") end end -- crude converter from csi sgr colors to weechat color function convert_csi_sgr(text) local fg, bg, attr = "", "", "|" local shift_param = function(s) if s then local p1, p2, chunk = s:find("^(%d+);?") if p1 then return chunk, s:sub(p2 + 1) end end end local convert_cb = function(code) local chunk, code = shift_param(code) while chunk do chunk = tonumber(chunk) if chunk == 0 then attr = "" local c2 = shift_param(code) if not c2 or c2 == "" then fg, bg = "", "" end elseif g.sgr.attributes[chunk] then attr = g.sgr.attributes[chunk] elseif chunk >= 30 and chunk <= 37 then fg = g.sgr.colors[ chunk - 30 ] elseif chunk == 38 then local c2, c3 c2, code = shift_param(code) fg, c2 = "default", tonumber(c2) if c2 == 5 then c3, code = shift_param(code) if c3 then fg = tonumber(c3) end end elseif chunk == 39 then fg = "default" elseif chunk >= 40 and chunk <= 47 then bg = g.sgr.colors[ chunk - 40 ] elseif chunk == 48 then local c2, c3 c2, code = shift_param(code) bg, c2 = "default", tonumber(c2) if c2 == 5 then c3, code = shift_param(code) if c3 then bg = tonumber(c3) end end elseif chunk == 49 then bg = "default" elseif chunk >= 90 and chunk <= 97 then fg = g.sgr.colors[ chunk - 82 ] elseif chunk >= 100 and chunk <= 107 then bg = g.sgr.colors[ chunk - 92 ] end chunk, code = shift_param(code) end local result if fg == "" and bg == "" and attr == "" then result = "reset" else result = attr .. fg if bg and bg ~= "" then result = result .. "," .. bg end end return w.color(result) end return text:gsub("\27%[([%d;]*)m", convert_cb) end function message(s) w.print("", g.script.name .. "\t" .. s) end function get_lang(lang) if not lang or lang == "" then return false end lang = lang:lower() if g.langs[lang] ~= nil then lang = g.langs[lang] end return lang end -- false will delete a localvar. nil (or value not specified) will return -- the current value. anything else will set the localvar to that value. function localvar(pointer, variable, value) if value == nil then return w.buffer_get_string(pointer, "localvar_" .. variable) elseif value == false then w.buffer_set(pointer, "localvar_del_" .. variable, "") else if value == true then value = 1 end w.buffer_set(pointer, "localvar_set_" .. variable, value) end end function parse_response_header(response) local p, c, m, h, r = response:match("^(%S+) (%d+) (.-)\r\n(.-)\r\n\r\n(.*)$") if p then c = tonumber(c) if c == 301 or c == 302 or c == 303 then if r ~= "" then -- since we use followlocation=1, there will be another block of header -- after the first empty line. parse that one instead. return parse_response_header(r) end end local result = { protocol = p, status_code = c, status_message = m } if h then result.headers = {} h = h .. "\r\n" for name, value in h:gmatch("([^:]+):%s+(.-)\r\n") do result.headers[name] = value end end return result end end function exec_generic_cb(short_name, cmd, status, response, err) local buffer = g.buffers[short_name] if not buffer then return end if status == 0 or status == w.WEECHAT_HOOK_PROCESS_RUNNING then buffer.temp = buffer.temp .. response if buffer.callback_partial and type(buffer.callback_partial) == "function" then buffer.callback_partial(buffer, short_name, response) end if status == 0 then local data = buffer.temp buffer.temp = nil if buffer.callback_ok and type(buffer.callback_ok) == "function" then buffer.callback_ok(buffer, short_name, data) end end elseif status >= 1 or status == w.WEECHAT_HOOK_PROCESS_ERROR then if (cmd:sub(1, 4) ~= "url:" and g.hide_stderr) or not err or err == "" then err = "Error when trying to access " .. cmd end message(string.format("Error %d: %s", status, err)) if buffer.callback_error and type(buffer.callback_error) == "function" then buffer.callback_error(buffer, short_name, status, err) end end end function exec_generic(short_name, cmd, options, callbacks) local buffer = g.buffers[short_name] buffer.temp = "" if callbacks then local cb_type = type(callbacks) local types = { ok = true, error = true, partial = true, input = true } if cb_type == "function" then buffer.callback_ok = callbacks elseif cb_type == "table" then for t, f in pairs(callbacks) do if type(f) == "function" and types[t] then buffer["callback_" .. t] = f end end end end if cmd:sub(1,4) == "url:" and options then if not options.useragent then options.useragent = g.useragent end if not options.followlocation then options.followlocation = 1 end end if options then buffer.hook = w.hook_process_hashtable( cmd, options, g.config.fetch_timeout, "exec_generic_cb", short_name) if options.stdin and options.stdin == 1 and buffer.callback_input then buffer.callback_input(buffer, short_name, buffer.hook) end else buffer.hook = w.hook_process( cmd, g.config.fetch_timeout, "exec_generic_cb", short_name) end return buffer.hook end function request_head(short_name, url, options, callbacks) if not options then options = {} end options.nobody = 1 options.header = 1 exec_generic(short_name, "url:" .. url, options, callbacks) end function copy_table(t) local r = {} for k,v in pairs(t) do r[k] = v end return r end function get_site_config(u) local host = u:match("^https?://([^/]+)") if host then if host:match("^www%.") then host = host:sub(5) end local site if not g.sites[host] then if not g.config.open_unsupported_url then return else site = copy_table(g.sites.__generic__) end else site = copy_table(g.sites[host]) end site.host = host site.url = u if not site.handler then site.id = string.gsub(u, site.pattern, site.id) site.raw = string.gsub(u, site.pattern, site.raw) end return site end end function init_mode(buf_ptr, mode) local prev_mode = localvar(buf_ptr, "mode") for key, _ in pairs(g.keys[prev_mode]) do w.buffer_set(buf_ptr, "key_unbind_" .. key, "") end for key, cmd in pairs(g.keys[mode]) do w.buffer_set(buf_ptr, "key_bind_" .. key, cmd) end localvar(buf_ptr, "mode", mode) end function action_scroll(buffer, short_name, param) if param == "start" then w.command(buffer.pointer, "/window scroll_top") w.command(buffer.pointer, "/window scroll_horiz -100%") elseif param == "end" then w.command(buffer.pointer, "/window scroll_bottom") w.command(buffer.pointer, "/window scroll_horiz -100%") end end function action_run(buffer, short_name, param) if not g.config.shell or g.config.shell == "" then message( "Can not run command because the shell is empty. " .. "Please specify your shell in plugins.var.lua.pastebuf.shell") return end local cmd, opt = param, param:sub(1, 3) local exec_options, exec_cb = {}, { ok = display_colors } if opt== "-n " then cmd = param:sub(4) else exec_options.stdin = 1 end if cmd == "" then message("Please specify an external command") return end localvar(buffer.pointer, "temp", buffer.temp_name) cmd = w.buffer_string_replace_local_var(buffer.pointer, cmd) localvar(buffer.pointer, "temp", false) if exec_options.stdin then exec_cb.input = function (_, _, hook) local fp = open_file(buffer.temp_name) for line in fp:lines() do w.hook_set(hook, "stdin", line .. "\n") end w.hook_set(hook, "stdin_close", "") fp:close() end end exec_generic( short_name, string.format("%s -c %q", g.config.shell, cmd), exec_options, exec_cb) end function action_save(buffer, short_name, filename) if not filename or filename == "" then message("You need to specify destination filename after `save`") else filename = filename:gsub("^~/", os.getenv("HOME") .. "/") local output = open_file(filename, "w") if output then local input = open_file(buffer.temp_name) if input then local chunk_size, written, chunk = 64 * 1024, 0 chunk = input:read(chunk_size) while chunk do output:write(chunk) written = written + #chunk chunk = input:read(chunk_size) end input:close() message(string.format( "%d %s written to %s", written, (written == 1 and "byte" or "bytes"), filename)) end output:close() end end end function action_change_language(buffer, short_name, new_lang) if not g.config.syntax_highlighter then return end new_lang = new_lang:match("^%s*(%S+)") if not new_lang then message("You need to specify the name of syntax language after `lang`") else local current_lang = localvar(buffer.pointer, "lang") or "" new_lang = get_lang(new_lang) if current_lang ~= new_lang then local fp = open_file(buffer.temp_name) if fp then buffer.file = fp if new_lang then localvar(buffer.pointer, "lang", new_lang) run_syntax_highlighter(short_name, fp) else localvar(buffer.pointer, "lang", false) display_plain(short_name, fp) end fp:close() buffer.file = nil end end end end function action_open_recent_url(current_buffer, limit) local list = {} limit = tonumber(limit) if not limit or limit == 0 then limit = 1 end local buf_lines = w.infolist_get("buffer_lines", current_buffer, "") if buf_lines and buf_lines ~= "" then local url_matcher = "(https?://[%w:!/#_~@&=,;%+%?%[%]%.%%%-]+)" local process_line = function () if w.infolist_integer(buf_lines, "displayed") ~= 1 then return 0 end local line = w.infolist_string(buf_lines, "message") line = w.string_remove_color(line, "") local url = line:match(url_matcher) if not url then return 0 end local site = get_site_config(url) if site then if site.handler and type(site.handler) == "function" then site.handler(site, url) else handler_normal(site, url) end return 1 end return 0 end w.infolist_prev(buf_lines) local c = process_line() while c < limit do if w.infolist_prev(buf_lines) ~= 1 then break end c = c + process_line() end w.infolist_free(buf_lines) if not c or c == 0 then message("No URLs from supported paste services found") end end end function create_buffer(site) local short_name if site.short_name then short_name = site.short_name else short_name = string.format("%s:%s", site.host, site.id) end local name = string.format("%s:%s", g.script.name, short_name) local buffer = w.buffer_new(name, "buffer_input_cb", "", "buffer_close_cb", "") if buffer and buffer ~= "" then local default_mode = "normal" w.buffer_set(buffer, "type", "free") w.buffer_set(buffer, "short_name", short_name) w.buffer_set(buffer, "display", "1") localvar(buffer, "mode", default_mode) init_mode(buffer, default_mode) g.buffers[short_name] = { pointer = buffer } return g.buffers[short_name], short_name end end function display_plain(short_name, fp) local pointer = g.buffers[short_name].pointer local total_lines = 0 if g.config.show_line_number then local lines, total_lines = {}, 0 for line in fp:lines() do total_lines = total_lines + 1 lines[total_lines] = line end if total_lines > 0 then w.buffer_clear(pointer) local num_col_width = #tostring(total_lines) local y = 0 for _, line in ipairs(lines) do print_line(pointer, y, num_col_width, line) y = y + 1 end end else for line in fp:lines() do print_line(pointer, total_lines, nil, line) total_lines = total_lines + 1 end end end function display_colors(buffer, short_name, data) local y, num_col_width = 0 data = convert_csi_sgr(data) if g.config.show_line_number then local _, total_lines = string.gsub(data .. "\n", ".-\n[^\n]*", "") num_col_width = #tostring(total_lines) end w.buffer_clear(buffer.pointer) for line in data:gmatch("(.-)\n") do print_line(buffer.pointer, y, num_col_width, line) y = y + 1 end end function run_syntax_highlighter(short_name, fp) local buffer = g.buffers[short_name] local cmd = w.buffer_string_replace_local_var( buffer.pointer, g.config.syntax_highlighter) local input_cb = function (_, _, hook) for line in fp:lines() do w.hook_set(hook, "stdin", line .. "\n") end w.hook_set(hook, "stdin_close", "") end exec_generic( short_name, cmd, { stdin = 1 }, { ok = display_colors, input = input_cb }); end function open_file(filename, mode) local fp = io.open(filename, mode or "r") if not fp then message(string.format("Unable to open file %s", filename)) else return fp end end function write_temp(data) local temp_name = os.tmpname() local fp = open_file(temp_name, "w+") if fp then fp:write(data) fp:seek("set") return fp, temp_name end end function display_paste(short_name) local buffer = g.buffers[short_name] local fp = open_file(buffer.temp_name) if fp then buffer.file = fp local lang = get_lang(localvar(buffer.pointer, "lang")) if g.config.syntax_highlighter and lang then run_syntax_highlighter(short_name, fp) else display_plain(short_name, fp) end fp:close() buffer.file = nil localvar(buffer.pointer, "temp", buffer.temp_name) w.buffer_set( buffer.pointer, "title", string.format("%s: %s", g.script.name, localvar(buffer.pointer, "url"))) end end function print_line(buffer, y, num_width, content) local line = w.color(g.config.color_line) .. " " .. content if num_width then line = string.format( "%s %" .. num_width .. "d %s", w.color(g.config.color_line_number), y + 1, line) end w.print_y(buffer, y, line) end function decode_json_response(s) if not s or s == "" then message("Error: No response received") else local decoded = json.decode(s) if not decoded or type(decoded) ~= "table" then message("Error: Unable to parse server response") else return decoded end end end function handler_sticky_notes(site, url, lang) local id, hash = url:match("^https?://[^/]+/(%w+)/?(%w*)") if id then site.id = id local short_name = string.format("%s:%s", site.host, id) if not g.buffers[short_name] then g.buffers[short_name] = { host = site.host, url = url } local api_url = string.format("http://%s/api/json/%s", site.host, site.id) if hash then api_url = api_url .. "/" .. hash local fix_json = function (json_string) return json_string:gsub('"data":%s*"(.-)"', function (s) s = s:gsub("\\", "\\\\") s = s:gsub( "([\t\n\r\b\f])", { ["\t"] = "\\t", ["\n"] = "\\n", ["\r"] = "\\r", ["\b"] = "\\b", ["\f"] = "\\f" }) s = s:gsub( "&([^;]+);", { lt = "<", gt = ">", quot = '\\"', amp = "&" }) return string.format('"data": "%s"', s) end) end local process_info = function (buffer, short_name, data) if g.config.sticky_notes_retardness_level == 1 then data = fix_json(data) end local info = decode_json_response(data) if not info then if g.buffers[short_name] then g.buffers[short_name] = nil end return end if info.result.error then message(string.format("Error: %s", info.result.error)) else local param = { short_name = short_name, url = buffer.url, host = buffer.host } local buffer = create_buffer(param) if not buffer then return end localvar(buffer.pointer, "url", param.url) localvar(buffer.pointer, "host", param.host) localvar(buffer.pointer, "id", param.id) w.buffer_set( buffer.pointer, "title", string.format("%s: %s", g.script.name, param.url)) local use_highlighter = false if info.result.language and info.result.language ~= json.null and info.result.language ~= "" then local lang = get_lang(info.result.language) if lang then localvar(buffer.pointer, "lang", lang) if g.config.syntax_highlighter then use_highlighter = true end end end buffer.file, buffer.temp_name = write_temp(info.result.data) if buffer.file then if use_highlighter then run_syntax_highlighter(short_name, buffer.file) else display_plain(short_name, buffer.file) end buffer.file:close() buffer.file = nil end end end local on_error = function (buffer, short_name, status, message) g.buffers[short_name] = nil end exec_generic(short_name, "url:" .. api_url, {}, { ok = process_info, error = on_error }) end end end end function handler_gist(site, url) local first, second = url:match("^https://gist%.github%.com/([^/]+)/?([^/]*)") local host, gist_id = "gist.github.com" if second and second ~= "" then gist_id = second elseif first then gist_id = first else message("Unrecognized gist url") return w.WEECHAT_RC_ERROR end local short_name = string.format("%s:%s", host, gist_id) if not g.buffers[short_name] then g.buffers[short_name] = {} local api_url = string.format("https://api.github.com/gists/%s", gist_id) local display_entry = function (entry) local entry_buffer, entry_short_name = create_buffer({ host = host, id = string.format("%s/%s", gist_id, entry.filename) }) if entry_buffer then local title = string.format( "%s: %s (file: %s)", g.script.name, url, entry.filename) if entry.description then title = string.format("%s [%s]", title, entry.description) end w.buffer_set(entry_buffer.pointer, "title", title) local use_highlighter = false if entry.language and entry.language ~= json.null and entry.language ~= "" then local lang = get_lang(entry.language) if lang then localvar(entry_buffer.pointer, "lang", lang) if g.config.syntax_highlighter then use_highlighter = true end end end entry_buffer.parent = short_name entry_buffer.file, entry_buffer.temp_name = write_temp(entry.content) if entry_buffer.file then if use_highlighter then run_syntax_highlighter(entry_short_name, entry_buffer.file) else display_plain(entry_short_name, entry_buffer.file) end entry_buffer.file:close() entry_buffer.file = nil end return entry_buffer, entry_short_name end end local process_info = function (buffer, short_name, data) local info = decode_json_response(data) if not info then if g.buffers[short_name] then g.buffers[short_name] = nil end return end if info.message then message(string.format("Gist error: %s", info.message)) g.buffers[short_name] = nil else if info.files and type(info.files) == "table" then buffer.sub = {} local description if info.description and info.description ~= json.null then description = info.description:gsub("[\r\n]+", " ") end for _, entry in pairs(info.files) do entry.description = description local sub_buffer, sub_short_name = display_entry(entry) if sub_buffer then buffer.sub[sub_short_name] = sub_buffer.pointer end end end end end local on_error = function (buffer, short_name, status, message) g.buffers[short_name] = nil end exec_generic(short_name, "url:" .. api_url, {}, { ok = process_info, error = on_error }) else message("Gist is already opened. Close all buffers related to this " .. "gist first before making another request") end return w.WEECHAT_RC_OK end function detect_lang_from_query(url, host) local pattern = "%?(.+)$" if host == "sprunge.us" then return url:match(pattern) elseif host == "vpaste.net" then local query = url:match(pattern) if not query then return end for var, value in query:gmatch("([^=]+)=([^&]+)") do if var == "ft" then return value end end end end function handler_normal(site, url, lang) local short_name = string.format("%s:%s", site.host, site.id) if g.buffers[short_name] then local pointer = g.buffers[short_name].pointer if pointer then w.buffer_set(pointer, "display", "1") end else local buffer, short_name = create_buffer(site) if not buffer.hook then --local raw_url = string.format(site.raw, site.id) local title = string.format("%s: Fetching %s", g.script.name, site.url) w.buffer_set(buffer.pointer, "title", title) localvar(buffer.pointer, "url", url) localvar(buffer.pointer, "host", site.host) localvar(buffer.pointer, "id", site.id) if not lang or lang == "" then lang = detect_lang_from_query(url, site.host) end lang = get_lang(lang) if lang then localvar(buffer.pointer, "lang", lang) end local receive_paste = function (buffer, short_name, data) buffer.hook = nil display_paste(short_name) end local send_request = function (buffer, short_name) buffer.temp_name = os.tmpname() exec_generic( short_name, "url:" .. site.raw, { file_out = buffer.temp_name }, receive_paste) end local prepare_request = function (buffer, short_name, data) buffer.hook = nil local response = parse_response_header(data) if response then if response.status_code == 200 then send_request(buffer, short_name) else local title = string.format( "%s: %sError %d: %s (URL: %s)", g.script.name, w.color("chat_prefix_error"), response.status_code, response.status_message, site.raw) w.buffer_set(buffer.pointer, "title", title) w.buffer_set(buffer.pointer, "hotlist", w.WEECHAT_HOTLIST_LOW) end end end if site.host == "sprunge.us" then -- sprunge doesn't allow HEAD method send_request(buffer, short_name) else request_head(short_name, site.raw, nil, prepare_request) end end end return w.WEECHAT_RC_OK end function handler_pastie(site, url, lang) local first, second = url:match("^http://pastie%.org/(%w+)/?(%w*)") local pastie_id if first == "pastes" and second and second ~= "" then pastie_id = second else pastie_id = first end site = { url = url, raw = string.format("http://pastie.org/pastes/%s/download", pastie_id), host = "pastie.org", id = pastie_id } return handler_normal(site, url, lang) end function handler_debian_paste(site, url, lang) local first, second = url:match("^http://paste%.debian%.net/(%w+)/?(%w*)") local id, plain if first == "hidden" and second and second ~= "" then id = second plain = "plainh" else id = first plain = "plain" end site = { url = url, raw = string.format("http://paste.debian.net/%s/%s", plain, id), host = "paste.debian.net", id = id } return handler_normal(site, url, lang) end function open_paste(url, lang) url = url:gsub("#.*$", "") local site = get_site_config(url) if not site then message("Unsupported site: " .. url) return w.WEECHAT_RC_ERROR end if site.handler and type(site.handler) == "function" then return site.handler(site, url, lang) else return handler_normal(site, url, lang) end end function run_action(buf_ptr, action, param) if not g.actions[action] then message(string.format("Unknown action: %s", action)) return end if action == "open-recent-url" then return g.actions[action](buf_ptr, param) else local short_name = w.buffer_get_string(buf_ptr, "short_name") if not g.buffers[short_name] then message("Special commands can only be called inside paste buffer") return end return g.actions[action](g.buffers[short_name], short_name, param) end end function command_cb(_, current_buffer, param) local first, second = param:match("^%s*(%S+)%s*(.*)") if not first then w.command(current_buffer, "/help " .. g.script.name) else if first:sub(1, 2) == "**" then run_action(current_buffer, first:sub(3), second) else open_paste(first, second:match("^(%S+)")) end end return w.WEECHAT_RC_OK end function config_cb(_, opt_name, opt_value) local name = opt_name:match("^plugins%.var%.lua%." .. g.script.name .. "%.(.+)$") if name and g.defaults[name] then g.config[name] = convert_plugin_option_value(g.defaults[name].type, opt_value) if name == "sticky_notes_retardness_level" then if g.config[name] < 2 then g.sites["fpaste.org"].handler = handler_sticky_notes g.sites["pastebin.osuosl.org"].handler = handler_sticky_notes g.sites["paste.is"].handler = handler_sticky_notes else g.sites["fpaste.org"].handler = nil g.sites["pastebin.osuosl.org"].handler = nil g.sites["paste.is"].handler = nil end elseif name == "syntax_highlighter" then if g.config[name] == "" then g.config[name] = nil end end end end function buffer_input_cb(_, pointer, input) local action, param = input:match("^%s*(%S+)%s*(.*)%s*$") if action then return run_action(pointer, action, param) end return w.WEECHAT_RC_OK end function buffer_close_cb(_, buffer) local short_name = w.buffer_get_string(buffer, "short_name") if g.buffers[short_name] then local buffer = g.buffers[short_name] if buffer.hook and buffer.hook ~= "" then w.unhook(buffer.hook) end if buffer.file and io.type(buffer.file) == "file" then buffer.file:close() end if buffer.temp_name then os.remove(buffer.temp_name) end if buffer.parent and g.buffers[buffer.parent] then local p = buffer.parent if g.buffers[p].sub and g.buffers[p].sub[short_name] then g.buffers[p].sub[short_name] = nil local sibling_exists = false for _ in pairs(g.buffers[p].sub) do sibling_exists = true break end if not sibling_exists then g.buffers[p] = nil end end end g.buffers[short_name] = nil end end function buffer_mod_cb(_, buffer, command) local short_name = w.buffer_get_string(buffer, "short_name") if g.buffers[short_name] then message("Please don't modify paste buffer's properties") return w.WEECHAT_RC_OK_EAT else return w.WEECHAT_RC_OK end end function setup() w.register( g.script.name, g.script.author, g.script.version, g.script.license, g.script.description, "", "") local weechat_version = tonumber(w.info_get("version_number", "") or 0) if weechat_version < 0x00040300 then message("This script requires Weechat v0.4.3 or newer") return end if weechat_version >= 0x00040400 then g.hide_stderr = false end prepare_modules({ json = "cjson" }) load_config() if json then g.sites["gist.github.com"].handler = handler_gist if g.config.sticky_notes_retardness_level < 2 then g.sites["fpaste.org"].handler = handler_sticky_notes g.sites["pastebin.osuosl.org"].handler = handler_sticky_notes g.sites["paste.is"].handler = handler_sticky_notes end end g.sites["pastie.org"].handler = handler_pastie g.sites["paste.debian.net"].handler = handler_debian_paste g.useragent = string.format( "%s v%s (%s)", g.script.name, g.script.version, g.script.url) g.actions = { lang = action_change_language, save = action_save, ["open-recent-url"] = action_open_recent_url, scroll = action_scroll, run = action_run } local sites = {} for name, info in pairs(g.sites) do local entry = name if name == "gist.github.com" or name == "fpaste.org" or name == "paste.is" or name == "pastebin.osuosl.org" then local flag = (info.handler and "with" or "no") entry = string.format("%s (%s API)", entry, flag) end table.insert(sites, entry) end local supported_sites = "" if #sites > 0 then supported_sites = "\n\nSupported sites: " .. table.concat(sites, ", ") end w.hook_config("plugins.var.lua." .. g.script.name .. ".*", "config_cb", "") w.hook_command_run("9001|/buffer set *", "buffer_mod_cb", "") local bold, nobold = w.color("bold"), w.color("-bold") w.hook_command( g.script.name, "View the content of a paste inside a buffer" .. supported_sites, " [] | **open-recent-url []", string.format([[ paste-url: URL of the paste syntax-language: Optional language for syntax highlighting %s**open-recent-url%s : Open recent pastebin URLs that are mentioned inside current buffer. Default value for is 1. Inside a paste buffer you can use the following commands: %slang%s Change the active syntax language for current buffer. Use %snone%s to set it to plain text. %ssave%s Save the content of current buffer into a file. %srun%s [-n] Run a shell command and pipe the paste content to it. Use %s-n%s if you don't want to pipe the paste. Command might use special variable $lang for current syntax language and $temp for location of temporary file for current buffer. This will not modify the content of a paste, only what is displayed on current buffer. Calling %slang%s will display the paste content again. Keyboard shortcuts for navigating inside paste buffer: Alt+C Close current buffer Up, Down, Left, Right Scroll buffer 1 line/char Ctrl+(Up/Down/Left/Right) Scroll buffer 10 lines/chars Home Scroll to the start of buffer End Scroll to the end of buffer ]], bold, nobold, bold, nobold, bold, nobold, bold, nobold, bold, nobold, bold, nobold, bold, nobold), "**open-recent-url", "command_cb", "") end setup() weechat-scripts-20191009/lua/text_effects.lua000066400000000000000000000051431354740107000210410ustar00rootroot00000000000000-- Copyright 2010 Vaughan Newton -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- SCRIPT_NAME = "text_effects" SCRIPT_AUTHOR = "Vaughan Newton " SCRIPT_VERSION = "1.1" SCRIPT_LICENSE = "GPL3" SCRIPT_DESC = "Adds effects to words surrounded by certain characters" local w = weechat w.register( SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", "" ) -- Effects effects = { ["*"] = "bold", ["_"] = "underline", } -- printf function function printf(buffer, fmt, ...) w.print(buffer, string.format(fmt, unpack(arg))) end -- Easy callback handling local nextCallbackID = 0 function callback(f) local name = "__callback_" .. nextCallbackID nextCallbackID = nextCallbackID + 1 _G[name] = f return name end -- Config config = { data = {} } setmetatable(config, { __index = function (tab, key) return w.config_string(tab.data[key]) end, }) -- Load config do config.file = w.config_new("text_effects", callback(function(data, file) return w.config_reload(file) end), "") if not config.file then return end config.look = w.config_new_section( config.file, "look", 0, 0, "", "", "", "", "", "", "", "", "", "") local c = config.data c.show_chars = w.config_new_option( config.file, config.look, "show_chars", "boolean", "Whether to show surrounding characters or not", "", 0, 0, "on", "on", 0, "", "", "", "", "", "") w.config_read(config.file) end -- Register modifier w.hook_modifier("weechat_print", callback(function(_, _, info, str) -- Add spaces to help pattern matching str = " " .. str .. " " local pattern = "(%s)([" for char, effect in pairs(effects) do pattern = pattern .. "%"..char end pattern = pattern .. "])([%w_]+)%2(%s)" str = str:gsub(pattern, function(sp1, char, word, sp2) local effect = effects[char] local c = (config.show_chars == "on") and char or "" return sp1 .. w.color(effect) .. c .. word .. c .. w.color("-"..effect) .. sp2 end) -- Remove spaces str = str:sub(2, -2) return str end), "") weechat-scripts-20191009/lua/urlselect.lua000066400000000000000000001306261354740107000203650ustar00rootroot00000000000000--[[ urlselect - A script for interactively select URL and perform an action on it To activate, run /urlselect. View the README at https://github.com/tomoe-mami/weechat-scripts/tree/master/urlselect for more information. Author: tomoe-mami/singalaut License: WTFPL Requires: Weechat 1.0+ ]] local w = weechat local g = { script = { name = "urlselect", version = "0.4", author = "tomoe-mami ", license = "WTFPL", description = "Interactively select URL" }, defaults = { scan_merged_buffers = { type = "boolean", value = "0", description = "Scan URLs from buffers that are merged with the current one" }, tags = { type = "list", value = "notify_message,notify_private,notify_highlight", description = "Comma separated list of tags. If not empty, script will only " .. "scan URLs from messages with any of these tags" }, time_format = { type = "string", value = "%H:%M:%S", description = "Format of time" }, status_timeout = { type = "number", value = "1300", description = "Timeout for displaying status notification (in milliseconds)" }, buffer_name = { type = "string", value = "normal", description = "Type of name to use inside urlselect_buffer_name item. " .. "Valid values are \"full\", \"normal\", and \"short\"" }, use_simple_matching = { type = "boolean", value = "0", description = "Use simple pattern matching when scanning for URLs" }, url_color = { type = "string", value = "_lightblue", description = "Color for URL" }, nick_color = { type = "string", value = "", description = "Color for nickname. Leave empty to use Weechat's nick color" }, highlight_color = { type = "string", value = "${weechat.color.chat_highlight},${weechat.color.chat_highlight_bg}", description = "Nickname color for highlighted message" }, index_color = { type = "string", value = "brown", description = "Color for URL index" }, message_color = { type = "string", value = "default", description = "Color for message text" }, time_color = { type = "string", value = "default", description = "Color for time" }, title_color = { type = "string", value = "default", description = "Color for bar title" }, key_color = { type = "string", value = "cyan", description = "Color for list of keys" }, buffer_number_color = { type = "string", value = "brown", description = "Color for buffer number" }, buffer_name_color = { type = "string", value = "green", description = "Color for buffer name" }, help_color = { type = "string", value = "default", description = "Color for help text" }, status_color = { type = "string", value = "black,green", description = "Color for status notification" }, search_scope = { type = "string", value = "url", valid_values = { url = true, msg = true, nick = true, ["nick+msg"] = true }, description = "Default search scope. Valid values are: url, msg, nick or nick+msg" }, search_prompt_color = { type = "string", value = "default", description = "Color for search prompt" }, search_scope_color = { type = "string", value = "green", description = "Color for current search scope" } }, config = {}, active = false, list = "", bar_items = { list = { "index", "nick", "url", "time", "duplicate", "message", "buffer_name", "buffer_number"}, extra = { "title", "help", "status", "search"} }, custom_commands = {}, hooks = {}, current_status = "", enable_help = false, last_index = 0, enable_search = false, search_scope = 1, scope_list = {"url", "msg", "nick", "nick+msg"} } g.bar = { main = { name = g.script.name }, search = { name = g.script.name .. "_search" }, help = { name = g.script.name .. "_help" } } g.keys = { normal = { ["meta2-B"] = "navigate next", ["meta2-A"] = "navigate previous", ["meta2-1~"] = "navigate last", ["meta2-4~"] = "navigate first", ["ctrl-P"] = "navigate previous-highlight", ["ctrl-N"] = "navigate next-highlight", ["ctrl-S"] = "hsignal", ["ctrl-C"] = "deactivate", ["ctrl-F"] = "search", ["meta-OP"] = "help", ["meta2-11~"] = "help" }, search = { ["ctrl-I"] = "scope next", ["meta2-Z"] = "scope previous", ["ctrl-N"] = "scope nick", ["ctrl-T"] = "scope msg", ["ctrl-U"] = "scope url", ["ctrl-B"] = "scope nick+msg" } } function unload_cb() if g.search_scope and g.scope_list[g.search_scope] then w.config_set_plugin("search_scope", g.scope_list[g.search_scope]) end end function set_default_open_command_cb(_, cmd, ret, out, err) if ret == w.WEECHAT_HOOK_PROCESS_ERROR or ret >= 0 then local open_cmd = "xdg-open" if out and out:match("^([^%s]+)") == "Darwin" then open_cmd = "open" end w.config_set_plugin("cmd.o", "/exec -bg -nosh " .. open_cmd .. " ${url}") w.config_set_plugin("label.o", open_cmd) end end function setup() assert( w.register( g.script.name, g.script.author, g.script.version, g.script.license, g.script.description, "unload_cb", ""), "Unable to register script. Perhaps it's already loaded before?") local wee_ver = tonumber(w.info_get("version_number", "") or 0) if wee_ver < 0x01000000 then error("This script requires WeeChat v1.0 or higher") end local first_run, total_cmd = init_config() setup_hooks() if total_cmd == 0 and first_run then print("No custom commands configured. Adding default custom command...") w.hook_process("uname -s", 5000, "set_default_open_command_cb", "") w.config_set_plugin("cmd.i", "/input insert ${url}\\x20") w.config_set_plugin("label.i", "insert into input bar") end setup_bar() if g.config.search_scope then cmd_action_search_scope(nil, g.config.search_scope) end end function print(msg, param) if not param or type(param) ~= "table" then param = {} end param.script_name = g.script.name if not param.no_eval then msg = w.string_eval_expression(msg, {}, param, {}) end local prefix = g.script.name if param.prefix_type then prefix = w.color("chat_prefix_" .. param.prefix_type) .. prefix end w.print("", prefix .. "\t" .. msg) end function get_or_set_option(name, info, value) local is_set = true if not value then if w.config_is_set_plugin(name) ~= 1 then is_set = false if info.type == "string" then value = w.string_eval_expression(info.value, {}, {}, {}) else value = info.value end w.config_set_plugin(name, value) if info.description then w.config_set_desc_plugin(name, info.description) end else value = w.config_get_plugin(name) end end if info.type == "list" then local list = {} for item in value:gmatch("([^,]+)") do table.insert(list, item:lower()) end value = list elseif info.type == "string" and info.valid_values then if not info.valid_values[value] then value = info.value end elseif info.type == "boolean" or info.type == "number" then value = tonumber(value) if info.type == "boolean" then value = value and value ~= 0 end end return value, is_set end function init_config() local total_cmd, not_set, first_run = 0 for name, info in pairs(g.defaults) do g.config[name], is_set = get_or_set_option(name, info) if first_run == nil and not is_set then first_run = true end end local prefix = "plugins.var.lua." .. g.script.name .. ".cmd." local cfg = w.infolist_get("option", "", prefix .. "*") if cfg and cfg ~= "" then while w.infolist_next(cfg) == 1 do local opt_name = w.infolist_string(cfg, "full_name") local opt_value = w.infolist_string(cfg, "value") local key = opt_name:sub(#prefix + 1) if key then local label = w.config_get_plugin("label." .. key) if set_custom_command(key, opt_value, label, true) then total_cmd = total_cmd + 1 end end end w.infolist_free(cfg) end return first_run, total_cmd end function set_custom_command(key, cmd, label, silent) if not key or not key:match("^[0-9a-z]$") then w.config_unset_plugin("cmd." .. key) if not silent then print( "You can only bind 1 character for custom command. " .. "Valid type of character are digit (0-9) and lowercase " .. "alphabet (a-z) ", { prefix_type = "error" }) end return false else local key_code = "meta-" .. key if not cmd or cmd == "" then if g.keys.normal[key_code] then g.keys.normal[key_code] = nil end if g.custom_commands[key] then g.custom_commands[key] = nil end if not silent then print("Key ${color:bold}${key}${color:-bold} removed", { key = key }) end else g.keys.normal[key_code] = "run " .. key g.custom_commands[key] = { command = cmd } if not label then label = w.config_get_plugin("label." .. key) end if label and label ~= "" then g.custom_commands[key].label = label end if not silent then print( "Key ${color:bold}alt-${key}${color:-bold} bound to command: " .. "${color:bold}${cmd}${color:-bold}", { key = key, cmd = cmd }) end end return true end end function set_custom_label(key, label) if key and key ~= "" and g.custom_commands[key] then if not label or label == "" then g.custom_commands[key].label = nil else g.custom_commands[key].label = label end end end function setup_hooks() w.hook_config("plugins.var.lua." .. g.script.name .. ".*", "config_cb", "") w.hook_command( g.script.name, "Control urlselect script", "[activate [current|merged]] " .. "|| bind [-label