From ddac8e5c72b4ac511f3ce63119eba541159b16ae Mon Sep 17 00:00:00 2001 From: Eric Renfro Date: Sat, 5 Jan 2019 13:45:43 -0500 Subject: [PATCH] Added HexChat config and vscode alias --- .config/hexchat/addons/buffextras.lua | 49 +++++++++++ .../hexchat/addons/masshighlightignore.lua | 58 +++++++++++++ .config/hexchat/addons/mymsg.lua | 66 +++++++++++++++ .config/hexchat/addons/playback.lua | 77 +++++++++++++++++ .config/hexchat/addons/pytabcomplete.py | 78 ++++++++++++++++++ .config/hexchat/addons/smartparts.lua | 82 +++++++++++++++++++ .config/hexchat/addons/statuscolor.lua | 52 ++++++++++++ .config/hexchat/addons/zncbuffer.lua | 47 +++++++++++ .config/hexchat/colors.conf | 42 ++++++++++ .config/hexchat/notify.conf | 0 .config/hexchat/replace.conf | 54 ++++++++++++ .local/dotfiles/environment/vscode.zsh | 1 + 12 files changed, 606 insertions(+) create mode 100644 .config/hexchat/addons/buffextras.lua create mode 100644 .config/hexchat/addons/masshighlightignore.lua create mode 100644 .config/hexchat/addons/mymsg.lua create mode 100644 .config/hexchat/addons/playback.lua create mode 100644 .config/hexchat/addons/pytabcomplete.py create mode 100644 .config/hexchat/addons/smartparts.lua create mode 100644 .config/hexchat/addons/statuscolor.lua create mode 100644 .config/hexchat/addons/zncbuffer.lua create mode 100644 .config/hexchat/colors.conf create mode 100644 .config/hexchat/notify.conf create mode 100644 .config/hexchat/replace.conf create mode 100644 .local/dotfiles/environment/vscode.zsh diff --git a/.config/hexchat/addons/buffextras.lua b/.config/hexchat/addons/buffextras.lua new file mode 100644 index 0000000..d00cb42 --- /dev/null +++ b/.config/hexchat/addons/buffextras.lua @@ -0,0 +1,49 @@ +-- SPDX-License-Identifier: MIT +hexchat.register('Buffextras', '1', "Format messages from ZNC's buffextras module") + +local function strip_brackets (str) + return str:sub(2, #str - 1) +end + +hexchat.hook_server_attrs('PRIVMSG', function (word, word_eol, attrs) + if not word[1]:match('^:%*buffextras!') then + return + end + + local channel = word[3] + local nick, host = word[4]:match('^:([^!]+)!(.*)$') + + local function is_event (event) + return word_eol[5]:sub(1, #event) == event + end + + local function emit (event, ...) + hexchat.emit_print_attrs(attrs, event, ...) + end + + if is_event('joined') then + emit('Join', nick, channel, host) + elseif is_event('quit with message') then + emit('Quit', nick, strip_brackets(word_eol[8]), host) + elseif is_event('parted with message') then + local reason = strip_brackets(word_eol[8]) + if reason ~= '' then + emit('Part with Reason', nick, host, channel, reason) + else + emit('Part', nick, host, channel) + end + elseif is_event('is now known as') then + emit('Change Nick', nick, word[9]) + elseif is_event('changed the topic to') then + emit('Topic Change', nick, word_eol[9], channel) + elseif is_event('kicked') then + emit('Kick', nick, word[6], channel, strip_brackets(word_eol[8])) + elseif is_event('set mode') then + emit('Raw Modes', nick, string.format('%s %s', channel, word_eol[7])) + else + return -- Unknown event + end + + return hexchat.EAT_ALL +end, hexchat.PRI_HIGH) + diff --git a/.config/hexchat/addons/masshighlightignore.lua b/.config/hexchat/addons/masshighlightignore.lua new file mode 100644 index 0000000..6b66725 --- /dev/null +++ b/.config/hexchat/addons/masshighlightignore.lua @@ -0,0 +1,58 @@ +-- SPDX-License-Identifier: MIT +hexchat.register('MassHighlightIgnore', '3', 'Ignore mass highlight spam') + +if unpack == nil then + unpack = table.unpack -- fix lua 5.2 +end + +local MAX_COUNT = 4 + +-- http://lua-users.org/wiki/SplitJoin +local function split(str) + local t = {} + for i in string.gmatch(str, "%S+") do + t[#t + 1] = i + end + return t +end + +local function nick_in_list (nick, list) + for _, word in pairs(list) do + if hexchat.nickcmp(word, nick) == 0 then + return true + end + end + return false +end + +local function is_mass_highlight (message) + local count = 0 + local words = split(message) + + for user in hexchat.props.context:iterate('users') do + if nick_in_list(user.nick, words) then + count = count + 1 + if count == MAX_COUNT then + return true + end + end + end + + return false +end + +local function ignore_mass_hilight (args, attrs, event) + if is_mass_highlight(args[2]) then + hexchat.emit_print_attrs(attrs, event, unpack(args)) + return hexchat.EAT_ALL + end +end + +hexchat.hook_print_attrs('Channel Msg Hilight', function (args, attrs) + return ignore_mass_hilight(args, attrs, 'Channel Message') +end, hexchat.PRI_HIGHEST) + +hexchat.hook_print('Channel Action Hilight', function (args, attrs) + return ignore_mass_hilight(args, attrs, 'Channel Action') +end, hexchat.PRI_HIGHEST) + diff --git a/.config/hexchat/addons/mymsg.lua b/.config/hexchat/addons/mymsg.lua new file mode 100644 index 0000000..7a609f7 --- /dev/null +++ b/.config/hexchat/addons/mymsg.lua @@ -0,0 +1,66 @@ +-- SPDX-License-Identifier: MIT +hexchat.register('MyMessage', '2', 'Properly show your own messages in ZNC playback') + +local function get_server_ctx() + local id = hexchat.prefs['id'] + for chan in hexchat.iterate('channels') do + if chan.type == 1 and chan.id == id then + return chan.context + end + end + return hexchat.props.context +end + +hexchat.hook_print('Capability List', function (args) + if args[2]:find('znc.in/self%-message') then + hexchat.command('CAP REQ znc.in/self-message') + + local ctx = get_server_ctx() + hexchat.hook_timer(1, function () + -- Emit right after this event + if ctx:set() then + hexchat.emit_print('Capability Request', 'znc.in/self-message') + end + end) + end +end) + +local function prefix_is_channel (prefix) + local chantypes = hexchat.props['chantypes'] + for i = 1, #chantypes do + if chantypes:sub(i, i) == prefix then + return true + end + end + return false +end + +hexchat.hook_server_attrs('PRIVMSG', function (word, word_eol, attrs) + -- Only want private messages + if prefix_is_channel(word[3]:sub(1, 1)) then + return + end + + local mynick = hexchat.get_info('nick') + local sender = word[1]:match('^:([^!]+)') + local recipient = word[3] + + if hexchat.nickcmp(sender, mynick) == 0 and hexchat.nickcmp(recipient, mynick) ~= 0 then + hexchat.command('query -nofocus ' .. recipient) + local ctx = hexchat.find_context(hexchat.get_info('network'), recipient) + local message = word_eol[4] + if message:sub(1, 1) == ':' then + message = message:sub(2) + end + + if message:sub(1, 8) == '\001ACTION ' then + local action = message:sub(9, #message-1) + ctx:emit_print_attrs(attrs, 'Your Action', mynick, action) + else + ctx:emit_print_attrs(attrs, 'Your Message', mynick, message) + end + + return hexchat.EAT_ALL + end +end) + diff --git a/.config/hexchat/addons/playback.lua b/.config/hexchat/addons/playback.lua new file mode 100644 index 0000000..661dbe9 --- /dev/null +++ b/.config/hexchat/addons/playback.lua @@ -0,0 +1,77 @@ +-- SPDX-License-Identifier: MIT +local lgi = require('lgi') +local GLib = lgi.require('GLib') + +hexchat.register('Playback', '1', "Integration with ZNC's Playback module") + +--[[ + This should behave like this: + + On connect (end of MOTD): + if new server, play all + if old server, play all after latest timestamp + On close query: + clear all + On new message: + update latest timestamp +]] + +local CAP_NAME = 'znc.in/playback' +local servers = {} -- Table of id to timestamp + +-- Request capability +hexchat.hook_print('Capability List', function (args) + if args[2]:find(CAP_NAME) then + hexchat.command('quote CAP REQ :' .. CAP_NAME) + + local ctx = hexchat.props.context + hexchat.hook_timer(1, function () + -- Emit this event right after the current one + if ctx:set() then + hexchat.emit_print('Capability Request', CAP_NAME) + end + end) + end +end) + +-- Capability supported +hexchat.hook_print('Capability Acknowledgement', function (args) + local id = hexchat.prefs['id'] + if args[2]:find(CAP_NAME) and not servers[id] then + servers[id] = 0 -- New server + end +end) + +-- On successful connection play history +hexchat.hook_server('376', function (word, word_eol) + local timestamp = servers[hexchat.prefs['id']] + + if timestamp then + hexchat.command('quote PRIVMSG *playback :play * ' .. tostring(timestamp)) + end +end) + +-- Remove history when closed +hexchat.hook_print('Close Context', function (args) + local id = hexchat.prefs['id'] + local timestamp = servers[id] + if not timestamp then + return + end + + local ctx_type = hexchat.props['type'] + if ctx_type == 3 then -- Dialog + hexchat.command('quote PRIVMSG *playback :clear ' .. hexchat.get_info('channel')) + elseif ctx_type == 1 then -- Server + servers[id] = nil + end +end) + +-- Store the timestamp of the latest message on the server +hexchat.hook_server_attrs('PRIVMSG', function (word, word_eol, attrs) + local id = hexchat.prefs['id'] + if servers[id] then + servers[id] = GLib.get_real_time() / 1000000 -- epoch in seconds with milisecond precision UTC + end +end, hexchat.PRI_LOWEST) + diff --git a/.config/hexchat/addons/pytabcomplete.py b/.config/hexchat/addons/pytabcomplete.py new file mode 100644 index 0000000..6331cb8 --- /dev/null +++ b/.config/hexchat/addons/pytabcomplete.py @@ -0,0 +1,78 @@ +from __future__ import print_function +import hexchat + +__module_name__ = "PythonTabComplete" +__module_author__ = "TingPing, FichteFoll" +__module_version__ = "0.3" +__module_description__ = "Tab-completes module attributes in Interactive Console" + +last_index = None +last_completes = None +last_text = None +last_pos = None + +exec_scope = {} + + +def keypress_cb(word, word_eol, userdata): + global last_index + global last_completes + global last_text + global last_pos + + if not word[0] == '65289': # Tab + return + if not hexchat.get_info('channel') == '>>python<<': + return + shift_key_is_down = bool(int(word[1]) & 1) # check if shift modifier is hold + + text = hexchat.get_info('inputbox') + pos = hexchat.get_prefs('state_cursor') + if not text: + return + + base = text[:pos].split(' ')[-1] + module, _, prefix = base.rpartition('.') + if not module: + # can not dir() the console's interpreter state sadly + return + + if last_text != text or last_pos != pos: + # new completion context + try: + exec('import {}'.format(module), exec_scope) # Has to be imported to dir() it + completions = eval('dir({})'.format(module), exec_scope) + except (NameError, SyntaxError, ImportError): + return + completions = [c for c in completions if c.startswith(prefix)] + if not completions: + return + index = 0 + else: + # same context, insert next completion + completions = last_completes + direction = 1 if not shift_key_is_down else -1 + index = (last_index + direction) % len(completions) + + complete_text = completions[index] + + new_text = text[:pos - len(prefix)] + complete_text + text[pos:] + new_pos = pos - len(prefix) + len(complete_text) + + hexchat.command('settext {}'.format(new_text)) + hexchat.command('setcursor {}'.format(new_pos)) + + last_index = index + last_completes = completions + last_text = new_text + last_pos = new_pos + + +def unload_cb(userdata): + print(__module_name__, 'version', __module_version__, 'unloaded.') + + +hexchat.hook_print('Key Press', keypress_cb) +hexchat.hook_unload(unload_cb) +print(__module_name__, 'version', __module_version__, 'loaded.') + diff --git a/.config/hexchat/addons/smartparts.lua b/.config/hexchat/addons/smartparts.lua new file mode 100644 index 0000000..2299362 --- /dev/null +++ b/.config/hexchat/addons/smartparts.lua @@ -0,0 +1,82 @@ +-- SPDX-License-Identifier: MIT +hexchat.register('SmartParts', '1', 'Intelligently hide parts, joins, modes, and nick changes') + +local TIME_THRESHOLD = 60 * 5 -- in seconds + +local function check_lasttalk (nick) + local nick = hexchat.strip(nick) + for user in hexchat.iterate('users') do + if hexchat.nickcmp(nick, user.nick) == 0 then + if os.time() - user.lasttalk > TIME_THRESHOLD then + return hexchat.EAT_HEXCHAT + else + return hexchat.EAT_NONE + end + end + end + + return hexchat.EAT_HEXCHAT +end + +local function check_you (nick) + return hexchat.nickcmp(hexchat.get_info('nick'), nick) == 0 +end + +local function check_notify (nick) + local nick = hexchat.strip(nick) + for user in hexchat.iterate('notify') do + if user.nick == nick then + return true + end + end + + return false +end + + +hexchat.hook_print('Join', function (args) + if check_notify (args[1]) then + return hexchat.EAT_NONE + else + return hexchat.EAT_HEXCHAT + end +end, hexchat.PRI_LOW) + +-- hexchat.hook_print('Change Nick', function (args) +-- if check_notify(args[1]) or check_notify(args[2]) then +-- return hexchat.EAT_NONE +-- end +-- +-- return check_lasttalk(args[1]) +-- end, hexchat.PRI_LOW) + +hexchat.hook_print('Raw Modes', function (args) + if check_you(args[1]) or check_notify(args[1]) then + return hexchat.EAT_NONE + end + + -- TODO: Parse targets + + return check_lasttalk(args[1]) +end, hexchat.PRI_LOW) + +for _, event in pairs({'Quit', 'Part', 'Part with Reason'}) do + hexchat.hook_print(event, function (args) + if check_notify(args[1]) then + return hexchat.EAT_NONE + end + + return check_lasttalk(args[1]) + end, hexchat.PRI_LOW) +end + +for _, event in pairs({'Channel Operator', 'Channel Voices'}) do + hexchat.hook_print(event, function (args) + if check_you(args[1]) or check_you(args[2]) or check_notify(args[2]) then + return hexchat.EAT_NONE + end + + return check_lasttalk(args[2]) + end, hexchat.PRI_LOW) +end + diff --git a/.config/hexchat/addons/statuscolor.lua b/.config/hexchat/addons/statuscolor.lua new file mode 100644 index 0000000..af2913a --- /dev/null +++ b/.config/hexchat/addons/statuscolor.lua @@ -0,0 +1,52 @@ +-- SPDX-License-Identifier: MIT +hexchat.register('StatusColor', '1', 'Color nicks based upon user modes') + +-- TODO: Update these to reflect default theme +local MODES = { + ['+'] = '24', + ['%'] = '28', + ['@'] = '19', + ['&'] = '21', + ['~'] = '22', +} + +local edited = false +local function on_message (args, attrs, event) + if edited then + return hexchat.EAT_NONE + end + + local color = MODES[args[3]] + if not color then + return hexchat.EAT_NONE + end + + -- In > 2.12.3 we need to be explicit about color changes + if event:sub(-7, -1) == 'Hilight' then + hexchat.command('gui color 3') + elseif event:sub(1, 4) ~= 'Your' then + hexchat.command('gui color 2') + end + + edited = true + args[1] = '\003' .. color .. hexchat.strip(args[1]) .. '\00399' + args[3] = '\003' .. color .. args[3] .. '\00399' + hexchat.emit_print_attrs(attrs, event, unpack(args)) + edited = false + + return hexchat.EAT_ALL +end + +for _, event in pairs({ + 'Channel Message', + 'Channel Action', + 'Channel Msg Hilight', + 'Channel Action Hilight', + 'Your Message', + 'Your Action' +}) do + hexchat.hook_print_attrs(event, function (args, attrs) + return on_message(args, attrs, event) + end, hexchat.PRI_LOW) +end + diff --git a/.config/hexchat/addons/zncbuffer.lua b/.config/hexchat/addons/zncbuffer.lua new file mode 100644 index 0000000..e20cbf1 --- /dev/null +++ b/.config/hexchat/addons/zncbuffer.lua @@ -0,0 +1,47 @@ +-- SPDX-License-Identifier: MIT +hexchat.register('ZNC Buffers', '1', 'Add menu options to manage ZNC buffers') + +-- Add menus +hexchat.command('menu -p4 add "$TAB/ZNC"') +hexchat.command('menu add "$TAB/ZNC/Clear Buffer" ".zncclearbuffer %s"') +hexchat.command('menu add "$TAB/ZNC/Play Buffer" "znc playbuffer %s"') +hexchat.hook_unload(function () hexchat.command('menu del "$TAB/ZNC') end) + + +-- Ignore our own actions +local recently_cleared = {} + +hexchat.hook_command('.zncclearbuffer', function(word, word_eol) + local name = word[2] + + -- Ignore znc queries + if name:sub(1, 1) ~= '*' then + recently_cleared[name] = true + hexchat.command('znc clearbuffer ' .. name) + end + + return hexchat.EAT_ALL +end) + +hexchat.hook_server('PRIVMSG', function(word, word_eol) + local cleared_channel = word_eol[1]:match('^:%*status!znc@znc.in [^:]+:%[%d+] buffers matching %[([^%]]+)] have been cleared$') + + if cleared_channel and recently_cleared[cleared_channel] then + recently_cleared[cleared_channel] = nil + return hexchat.EAT_ALL + end +end) + +hexchat.hook_command('zncclosepm', function (word, word_eol) + local id = hexchat.props.id + + for chan in hexchat.iterate('channels') do + if chan.id == id and chan.type == 3 then + hexchat.command('.zncclearbuffer ' .. chan.channel) + chan.context:command('close') + end + end + + return hexchat.EAT_ALL +end) + diff --git a/.config/hexchat/colors.conf b/.config/hexchat/colors.conf new file mode 100644 index 0000000..8e636e2 --- /dev/null +++ b/.config/hexchat/colors.conf @@ -0,0 +1,42 @@ +color_0 = d3d3 d7d7 cfcf +color_1 = 2e2e 3434 3636 +color_2 = 3434 6565 a4a4 +color_3 = 4e4e 9a9a 0606 +color_4 = cccc 0000 0000 +color_5 = 8f8f 3939 0202 +color_6 = 5c5c 3535 6666 +color_7 = cece 5c5c 0000 +color_8 = c4c4 a0a0 0000 +color_9 = 7373 d2d2 1616 +color_10 = 1111 a8a8 7979 +color_11 = 5858 a1a1 9d9d +color_12 = 5757 7979 9e9e +color_13 = a0d0 42d4 6562 +color_14 = 5555 5757 5353 +color_15 = 8888 8a8a 8585 +color_16 = d3d3 d7d7 cfcf +color_17 = 2e2e 3434 3636 +color_18 = 3434 6565 a4a4 +color_19 = 4e4e 9a9a 0606 +color_20 = cccc 0000 0000 +color_21 = 8f8f 3939 0202 +color_22 = 5c5c 3535 6666 +color_23 = cece 5c5c 0000 +color_24 = c4c4 a0a0 0000 +color_25 = 7373 d2d2 1616 +color_26 = 1111 a8a8 7979 +color_27 = 5858 a1a1 9d9d +color_28 = 5757 7979 9e9e +color_29 = a0d0 42d4 6562 +color_30 = 5555 5757 5353 +color_31 = 8888 8a8a 8585 +color_256 = d3d3 d7d7 cfcf +color_257 = 2020 4a4a 8787 +color_258 = bfff bfff bfff +color_259 = 0000 0000 0000 +color_260 = 8f8f 3939 0202 +color_261 = 3434 6565 a4a4 +color_262 = 4e4e 9a9a 0606 +color_263 = cece 5c5c 0000 +color_264 = 8888 8a8a 8585 +color_265 = a4a4 0000 0000 diff --git a/.config/hexchat/notify.conf b/.config/hexchat/notify.conf new file mode 100644 index 0000000..e69de29 diff --git a/.config/hexchat/replace.conf b/.config/hexchat/replace.conf new file mode 100644 index 0000000..868ae0d --- /dev/null +++ b/.config/hexchat/replace.conf @@ -0,0 +1,54 @@ +NAME teh +CMD the + +NAME :thumbsup: +CMD 👍 + +NAME :pb: +CMD pastebin.com is frowned upon due to many issues they themselves have caused. Pastes being reformatted, malvertising, adblock blocking, being blocked due to many reasons. See /topic for the channel's official pastebin. + +NAME :ok: +CMD 👌 + +NAME :penguin: +CMD 🐧 + +NAME :thumbsdown: +CMD 👎 + +NAME :clap: +CMD 👏 + +NAME :fist: +CMD ✊ + +NAME :hand: +CMD ✋ + +NAME :this: +CMD ☝️ + +NAME :pointleft: +CMD 👈 + +NAME :pointright: +CMD 👉 + +NAME :pointdown: +CMD 👇 + +NAME :pointup: +CMD 👆 + +NAME :shush: +CMD 🤫 + +NAME :thinking: +CMD 🤔 + +NAME :fearful: +CMD 😨 + +NAME :scream: +CMD 😱 + diff --git a/.local/dotfiles/environment/vscode.zsh b/.local/dotfiles/environment/vscode.zsh new file mode 100644 index 0000000..a6810a7 --- /dev/null +++ b/.local/dotfiles/environment/vscode.zsh @@ -0,0 +1 @@ +alias code="flatpak run com.visualstudio.code"