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