weechat-scripts/0000755000175000017500000000000015000014144012632 5ustar manumanuweechat-scripts/tcl/0000755000175000017500000000000015000014143013413 5ustar manumanuweechat-scripts/tcl/inverter.tcl0000644000175000017500000000270315000014143015757 0ustar manumanu# Copyright (c) 2016 by CrazyCat # # 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 . # # Invert all letters of your text # # Usage: /inv Your text here # # Output: ereh txet ruoY set VERSION 0.1 set SCRIPT_NAME inverter weechat::register $SCRIPT_NAME {CrazyCat } $VERSION GPL3 {invert all letters of your text} {} {} weechat::hook_command inv {invert all letters of the text} {} {} {} invert_cmd {} proc invert_cmd {data buffer args} { set text [join $args] set channel [weechat::buffer_get_string $buffer localvar_channel] if { $text eq "" } { weechat::print $buffer "You need a text to revert" return $::weechat::WEECHAT_RC_ERROR } set inv "" for {set i 0} {$i<=[string length $text]} {incr i} { append inv [string index $text end-$i] } weechat::command $buffer "/msg $channel $inv" return $::weechat::WEECHAT_RC_OK } weechat-scripts/tcl/chan_hl.tcl0000644000175000017500000001212115000014143015510 0ustar manumanu# Copyright (c) 2009 by Dmitry Kobylin # # 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 . # # # mark channels to highlight on each message # # this script is useful with other scripts like: # beep.pl, welauncher.pl, notify.py etc # # to mark channels on strartup set option "default_list" of this # script ( via iset.pl plugin (/iset command) or /setp command) # # by default if message appeared on current channel ( and channel # is marked) highlight event is not sended, to prevent this behaviour # set "hl_on_cur_chan" option to 1 # # Usage: # /mark # /smark # /unmark # /unmark all # /set plugins.var.tcl.chan_hl.default_list "#chan1,#chan2,#somechan" # /set plugins.var.tcl.chan_hl.hl_on_cur_chan 0 # # TODO: # * separate channels with same name on different servers # # 2009-05-02, FlashCode : # version 0.2: sync with last API changes # 2009-04-17, Dmitry Kobylin : # version 0.1 # set VERSION 0.2 set SCRIPT_NAME chan_hl weechat::register \ $SCRIPT_NAME {Karvur } $VERSION GPL3 \ {mark channels to highlight on each message} {} {} set MARK_LIST [list] if {[set DEFAULT_LIST [weechat::config_get_plugin default_list]] eq ""} { weechat::config_set_plugin default_list "" } else { foreach element [split $DEFAULT_LIST ,] {lappend MARK_LIST $element} } if {[set HL_ON_CUR_CHAN [weechat::config_get_plugin hl_on_cur_chan]] eq ""} { weechat::config_set_plugin hl_on_cur_chan 0 set HL_ON_CUR_CHAN 0 } proc config_changed {data option value} { set ::HL_ON_CUR_CHAN $value return $::weechat::WEECHAT_CONFIG_OPTION_SET_OK_CHANGED } proc mark_cmd {data buffer args} { set channel [weechat::buffer_get_string $buffer localvar_channel] if {[weechat::info_get irc_is_channel $channel] eq "1"} { if {[lsearch $::MARK_LIST $channel] == -1} { lappend ::MARK_LIST $channel weechat::print $buffer "channel \"$channel\" was appended to notify list" } else { weechat::print $buffer "channel \"$channel\" already in notify list" } } else { weechat::print $buffer "this command must be executed on channel" } return $::weechat::WEECHAT_RC_OK } proc unmark_cmd {data buffer args} { if {[lindex $args 0] eq "all"} { set ::MARK_LIST [list] weechat::print $buffer "all channels was removed from notify list" return $::weechat::WEECHAT_RC_OK } set channel [weechat::buffer_get_string $buffer localvar_channel] if {[weechat::info_get irc_is_channel $channel] eq "1"} { if {[set index [lsearch $::MARK_LIST $channel]] != -1} { set ::MARK_LIST [lreplace $::MARK_LIST $index $index] weechat::print $buffer "channel \"$channel\" was removed from notify list" } else { weechat::print $buffer "channel \"$channel\" not on notify list" } } else { weechat::print $buffer "this command must be executed on channel" } return $::weechat::WEECHAT_RC_OK } proc smark_cmd {data buffer args} { set channel [weechat::buffer_get_string $buffer localvar_channel] if {[weechat::info_get irc_is_channel $channel] eq "1"} { if {[set index [lsearch $::MARK_LIST $channel]] == -1} { lappend ::MARK_LIST $channel weechat::print $buffer "channel \"$channel\" was appended to notify list" } else { set ::MARK_LIST [lreplace $::MARK_LIST $index $index] weechat::print $buffer "channel \"$channel\" was removed from notify list" } } else { weechat::print $buffer "this command must be executed on channel" } return $::weechat::WEECHAT_RC_OK } proc signal_proc {data signal irc_msg} { if {[regexp {.+@.+\sPRIVMSG\s(#.+)\s:.+} $irc_msg wh channel] == 1} { if {[lsearch $::MARK_LIST $channel] != -1} { set buffer [weechat::current_buffer] if {$channel ne [weechat::buffer_get_string $buffer localvar_channel]} { weechat::print $buffer "$::SCRIPT_NAME: there is new message on $channel" weechat::hook_signal_send weechat_highlight $::weechat::WEECHAT_HOOK_SIGNAL_STRING $channel } else { if {$::HL_ON_CUR_CHAN} { weechat::hook_signal_send weechat_highlight $::weechat::WEECHAT_HOOK_SIGNAL_STRING $channel } } } } return $::weechat::WEECHAT_RC_OK } weechat::hook_command mark {mark current channel to highlight on each message} {} {} {} mark_cmd {} weechat::hook_command unmark {unmark channel(s)} {[all]} {} {} unmark_cmd {} weechat::hook_command smark {unmark channel(s)} {[all]} {} {} smark_cmd {} weechat::hook_signal *,irc_in_PRIVMSG signal_proc {} weechat::hook_config plugins.var.tcl.chan_hl.hl_on_cur_chan config_changed {} weechat-scripts/tcl/rnotify.tcl0000644000175000017500000001052015000014143015607 0ustar manumanu# Remote Notification Script v1.4 # by Gotisch # # With help of this script you can make weechat create notification bubbles # in ubuntu or any other distribution that supports libnotify. # # Changelog: # 1.4 # fixed problem with reserved characters preventing notification (see http://wiki.tcl.tk/1353) (thanks Ongy) # 1.3 # fixed yet more typos and a possible problem with notifications not showing when they should. # 1.2 # fixed small typo that prevented remote notification (thanks Jesse) # 1.1 # added setting: privmessage to customize notifications of messages in query # 1.0 # initial release # # How does it work? # # The script inside weechat will either call libnotify directly, or it will # send the data to the "server" listening on a port which will call the # libnotify executable and create the notification. This "remote" option # is the main use of the script. # # Example 1: Weechat runs on the local pc # /tcl load rnotify.tcl # and set the port # /set plugins.var.tcl.rnotify.port local # # Example 2: Weechat runs on a remote pc and you login via ssh port you # want to use is 4321 # sh location/of/rnotify.tcl 4321 & ssh -R 4321:localhost:4321 username@host # on server you start weechat (or resume screen or whatever). # Then inside weechat # /tcl load rnotify.tcl # and set the port # /set plugins.var.tcl.rnotify.port 4321 # # General Syntax: # In weechat # /set plugins.var.tcl.rnotify.port # To get notifications for private messages set: # /set plugins.var.tcl.rnotify.privmessage [no(default)|all|inactive] # no - no notifications for private messages (besides on highlight) # all - notifications for all private messages # inactive - notifications only for messages that are not the currently active buffer # As script # rnotify.tcl # if no port is given it will listen on 1234. # # Requirements: # libnotify (esp. notify-send executable) # # Possible problems: # It could be other programs send data to the notify port when using remote # mode. This will then lead to the following: either break the script, or # make weird notification bubbles. # \ exec tclsh "$0" ${1+"$@"} if {[namespace exists ::weechat]} { # We have been called inside weechat namespace eval weechat::script::rnotify { weechat::register "rnotify" {Gotisch gotisch@gmail.com} 1.4 GPL3 {Sends highlights to (remote) client} {} {} proc highlight { data buffer date tags displayed highlight prefix message } { set buffername [weechat::buffer_get_string $buffer short_name] if {$buffername != $prefix} { set buffername "$prefix in $buffername" if {$highlight == 0} { return $::weechat::WEECHAT_RC_OK } } else { if {![string equal -nocase [weechat::config_get_plugin privmessage] "all"]} { if {![string equal -nocase [weechat::config_get_plugin privmessage] "inactive"] || [string equal [weechat::buffer_get_string [weechat::current_buffer] short_name] $buffername]} { if {$highlight == 0} { return $::weechat::WEECHAT_RC_OK } } } set buffername "$prefix in query" } notify $buffername $message return $::weechat::WEECHAT_RC_OK } proc notify {title text} { set title "\u200B$title" set text "\u200B$text" if {[weechat::config_get_plugin port] == "local"} { catch { exec notify-send -u normal -c IRC -i gtk-help "$title" "$text" } } else { catch { set sock [socket -async localhost [weechat::config_get_plugin port]] puts $sock [list normal gtk-help $title $text] close $sock } } } weechat::hook_print "" "irc_privmsg" "" 1 [namespace current]::highlight {} } } else { # We probably have been called from the shell set port 1234 if {[llength $argv] == 1} { set port $argv } proc notify_server {port} { set s [socket -server accept $port] puts "Listening on $port for Connections..." vwait forever } proc accept {sock addr port} { fileevent $sock readable [list recieve $sock] } proc recieve {sock} { if {[eof $sock] || [catch {gets $sock line}]} { close $sock } else { foreach {urgency icon title text} $line { exec notify-send -u $urgency -c IRC -i $icon "$title" "$text" } } } notify_server $port } weechat-scripts/tcl/wttr.tcl0000644000175000017500000001132415000014143015120 0ustar manumanu# Copyright (c) 2023 by CrazyCat # # 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 . # # --------------------------------------------- # Adds an item showing weather # # --------------------------------------------- # History # 2023-06-15 : Improved help # 2023-06-14 : Initial release set SCRIPT_VERSION 1.1 set SCRIPT_NAME wttr set SCRIPT_SUMMARY "Adds an item showing weather" set SCRIPT_ARGS "loc |format <1-4|format>|lang " set SCRIPT_ADESC "loc : sets the new location\n\ : example : /wttr loc Paris, France\n\ * format : Formats of the output, can be an integer (predefined formats from 1 to 4) or a string (custom format).\n\ : example : /wttr format %l:+%C+%t+(%f)+%w\n\ -- Main format variables --\n\ : %l : location\n\ : %c / %C / %x: weather condition (icon / textual)\n\ : %t / %f : temperature (actual / feels like)\n\ : %w : wind\n\ -- Predefined formats --\n\ : 1 - %c+%t\n\ : 2 - %c+%t+%w (with icons)\n\ : 3 - %l:+%c+%t\n\ : 4 - %l:%c+%t+%w (with icons)\n\ : More explanation @ https://github.com/chubin/wttr.in#one-line-output\n\ * lang : Defines the lang to use (EN for english, FR for french, ...). Default is your weechat lang.\n\ Think to add the \[wttr\] item to a bar. Example to add it to the status bar:\n\ /eval /set weechat.bar.status.items \"\${weechat.bar.status.items},wttr\")" weechat::register $SCRIPT_NAME {CrazyCat } $SCRIPT_VERSION GPL3 $SCRIPT_SUMMARY {} {} weechat::hook_command wttr $SCRIPT_SUMMARY $SCRIPT_ARGS $SCRIPT_ADESC {loc || format || lang} wttr_cmds {} # Management of settings proc wttr_cmds {data buffer args} { set value [lassign {*}$args cmd] if {$cmd eq "" || [string tolower $cmd] eq "help"} { weechat::command "" "/help wttr" return $::weechat::WEECHAT_RC_OK } set cmd [string tolower $cmd] switch -nocase $cmd { "loc" { if {$value eq ""} { weechat::print $buffer "Use /wttr set loc City" return $weechat::WEECHAT_RC_ERROR } weechat::config_set_plugin city [join $value] } "format" { if {$value eq ""} { weechat::print $buffer "Using default format" set value 4 } weechat::config_set_plugin wformat [join $value] } "lang" { if {$value eq ""} { weechat::print $buffer "Using weechat locale" set value [lindex [split [::weechat::info_get "locale" ""] "_"] 0] } weechat::config_set_plugin lang $value } default { weechat::print $buffer "Usage : /wttr value" return $::weechat::WEECHAT_RC_ERROR } } wttr_timer_cb "" 0 return $::weechat::WEECHAT_RC_OK } # Periodical call proc wttr_timer_cb {data remaining_calls} { set city [string map {" " "%20"} [weechat::config_get_plugin city]] set url "http://wttr.in/$city?format=[weechat::config_get_plugin wformat]&lang=[weechat::config_get_plugin lang]" weechat::hook_process "url:${url}" 5000 "wttr_get_cb" "" return $::weechat::WEECHAT_RC_OK } # Callback when getting datas from wttr.in proc wttr_get_cb { data command rc out err} { global wttr_value if {$out ne ""} { set wttr_value $out weechat::bar_item_update "wttr" } return $::weechat::WEECHAT_RC_OK } # Update of the item proc wttr_show {args} { global wttr_value if {[info exists wttr_value] && $wttr_value ne ""} { return $wttr_value } return "[weechat::config_get_plugin city] : no data" } # Initial settings if {[set city [weechat::config_get_plugin city]] eq ""} { weechat::config_set_plugin city "Paris" } if {[set wformat [weechat::config_get_plugin wformat]] eq ""} { weechat::config_set_plugin wformat 4 } if {[set refresh [weechat::config_get_plugin refresh]] eq ""} { weechat::config_set_plugin refresh 300 } if {[set refresh [weechat::config_get_plugin lang]] eq ""} { set tlang [split [::weechat::info_get "locale" ""] "_"] weechat::config_set_plugin lang [lindex $tlang 0] } weechat::hook_timer [expr [weechat::config_get_plugin refresh]*1000] 60 0 wttr_timer_cb "" weechat::bar_item_new "wttr" "wttr_show" "" weechat-scripts/tcl/xosdnotify.tcl0000644000175000017500000001207115000014143016326 0ustar manumanu# Copyright (c) 2010-2013 by Dmitry Kobylin # # 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 . # # show private/highlight messages with OSD # # 2013-03-28, Dmitry Kobylin : # version 0.2 # * add /xosdtest command # * add config change hook # 2010-09-29, Dmitry Kobylin : # version 0.1 # # set SCRIPT xosdnotify set VERSION 0.2 weechat::register $SCRIPT {Dmitry Kobylin } $VERSION GPL3 {show OSD on highlight/private message} {} {} package require tclxosd # default values set default_blink on ;# blink of OSD set default_blink_interval 700 ;# interval of blinking set default_blink_count 4 ;# count of blinks before OSD hides, don't set to 0 set default_lines 1 ;# number of lines in OSD that can be shown simultaneously set default_align {left bottom} ;# align of OSD set default_offset {16 16} ;# padding of OSD from screen edge set default_font -*-fixed-*-*-*-*-*-200-*-*-*-*-*-* ;# font of OSD set default_encoding utf-8 set default_color #ffff00 # check config and set default values if necessary if {[weechat::config_get_plugin blink] eq ""} {weechat::config_set_plugin blink $default_blink} if {[weechat::config_get_plugin blink_interval] eq ""} {weechat::config_set_plugin blink_interval $default_blink_interval} if {[weechat::config_get_plugin blink_count] eq ""} {weechat::config_set_plugin blink_count $default_blink_count} if {[weechat::config_get_plugin lines] eq ""} {weechat::config_set_plugin lines $default_lines} if {[weechat::config_get_plugin align] eq ""} {weechat::config_set_plugin align $default_align} if {[weechat::config_get_plugin offset] eq ""} {weechat::config_set_plugin offset $default_offset} if {[weechat::config_get_plugin font] eq ""} {weechat::config_set_plugin font $default_font} if {[weechat::config_get_plugin encoding] eq ""} {weechat::config_set_plugin encoding $default_encoding} if {[weechat::config_get_plugin color] eq ""} {weechat::config_set_plugin color $default_color} # create xosd command set osd [xosd::create [weechat::config_get_plugin lines]] $osd align {*}[split [weechat::config_get_plugin align]] $osd offset {*}[split [weechat::config_get_plugin offset]] $osd font [weechat::config_get_plugin font] $osd color [weechat::config_get_plugin color] proc private_msg {osd signal msg} { if {[regexp {:(.+)!.+@.+\s+PRIVMSG\s.+:(.+)} \ [weechat::iconv_from_internal [weechat::config_get_plugin encoding] $msg] -> nick msg]} { $osd text 0 "$nick: $msg" } set n [expr {[weechat::config_get_plugin blink_count] * 2}] weechat::hook_timer [weechat::config_get_plugin blink_interval] 0 $n timer [list $osd [incr ::key]] return $::weechat::WEECHAT_RC_OK } proc highlight_msg {osd signal msg} { $osd text 0 [weechat::iconv_from_internal [weechat::config_get_plugin encoding] $msg] set n [expr {[weechat::config_get_plugin blink_count] * 2}] weechat::hook_timer [weechat::config_get_plugin blink_interval] 0 $n timer [list $osd [incr ::key]] return $::weechat::WEECHAT_RC_OK } proc osd_test {osd buffer args} { if {[string length [set s [join $args]]] == 0} { set s test } $osd text 0 [weechat::iconv_from_internal [weechat::config_get_plugin encoding] $s] set n [expr {[weechat::config_get_plugin blink_count] * 2}] weechat::hook_timer [weechat::config_get_plugin blink_interval] 0 $n timer [list $osd [incr ::key]] } proc timer {data count} { lassign $data osd key # don't response to old timer if {$key < $::key} { return $::weechat::WEECHAT_RC_OK } if {[weechat::config_get_plugin blink] != "off"} { if {[$osd onscreen]} { $osd hide } else { $osd show } } if {$count == 0} { $osd hide } return $::weechat::WEECHAT_RC_OK } proc config_changed {osd option value} { $osd align {*}[split [weechat::config_get_plugin align]] $osd offset {*}[split [weechat::config_get_plugin offset]] $osd font [weechat::config_get_plugin font] $osd color [weechat::config_get_plugin color] return $::weechat::WEECHAT_CONFIG_OPTION_SET_OK_CHANGED } set ::key 0 # hook signals weechat::hook_signal irc_pv private_msg $osd weechat::hook_signal weechat_highlight highlight_msg $osd # hook test command weechat::hook_command xosdtest {show test message with OSD} {msg} {} {} osd_test $osd # hook config change weechat::hook_config plugins.var.tcl.$SCRIPT\.* config_changed $osd weechat-scripts/tcl/ipinfo.tcl0000644000175000017500000001006715000014143015407 0ustar manumanu# Copyright (c) 2022 by CrazyCat # # 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 . # # --------------------------------------------- # Retrieve informations about an IP # # Usage : /ipinfo 132.54.12.32 # --------------------------------------------- # History # 2022-02-24 : Initial release set SCRIPT_VERSION 1.0 set SCRIPT_NAME ipinfo weechat::register $SCRIPT_NAME {CrazyCat } $SCRIPT_VERSION GPL3 {retrieve informations about an IP} {} {} weechat::hook_command ipinfo {retrieve informations about an IP} {} {Do /set *ipinfo* for settings} {} ipinfo {} if {[set output [weechat::config_get_plugin output]] eq ""} { weechat::config_set_plugin output "CITY (COUNTRY) - ISP" } if {[set output [weechat::config_get_plugin lang]] eq ""} { weechat::config_set_plugin lang "en" } # Small variables for utility set mask(ipv4) {^(?:25[0-5]|2[0-4]\d|[0-1]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d{1,2})){3}$} set mask(ipv6) {^([[:xdigit:]]{1,4}(?::[[:xdigit:]]{1,4}){7}|::|:(?::[[:xdigit:]]{1,4}){1,6}|[[:xdigit:]]{1,4}:(?::[[:xdigit:]]{1,4}){1,5}|(?:[[:xdigit:]]{1,4}:){2}(?::[[:xdigit:]]{1,4}){1,4}|(?:[[:xdigit:]]{1,4}:){3}(?::[[:xdigit:]]{1,4}){1,3}|(?:[[:xdigit:]]{1,4}:){4}(?::[[:xdigit:]]{1,4}){1,2}|(?:[[:xdigit:]]{1,4}:){5}:[[:xdigit:]]{1,4}|(?:[[:xdigit:]]{1,4}:){1,6}:)$} # this will be used later variable private {"0.0.0.0/8" "10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" \ "192.0.0.0/24" "192.0.2.0/24" "192.88.99.0/24" "162.168.0.0/16" "192.168.18.0.0/15" "198.51.100.0/24" \ "203.0.113.0/24" "224.0.0.4/24" "233.252.0.0/24" "240.0.0.0/4" "255.255.255.255/32"} proc ipinfo {data buffer args} { set ip [string trim [join $args]] set ::ipinfo(buffer) $buffer if {$ip eq ""} { weechat::print $buffer "Error : Syntax is /ipinfo ip.to.check" return $::weechat::WEECHAT_RC_ERROR } if {![isip $ip]} { weechat::print $buffer [format "*** %s$ip%s is not a valid IP address" [weechat::color "red"] [weechat::color "default"]] return $::weechat::WEECHAT_RC_ERROR } weechat::hook_process "url:http://ip-api.com/json/$ip?fields=status,message,continent,country,city,zip,lat,lon,timezone,isp,org,reverse,mobile,proxy,hosting,query&lang=[weechat::config_get_plugin lang]" 5000 "ipinfo_process_cb" "" return $::weechat::WEECHAT_RC_OK } proc ipinfo_process_cb {data command rc out err} { set infos [json2dict $out] if {![dict exists $infos status]} { weechat::print $::ipinfo(buffer) [format "*** %sERROR%s : Cannot retrieve informations from ip-api.com" [weechat::color "red"] [weechat::color "default"]] return $::weechat::WEECHAT_RC_ERROR } if {[dict get $infos status]=="fail"} { weechat::print $::ipinfo(buffer) [format "*** %sERROR%s : [dict get $infos message]" [weechat::color "red"] [weechat::color "default"]] return $::weechat::WEECHAT_RC_ERROR } set ip [dict get $infos query] set myout [string map [list "CITY" [dict get $infos city]\ "COUNTRY" [dict get $infos country]\ "ISP" [dict get $infos isp]\ ] [weechat::config_get_plugin output]] weechat::print $::ipinfo(buffer) [format "*** IP infos for %s$ip%s: $myout" [weechat::color "red"] [weechat::color "default"]] return $::weechat::WEECHAT_RC_OK } proc isip { ip } { if {[regexp $::mask(ipv4) $ip ipv4]} { return true } elseif {[regexp $::mask(ipv6) $ip ipv6]} { return true } else { return false } } proc json2dict {JSONtext} { string range [string trim [string trimleft [string map {\t {} \n {} \r {} , { } : { } \[ \{ \] \}} $JSONtext] {\uFEFF}]] 1 end-1 } weechat-scripts/lua/0000755000175000017500000000000015000014144013413 5ustar manumanuweechat-scripts/lua/emoji.lua0000644000175000017500000011150015000014144015217 0ustar manumanu-- 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 5, 2020-05-09, FlashCode: * remove obsolete comment on weechat_print modifier data 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 = "5" 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) -- 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/lua/nick_complete_wrapper.lua0000644000175000017500000001421715000014144020477 0ustar manumanu--[[ 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/lua/oldswarner.lua0000644000175000017500000001052215000014144016276 0ustar manumanu-- 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/lua/http_item.lua0000644000175000017500000000672415000014144016124 0ustar manumanu-- 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/lua/text_effects.lua0000644000175000017500000000514315000014143016603 0ustar manumanu-- 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/lua/mpdbitl.lua0000644000175000017500000004053415000014144015557 0ustar manumanu--[[ -- 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/lua/pastebuf.lua0000644000175000017500000012640415000014144015736 0ustar manumanu--[[ -- 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/lua/urlselect.lua0000644000175000017500000013273015000014144016126 0ustar manumanu--[[ 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.5", 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