From e0330cb6feb7800608186d9374a99a9f6ab5dd63 Mon Sep 17 00:00:00 2001 From: cos Date: Sun, 2 Oct 2022 23:58:50 +0200 Subject: Initial commit --- irssi/scripts/micmot.pl | 90 ++++++++++++++++++++++++++++++++++++++++++++++ lib/micmot-irssi-wrapper | 7 ++++ lib/micmot-menu-pane | 73 +++++++++++++++++++++++++++++++++++++ lib/micmot-weechat-wrapper | 7 ++++ lib/tmux-micmot.conf | 2 ++ micmot | 17 +++++++++ weechat/python/micmot.py | 82 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 278 insertions(+) create mode 100644 irssi/scripts/micmot.pl create mode 100755 lib/micmot-irssi-wrapper create mode 100755 lib/micmot-menu-pane create mode 100755 lib/micmot-weechat-wrapper create mode 100644 lib/tmux-micmot.conf create mode 100755 micmot create mode 100644 weechat/python/micmot.py diff --git a/irssi/scripts/micmot.pl b/irssi/scripts/micmot.pl new file mode 100644 index 0000000..1ff8f87 --- /dev/null +++ b/irssi/scripts/micmot.pl @@ -0,0 +1,90 @@ +#!/usr/bin/perl +# +# Irssi script to display buffer activity in tmux pane name. +# +# Ideally one single feature complete chat client should be used, but this +# workaround makes life a bit more bearably in our contemporary world requiring +# multiple chat clients. +# +# Requires something like: `F=~/.irssi/micmot-fifo; mkfifo $F; tail -f $F &` +# +# Also requires ":set-option allow-rename on" in the tmux buffer. + +use strict; +use vars qw ($VERSION %IRSSI); +use 5.32.0; + +use Irssi; + +$VERSION = '0.1.0'; +%IRSSI = ( + authors => 'cos', + contact => '|cos|', + description => 'Abusing tmux pane names for displaying channel activity.', + license => 'MIT', + name => 'micmot', +); + +my $TMUX_FIFO = $ENV{'IRSSI_TMUX_FIFO'}; +$TMUX_FIFO = $ENV{'HOME'}.'/.irssi/micmot-fifo' unless $TMUX_FIFO; + +my $PANE_NAME = $ENV{'IRSSI_TMUX_PANE'}; +$PANE_NAME = 'irssi' unless $PANE_NAME; + +sub set_pane_title { + my ( $title ) = @_; + + my $FILE_HANDLE; + open $FILE_HANDLE, '>>', $TMUX_FIFO or return; + printf($FILE_HANDLE "%c]2;%s%c\\", 0x1b, $title, 0x1b); + close $FILE_HANDLE; +} + +sub set_pane_name { + my ( $name ) = @_; + + my $FILE_HANDLE; + open $FILE_HANDLE, '>>', $TMUX_FIFO or return; + printf($FILE_HANDLE "%ck%s%c\\", 0x1b, $name, 0x1b); + close $FILE_HANDLE; +} + +sub highlight_pane { + my $FILE_HANDLE; + open $FILE_HANDLE, '>>', $TMUX_FIFO or return; + printf($FILE_HANDLE "\x07"); + close $FILE_HANDLE; +} + +sub activity_to_tmux { + my $active_win = Irssi::active_win() or return; + my $active_win_refnum = $active_win->{'refnum'} or return; + + my @windows = Irssi::windows() or return; + my $tmux = ""; + for ( @windows ) { + # Skip the currently active window. + next if $_->{'refnum'} eq $active_win_refnum; + + # Include any windows with data_level 'msg' or 'highlight'. + if ($_->{'active'}->{'data_level'} ge 2) { + if (length($tmux) > 0) { + $tmux .= ","; + } + $tmux .= $_->{'active'}->{'visible_name'}; + } + } + + set_pane_name( $tmux ? "[" . $tmux =~ s/[^.,#0-9A-Za-z-]+//rg . "]" : + $PANE_NAME ); + if ( $tmux ) { + highlight_pane(); + } +} + +say qq($IRSSI{name} $VERSION using "$TMUX_FIFO"); +set_pane_name( $PANE_NAME ); +set_pane_title( $PANE_NAME ); + +Irssi::signal_add 'window activity' => \&activity_to_tmux; +Irssi::signal_add 'window changed' => \&activity_to_tmux; diff --git a/lib/micmot-irssi-wrapper b/lib/micmot-irssi-wrapper new file mode 100755 index 0000000..60869fe --- /dev/null +++ b/lib/micmot-irssi-wrapper @@ -0,0 +1,7 @@ +#!/bin/sh -eu + +_fifo="${IRSSI_TMUX_FIFO:-${HOME}/.irssi/micmot-fifo}" + +mkfifo "${_fifo}" +tail -f "${_fifo}" & +irssi diff --git a/lib/micmot-menu-pane b/lib/micmot-menu-pane new file mode 100755 index 0000000..0b4900e --- /dev/null +++ b/lib/micmot-menu-pane @@ -0,0 +1,73 @@ +#!/usr/bin/sh -eu + +_script_name='micmot' + +_micmot_menu_i_cmd='micmot-irssi-wrapper irssi' +_micmot_menu_i_desc='Launch irssi as current user' +_micmot_menu_w_cmd='micmot-weechat-wrapper weechat' +_micmot_menu_w_desc='Launch weechat as current user' +_micmot_menu_d_cmd='sudo -u bar WEECHAT_TMUX_PANE=foo + `which micmot-weechat-wrapper` weechat' +_micmot_menu_d_desc='Launch weechat for foo as user bar' + +text_width() { + IFS='' + echo "$@" | while read -r _line; do + echo ${#_line} + done | sort -n | tail -1 + unset IFS +} + +micmot_banner() { + _micmot_banner="$( figlet -f slant "${_script_name}" )" || return 0 + _text_width=$( text_width "$_micmot_banner" ) || return 0 + _terminal_width=$( tput cols ) || return 0 + + _padding=$( printf "%$(( (_terminal_width - _text_width) / 2 ))s" ' ' ) + IFS='' + echo "$_micmot_banner" | while read -r _line; do + echo "${_padding}${_line}" + done + unset IFS + + unset _micmot_banner _terminal_width _text_width +} + +micmot_menu() { + for _menu_option in $( set | sed -n 's/.*_micmot_menu_\(.\)_desc=.*/\1/p' ) + do + printf "%3s %s\n" "${_menu_option}" \ + "$( eval echo \${_micmot_menu_${_menu_option}_desc} )" + done + printf '\n' + printf "%3s %s\n" 'q' "Quit ${_script_name}. (Will not kill other panes)" + printf '\n> ' + unset _menu_option +} + +clear +_input='' +while ( true ); do + printf "\ek${_script_name}\e\\" + printf "\e]2;${_script_name}\e\\" + micmot_banner + micmot_menu + + read -r _input + case "${_input}" in + 'q' | 'Q') + break + ;; + *) + if [ "$( eval echo \${_micmot_menu_${_input}_cmd} 2>/dev/null )" ]; then + echo "Selected: $( eval echo \${_micmot_menu_${_input}_desc} )" + tmux -L "${MICMOT_SOCKET}" \ + new-window "$( eval echo \${_micmot_menu_${_input}_cmd} )" + else + echo "Unknown choice: ${_input}" >&2 + fi + ;; + esac +done + +# vim: sw=2 et diff --git a/lib/micmot-weechat-wrapper b/lib/micmot-weechat-wrapper new file mode 100755 index 0000000..ec18f78 --- /dev/null +++ b/lib/micmot-weechat-wrapper @@ -0,0 +1,7 @@ +#!/bin/sh -eu + +_fifo="${HOME}/.weechat/micmot-fifo" + +mkfifo "${_fifo}" +tail -f "${_fifo}" & +weechat diff --git a/lib/tmux-micmot.conf b/lib/tmux-micmot.conf new file mode 100644 index 0000000..58da856 --- /dev/null +++ b/lib/tmux-micmot.conf @@ -0,0 +1,2 @@ +set-option -g allow-rename on +set-option -g remain-on-exit on diff --git a/micmot b/micmot new file mode 100755 index 0000000..4571011 --- /dev/null +++ b/micmot @@ -0,0 +1,17 @@ +#!/bin/sh -eu + +[ "${MICMOT_SOCKET:-}" ] || MICMOT_SOCKET='micmot' +[ "${MICMOT_SESSION:-}" ] || MICMOT_SESSION='chat' + +export MICMOT_SOCKET + +_basedir="$( realpath "$( dirname "$0" )" )" +PATH="${PATH}:${_basedir}/lib" +export PATH + +tmux -f "./lib/tmux-micmot.conf" \ + -L "${MICMOT_SOCKET}" \ + new-session -s "${MICMOT_SESSION}" \ + "micmot-menu-pane" + +unset _basedir diff --git a/weechat/python/micmot.py b/weechat/python/micmot.py new file mode 100644 index 0000000..e1a77b3 --- /dev/null +++ b/weechat/python/micmot.py @@ -0,0 +1,82 @@ +#!/usr/bin/python3 +# +# Weechat script to display buffer actitity in tmux pane name. +# +# A workaround for: https://github.com/weechat/weechat/issues/741 +# +# Ideally weechat should support multiple hotlists, to make it possible to +# logically separate different chats into groups. Since such a feature is +# missing, and implementing it would be non-trivial, this script helps if +# running multiple weechat instances within a tmux. It abuses the ability to +# rename pane to make them double as channel activity indicators. +# +# Requires something like: `F=~/.weechat/micmot-fifo; mkfifo $F; tail -f $F &` +# +# Also requires ":set-option allow-rename on" in the tmux buffer. + +import os +import re +import weechat + +TMUX_FIFO = os.environ.get('WEECHAT_TMUX_FIFO', + os.environ['HOME'] + '/.weechat/micmot-fifo') + +PANE_NAME = os.environ.get('WEECHAT_TMUX_PANE', 'weechat') + +weechat.register( + "micmot", + "|cos|", + "0.1.0", + "MIT", + "Abusing tmux pane names for displaying channel activity.", + "", + "" +) + +def set_pane_name(name): + with open(TMUX_FIFO,'a') as f: + f.write("\x1bk%s\x1b\\" % name) + +def highlight_pane(): + with open(TMUX_FIFO,'a') as f: + f.write("\x07") + +def set_pane_title(name): + with open(TMUX_FIFO, 'a') as f: + f.write("\x1b]2;%s\x1b\\" % name) + +def hotlist_cb(a, b, c): + # https://weechat.org/files/doc/stable/weechat_user.en.html#notify_levels + tmux = "" + infolist = weechat.infolist_get("hotlist", "", "") + while weechat.infolist_next(infolist) != 0: + buffer_name = weechat.infolist_string(infolist, "buffer_name") + plugin_name = weechat.infolist_string(infolist, "plugin_name") + needle_pointer = weechat.buffer_search(plugin_name, buffer_name) + if needle_pointer: + short = weechat.buffer_get_string(needle_pointer, "short_name") + count_01 = weechat.infolist_integer(infolist, "count_01") + count_02 = weechat.infolist_integer(infolist, "count_02") + count_03 = weechat.infolist_integer(infolist, "count_03") + if count_01 > 0 or count_02 > 0 or count_03 > 0: + if tmux: + tmux = "{},{}".format(tmux,short) + else: + tmux = "{}".format(short) + else: + weechat.prnt("", "No buffer matching {} for plugin {}." + .format(buffer_name, plugin_name)) + + if tmux: + set_pane_name("[{}]".format(re.sub(r'[^.,#0-9A-Za-z-]+', '', tmux))) + highlight_pane() + else: + set_pane_name(PANE_NAME) + + weechat.infolist_free(infolist) + return weechat.WEECHAT_RC_OK + +weechat.prnt("", "micmot " + PANE_NAME + TMUX_FIFO) +set_pane_name(PANE_NAME) +set_pane_title(PANE_NAME) +weechat.hook_signal("hotlist_changed", "hotlist_cb", "") -- cgit v1.2.3