# HG changeset patch # User Steve Losh # Date 1756325964 14400 # Node ID 62e3298396253f54d4786f7ca730a08048fd29d0 # Parent 87ff0514c83bee8b42d6767af554be3c11d58177# Parent 93d27886c09992713660dd474663bae8a854afd6 Merge diff -r 93d27886c099 -r 62e329839625 .hgsub --- a/.hgsub Sun May 18 14:59:11 2025 -0400 +++ b/.hgsub Wed Aug 27 16:19:24 2025 -0400 @@ -2,6 +2,7 @@ mercurial/templates = [hg]ssh://hg.stevelosh.com/repos/mercurial-cli-templates vim/bundle/abolish = [git]https://github.com/tpope/vim-abolish vim/bundle/ack = [git]https://github.com/mileszs/ack.vim +vim/bundle/ansible = [git]https://github.com/pearofducks/ansible-vim vim/bundle/badwolf = [hg]ssh://hg.stevelosh.com/repos/badwolf/ vim/bundle/boxdraw = [git]https://github.com/gyim/vim-boxdraw vim/bundle/clam = [hg]ssh://hg.stevelosh.com/repos/clam.vim/ @@ -18,6 +19,8 @@ vim/bundle/markdown = [git]https://github.com/sjl/vim-markdown vim/bundle/neoformat = [git]https://github.com/sbdchd/neoformat vim/bundle/nerdtree = [git]https://github.com/scrooloose/nerdtree +vim/bundle/nextflow-vim = [git]https://github.com/sjl/nextflow-vim +vim/bundle/nvim-r = [git]https://github.com/jalvesaq/Nvim-R vim/bundle/paredit = [git]https://github.com/kovisoft/paredit vim/bundle/pgsql = [git]https://github.com/exu/pgsql.vim vim/bundle/python-mode = [git]https://github.com/klen/python-mode @@ -28,11 +31,13 @@ vim/bundle/sexp = [git]https://github.com/guns/vim-sexp vim/bundle/shellcheck = [git]https://github.com/itspriddle/vim-shellcheck vim/bundle/simpylfold = [git]https://github.com/tmhedberg/SimpylFold +vim/bundle/singularity-syntax = [git]https://github.com/rbberger/vim-singularity-syntax vim/bundle/splice = [hg]ssh://hg.stevelosh.com/repos/splice.vim vim/bundle/strftimedammit = [hg]ssh://hg.stevelosh.com/repos/strftimedammit.vim/ vim/bundle/surround = [git]https://github.com/tpope/vim-surround vim/bundle/swig = [git]https://github.com/vim-scripts/SWIG-syntax vim/bundle/targets = [git]https://github.com/wellle/targets.vim +vim/bundle/ultisnips = [git]https://github.com/SirVer/ultisnips vim/bundle/vim-go = [git]https://github.com/fatih/vim-go vim/bundle/vimtex = [git]https://github.com/lervag/vimtex vim/bundle/vlime = [git]https://github.com/sjl/vlime diff -r 93d27886c099 -r 62e329839625 .hgsubstate --- a/.hgsubstate Sun May 18 14:59:11 2025 -0400 +++ b/.hgsubstate Wed Aug 27 16:19:24 2025 -0400 @@ -1,24 +1,27 @@ 16aa2def1d5b91f2f38c0bf50a955d28559c7ebe mercurial/hg-prompt 1fc4a9fbead7e0acc4c828b346f3be2658ec3df9 mercurial/templates -b6a8b49e2173ba5a1b34d00e68e0ed8addac3ebd vim/bundle/abolish -a16a9b63eb85cc0960a7f25c54647ac1f99f3360 vim/bundle/ack -599e1bb1aee98e563132553cf8b7bc32cb402b75 vim/bundle/badwolf -24f6d94dd03ba0fdc703265fe281f70cf2b45ba6 vim/bundle/boxdraw +dcbfe065297d31823561ba787f51056c147aa682 vim/bundle/abolish +36e40f9ec91bdbf6f1adf408522a73a6925c3042 vim/bundle/ack +3329367d2e5f90d203c8d340c53fa83c60a1ad41 vim/bundle/ansible +a93aaf7f4247858f5e483dc98001a878a5233761 vim/bundle/badwolf +b7f789f305b1c5b0b4623585e0f10adb417f2966 vim/bundle/boxdraw b542a7bc4d9bc5da8fb12e110fe7975131fb57a4 vim/bundle/clam -8295187ea1210138c0b171d8e3ec3569936f4c1a vim/bundle/commentary -c6d1fc5e58d689bfb104ff336aeb89d9ef1b48e2 vim/bundle/ctrlp +e87cd90dc09c2a203e13af9704bd0ef79303d755 vim/bundle/commentary +7c972cb19c8544c681ca345c64ec39e04f4651cc vim/bundle/ctrlp 38487bbec8ba50834e257940b357de03991fa8f9 vim/bundle/delimitmate 755554bb3c44944f70f4b2048acf0c69261782ac vim/bundle/fugitive 127d706f2def96876605e6bd5d366c973cb8e406 vim/bundle/gdl 7fcea1a08423da3012aac87f5224738c85d212a1 vim/bundle/gnupg 0d57b080f9fae8573c688b6679b31eb1666edc4c vim/bundle/gnuplot 1d84591fff04caebab75cba2294fc3843f0a4a29 vim/bundle/gundo -fccd580f5f11d576169ee347907c9fbd77af410a vim/bundle/html5 +485f2cd62162c81e56d8604b4c630f0b5ef69d1f vim/bundle/html5 dd84369d731bcb8feee0901cbb9b63a2b219bf28 vim/bundle/javascript e2d7fcd682a461a3951e8b5067cc8a0083e75e35 vim/bundle/markdown 964c66fa22500ae7375114342d212d7fe15da341 vim/bundle/neoformat 9310f91476a94ee9c2f3a587171893743a343e26 vim/bundle/nerdtree -c76e0987ec45c84103b408691ec0506e7b99cb30 vim/bundle/paredit +47f6d8508757559fcfa8f49cd93cd5c86ce847f0 vim/bundle/nextflow-vim +eb97bf7c88480b9f00b6765c09c3886550ed8d43 vim/bundle/nvim-r +989d1c046bbe36f7d71878636dbe6af8ea3f4f86 vim/bundle/paredit 1a436f7d875b4ec630da081b041c73264235c7e7 vim/bundle/pgsql d241974f40e8d206f9970e51fb0069951862ba35 vim/bundle/python-mode eb8baa5428bde10ecc1cb14eed1d6e16f5f24695 vim/bundle/rainbow-parentheses @@ -28,12 +31,14 @@ b4398689f7483b01684044ab6b55bf369744c9b3 vim/bundle/sexp 4346419ac57ef341a15aa39c827c0848f17c6faf vim/bundle/shellcheck 0459df8a0bbfc8ef1bfd88db889e881626f65914 vim/bundle/simpylfold +caaba2594df4f1859a448e6cf13c64d956419acd vim/bundle/singularity-syntax 062b18eebd153c13e6f36577707acb17893cd959 vim/bundle/splice 26fbdd7d1f1aa5600d2ebf39bbdd292c38aac16e vim/bundle/strftimedammit aa1f120ad3a29c27cc41d581cda3751c59343cce vim/bundle/surround 19c3d966440b6cfe8d74251881a48e961ddb8648 vim/bundle/swig f6f2d6618a321f5b0065586a7bc934325fec81ab vim/bundle/targets +b393ba65386d47664421e1f8b246a87a6e8b218c vim/bundle/ultisnips e9d7ff3eb4a369f0cb2069c8f77ae68796bca308 vim/bundle/vim-go -5d5c71044880443035e07009497962feacb56b20 vim/bundle/vimtex -54feb567738398ab65d783e096bc84938e7620a0 vim/bundle/vlime +9df79e15bf035d1cfb32c11fffed38dd7b6a0501 vim/bundle/vimtex +eee93632fee3b680fe992008b723b0802bb94a60 vim/bundle/vlime 6876fe38b33732cb124d415ffc4156f16da5e118 vim/bundle/windowswap diff -r 93d27886c099 -r 62e329839625 .mbsyncrc --- a/.mbsyncrc Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -# tweaked https://raw.githubusercontent.com/bm4cs/dots/Far/.mbsyncrc - -IMAPAccount fastmail -Host imap.fastmail.com -Port 993 -User steve@stevelosh.com -PassCmd "pass show mutt/ouroboros/steve@stevelosh.com | head -n 1" -SSLType IMAPS -SSLVersion TLSv1.2 -CertificateFile /etc/ssl/certs/ca-certificates.crt - -# Remote -IMAPStore mail-remote -Account fastmail - -# Local -MaildirStore mail-local -Subfolders Verbatim -Path ~/.mail2/sjl/ -Inbox ~/.mail2/sjl/INBOX - -# CONNECTIONS SPECIFY LINKS BETWEEN REMOTE AND LOCAL FOLDERS -# CONNECTIONS ARE SPECIFIED USING PATTERNS, WHICH MATCH REMOTE MAIl -# FOLDERS. SOME COMMONLY USED PATTERS INCLUDE: -# -# 1 "*" TO MATCH EVERYTHING -# 2 "!DIR" TO EXCLUDE "DIR" -# 3 "DIR" TO MATCH DIR - -Channel mail-inbox -Far :mail-remote: -Near :mail-local: -Patterns INBOX -Create Near -Sync All -Expunge Both -SyncState * - -Channel mail-sent -Far :mail-remote: -Near :mail-local: -Patterns "Sent" -Create Both -Sync All -Expunge Both -SyncState * - -Channel mail-spam -Far :mail-remote: -Near :mail-local: -Patterns "Uncaught Spam" -Create Near -Sync All -Expunge Both -SyncState * - -Channel mail-drafts -Far :mail-remote: -Near :mail-local: -Patterns "Drafts" -Create Near -Sync All -Expunge Both -SyncState * - -Channel mail-archive -Far :mail-remote: -Near :mail-local: -Patterns "Arc*" -Create Near -Sync All -Expunge Both -SyncState * - -Group mail -Channel mail-inbox -Channel mail-spam -Channel mail-drafts -Channel mail-sent -Channel mail-archive - diff -r 93d27886c099 -r 62e329839625 Xmodmap --- a/Xmodmap Sun May 18 14:59:11 2025 -0400 +++ b/Xmodmap Wed Aug 27 16:19:24 2025 -0400 @@ -6,7 +6,11 @@ clear mod4 clear mod5 +! Laptop lctrl keycode 37 = Hyper_L +! Laptop rctrl +keycode 105 = Hyper_R + keycode 66 = Control_L keycode 133 = Alt_L keycode 64 = Super_L @@ -53,4 +57,4 @@ add mod1 = Alt_L add mod2 = Num_Lock add mod4 = Super_L -add mod5 = Hyper_L +add mod5 = Hyper_L Hyper_R diff -r 93d27886c099 -r 62e329839625 bash_profile --- a/bash_profile Sun May 18 14:59:11 2025 -0400 +++ b/bash_profile Wed Aug 27 16:19:24 2025 -0400 @@ -6,6 +6,7 @@ shopt -s expand_aliases shopt -s histappend +shopt -s checkwinsize # Save multiline commands as a single history entry. shopt -s cmdhist @@ -21,12 +22,12 @@ eval "$(dircolors -b ~/.dircolors)" fi -D=$'\e[37m' -RED=$'\e[31m' -GREEN=$'\e[32m' -ORANGE=$'\e[33m' -BLUE=$'\e[34m' -PINK=$'\e[35m' +D=$'\x01\e[37m\x02' +RED=$'\x01\e[31m\x02' +GREEN=$'\x01\e[32m\x02' +ORANGE=$'\x01\e[33m\x02' +BLUE=$'\x01\e[34m\x02' +PINK=$'\x01\e[35m\x02' # CYAN=$'\e[36m' function last_return_value() { @@ -54,6 +55,10 @@ alias .....="cd ../../../.." alias ......="cd ../../../../.." +function mcd { + mkdir "$1" && cd "$1" +} + alias js='cd ~/scratch' alias :q=exit @@ -114,3 +119,5 @@ export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm + +export PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig" diff -r 93d27886c099 -r 62e329839625 bin/abcl --- a/bin/abcl Sun May 18 14:59:11 2025 -0400 +++ b/bin/abcl Wed Aug 27 16:19:24 2025 -0400 @@ -1,3 +1,3 @@ #!/usr/bin/env bash -rlwrap-lisp /usr/local/bin/abcl "$@" +rlwrap-lisp abcl-raw "$@" diff -r 93d27886c099 -r 62e329839625 bin/abcl-raw --- a/bin/abcl-raw Sun May 18 14:59:11 2025 -0400 +++ b/bin/abcl-raw Wed Aug 27 16:19:24 2025 -0400 @@ -1,4 +1,5 @@ #!/usr/bin/env bash set -e -/usr/local/bin/abcl --noinform "$@" + +java -jar /usr/local/bin/abcl.jar --noinform "$@" diff -r 93d27886c099 -r 62e329839625 bin/battery --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/battery Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail + +function check_battery { + # TODO make this less shit + BATT="$1" + echo "$BATT" + cat "$BATT"/type + + if test -e "$BATT"/online; then + echo -n "Online: " + cat "$BATT"/online + fi + + if test -e "$BATT"/capacity; then + echo -n "Capacity (%): " + cat "$BATT"/capacity + fi + + echo +} + +for b in /sys/class/power_supply/*; do + check_battery "$b" +done diff -r 93d27886c099 -r 62e329839625 bin/bht --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/bht Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ffplay -v 0 -nodisp -autoexit ~/bin/bht.mp3 diff -r 93d27886c099 -r 62e329839625 bin/bootstrap.sh --- a/bin/bootstrap.sh Sun May 18 14:59:11 2025 -0400 +++ b/bin/bootstrap.sh Wed Aug 27 16:19:24 2025 -0400 @@ -12,11 +12,14 @@ mkdir -p ~/.local/share mkdir -p ~/.config/fish mkdir -p ~/.config/nvim +mkdir -p ~/.config/htop +mkdir -p ~/.config/mpd mkdir -p ~/src/hg mkdir -p ~/src/virtualenvs mkdir -p ~/bin mkdir -p ~/src mkdir -p ~/.w3m +mkdir -p ~/.weechat ensure_link "src/dotfiles/hgrc" ".hgrc" @@ -44,8 +47,10 @@ ensure_link "src/dotfiles/gitignore" ".gitignore" ensure_link "src/dotfiles/gnuplot" ".gnuplot" ensure_link "src/dotfiles/hgignore" ".hgignore" +ensure_link "src/dotfiles/htoprc" ".config/htop/htoprc" ensure_link "src/dotfiles/lisprc" ".lisprc" ensure_link "src/dotfiles/lispwords" ".lispwords" +ensure_link "src/dotfiles/mpd.conf" ".config/mpd/mpd.conf" ensure_link "src/dotfiles/mutt" ".mutt" ensure_link "src/dotfiles/mutt/mailcap" ".mailcap" ensure_link "src/dotfiles/mutt/muttrc" ".muttrc" @@ -54,13 +59,13 @@ ensure_link "src/dotfiles/sbclrc" ".sbclrc" ensure_link "src/dotfiles/shellcheckrc" ".shellcheckrc" ensure_link "src/dotfiles/sqliterc" ".sqliterc" -ensure_link "src/dotfiles/stumpwmrc" ".stumpwmrc" ensure_link "src/dotfiles/stumpwm/local-share-stumpwm" ".local/share/stumpwm" +ensure_link "src/dotfiles/stumpwm/stumpwmrc" ".stumpwmrc" ensure_link "src/dotfiles/vim" ".vim" ensure_link "src/dotfiles/vim/vimrc" ".vimrc" -ensure_link "src/dotfiles/w3m-keymap" ".w3m/keymap" +ensure_link "src/dotfiles/vim/vimrc-minimal" ".vimrc-minimal" ensure_link "src/dotfiles/w3m-config" ".w3m/config" -ensure_link "src/dotfiles/weechat" ".weechat" +ensure_link "src/dotfiles/w3m-keymap" ".w3m/keymap" ensure_link "src/dotfiles/xbindkeysrc" ".xbindkeysrc" ensure_link "src/dotfiles/xsessionrc" ".xsessionrc" diff -r 93d27886c099 -r 62e329839625 bin/boxify --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/boxify Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +import sys + +lines = sys.stdin.readlines() + +def ch(row, col): + if row < 0 or row >= len(lines): + return None + line = lines[row] + if col < 0 or col >= len(line): + return None + return line[col] + +for row, line in enumerate(lines): + for col, char in enumerate(line): + c = char + if char == '-': + c = '—' + elif char == '|': + c = '│' + elif char == '+': + u = ch(row-1, col) == '|' + d = ch(row+1, col) == '|' + l = ch(row, col-1) == '-' + r = ch(row, col+1) == '-' + if u and d and l and r: c = '┼' + elif u and d and l and not r: c = '┤' + elif u and d and not l and r: c = '├' + elif u and not d and l and r: c = '┴' + elif not u and d and l and r: c = '┬' + elif u and r: c = '└' + elif u and l: c = '┘' + elif d and l: c = '┐' + elif d and r: c = '┌' + elif u and d: c = '│' + elif l and r: c = '─' + else: + print(u, d, l, r,) + assert False + + sys.stdout.write(c) diff -r 93d27886c099 -r 62e329839625 bin/cax --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/cax Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +chmod a+x "$@" diff -r 93d27886c099 -r 62e329839625 bin/cmrm --- a/bin/cmrm Sun May 18 14:59:11 2025 -0400 +++ b/bin/cmrm Wed Aug 27 16:19:24 2025 -0400 @@ -4,4 +4,4 @@ set -x rm ~/.ssh/controlmaster/* -ps auxww | grep 'ssh.*[.]sock.*mux' | f 2 | xargs kill +ps auxww | grep -P 'ssh.*controlmaster.*mux' | f 2 | xargs kill diff -r 93d27886c099 -r 62e329839625 bin/code-to-pdf --- a/bin/code-to-pdf Sun May 18 14:59:11 2025 -0400 +++ b/bin/code-to-pdf Wed Aug 27 16:19:24 2025 -0400 @@ -9,12 +9,11 @@ --toc \ --header '%H - $N | | page $% of $= in file $v' \ --fancy-header=sjl \ - --font "UbuntuMono-Regular@9" \ - --header-font "UbuntuMono-Bold@12" \ + --font "UbuntuMono-Regular@8" \ + --header-font "UbuntuMono-Bold@10" \ --title "$TITLE" \ --baselineskip 3 \ --line-numbers \ - --highlight \ --color \ --mark-wrapped-lines=arrow \ --margins=50:50:18:50 \ @@ -25,3 +24,4 @@ # --margins=20:40:30:30 \ # --landscape \ + # --highlight \ diff -r 93d27886c099 -r 62e329839625 bin/cqn --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/cqn Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +/home/sjl/bin/lqn.core --script ~/src/lqn/bin/cqn-sh.lisp "$@" diff -r 93d27886c099 -r 62e329839625 bin/csv2tsv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/csv2tsv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +import sys +import csv + +def run_file(f): + w = csv.writer(sys.stdout, delimiter='\t') + for row in csv.reader(f): + w.writerow(row) + +def run(paths): + for path in paths: + if path == '-': + run_file(sys.stdin) + else: + with open(path) as f: + run_file(f) + +if __name__ == '__main__': + run(sys.argv[1:] or ['-']) diff -r 93d27886c099 -r 62e329839625 bin/csvconcat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/csvconcat Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail + +head -n1 "$1" +tail --quiet -n +2 "$@" diff -r 93d27886c099 -r 62e329839625 bin/cux --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/cux Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +chmod u+x "$@" diff -r 93d27886c099 -r 62e329839625 bin/cv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/cv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +column -s, -t "$@" diff -r 93d27886c099 -r 62e329839625 bin/cvs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/cvs Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +csvconcat "$@" | cv diff -r 93d27886c099 -r 62e329839625 bin/date-block --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/date-block Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +import sys, datetime + + +days = 'mtwhfsu' +start_date = datetime.datetime.strptime(sys.argv[1] + ' 12:00:00 UTC', '%Y-%m-%d %H:%M:%S %Z') + +d = start_date + +for _ in range(7 * 8): + day = days[d.weekday()] + date = d.strftime('%Y-%m-%d') + + if day == 'm': + print() + + print(f"{day} {date}") + d += datetime.timedelta(days=1) diff -r 93d27886c099 -r 62e329839625 bin/descendent-pids --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/descendent-pids Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -euo pipefail + +pids="$1" + +while [ "$pids" ]; do + echo $pids + pids=$(for p in $pids; do cat /proc/$p/task/$p/children; done) +done | tr " " "\n" diff -r 93d27886c099 -r 62e329839625 bin/disks --- a/bin/disks Sun May 18 14:59:11 2025 -0400 +++ b/bin/disks Wed Aug 27 16:19:24 2025 -0400 @@ -12,10 +12,10 @@ OUT=$(df -h) echo "$OUT" | head -1 echo "$OUT" | head -1 | sed 's/./-/g' -echo "$OUT" | tail +2 | grep -Pv '^/dev/loop' | grep -Pv tmpfs | sort -k6 +echo "$OUT" | tail +2 | grep -Pv '^/dev/loop' | grep -Pv tmpfs | sort -k6 | grep -P --color '/dev.*\s/$|' echo OUT=$(df -i) echo "$OUT" | head -1 echo "$OUT" | head -1 | sed 's/./-/g' -echo "$OUT" | tail +2 | grep -Pv '^/dev/loop' | grep -Pv tmpfs | sort -k6 +echo "$OUT" | tail +2 | grep -Pv '^/dev/loop' | grep -Pv tmpfs | sort -k6 | grep -P --color '/dev.*\s/$|' diff -r 93d27886c099 -r 62e329839625 bin/f, --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/f, Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +cut -d, -f "$@" diff -r 93d27886c099 -r 62e329839625 bin/fnums --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/fnums Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Field Numbers, because I'm sick of manually counting + +head -n 1 "$@" | tr -s ',\t' '\n\n' | nl diff -r 93d27886c099 -r 62e329839625 bin/forward-igv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/forward-igv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail + +slurm_node="$1" + +ssh -NAL 60151:localhost:60151 "$slurm_node" diff -r 93d27886c099 -r 62e329839625 bin/heic-conv-all --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/heic-conv-all Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,44 @@ +#!/bin/bash + +# from https://github.com/lokarithm/HandyBashCommands/blob/main/heic-converter/heic-converter.sh + +if ! command -v heif-convert &> /dev/null +then + echo "heif-convert COMMAND could not be found." + echo "Please install 'libheif-examples' first." + echo "To install 'libheif-examples', run the following command:" + echo " sudo apt install libheif-examples" + exit +else + fileExtension="jpg" + + while getopts :p flag; do + case ${flag} in + # -p flag: convert heic files to png format instead + p) fileExtension="png" + ;; + esac + done + + start_time=$(date +%s.%3N) + + # look for files in current path that contains ".heic" in a case-insensitive manner + for file in $( ls | grep -iF ".heic") + do + echo "Converting file: $file" + + # file extension of current file + currFileExtension=`echo $file | grep -iFo "heic"` + sedCommand="s/${currFileExtension}/${fileExtension}/g;s/HEIC/${fileExtension}/g" + + #replace original file name by changing the extension from heic to jpg + outputFileName=`echo $file | sed -e $sedCommand` + heif-convert $file $outputFileName + done + + end_time=$(date +%s.%3N) + + elapsed=$(echo "scale=3; $end_time - $start_time" | bc) + echo -e "\nElapsed time: \e[32m$elapsed \e[39mmilliseconds." + +fi diff -r 93d27886c099 -r 62e329839625 bin/hg-clone-llp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/hg-clone-llp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo="$1" + +h clone hsl://"$repo" "$repo" +cd "$repo" +llp diff -r 93d27886c099 -r 62e329839625 bin/hl --- a/bin/hl Sun May 18 14:59:11 2025 -0400 +++ b/bin/hl Wed Aug 27 16:19:24 2025 -0400 @@ -1,3 +1,3 @@ #!/usr/bin/env bash -less -R +less -S -R "$@" diff -r 93d27886c099 -r 62e329839625 bin/install-figlet-fonts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/install-figlet-fonts Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# I'm so sick of doing this shit by hand every time I get a new computer. +# +# cd ~/src/ +# git clont https://github.com/xero/figlet-fonts + +for f in /home/sjl/src/figlet-fonts/*.fl*; do + dest="$(echo "$f" | cut -d/ -f 6 | tr '[:upper:] ' '[:lower:]-')" + sudo cp "$f" "/usr/share/figlet/$dest" +done + diff -r 93d27886c099 -r 62e329839625 bin/jabref --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/jabref Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail + +jabref-bin + +scp ~/Sync/papers/sjl.bib "cylinder:bib-backup/sjl.bib.$(nicedate).backup" diff -r 93d27886c099 -r 62e329839625 bin/jqn --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/jqn Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +/home/sjl/bin/lqn.core --script ~/src/lqn/bin/jqn-sh.lisp "$@" diff -r 93d27886c099 -r 62e329839625 bin/lesss --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/lesss Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +less -S "$@" diff -r 93d27886c099 -r 62e329839625 bin/longcat --- a/bin/longcat Sun May 18 14:59:11 2025 -0400 +++ b/bin/longcat Wed Aug 27 16:19:24 2025 -0400 @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import sys @@ -7,25 +7,24 @@ else: n = 20 -print r''' - /\___/\ - / \ - | o o | - \ # | - \ _|_ / - / \______ - / _______ ___ \ - |_____ \ \__/ +print (r''' + /\___/\ + / \ + | o o | + \ # | + \ _|_ / + / \______ + / _______ ___ \ + |_____ \ \__/ | \__/ - | | -''', -print ' | |\n' * n, -print r''' | | + | |'''), +print(' | |\n' * n, end='') +print(r''' | | / \ / ____ \ | / \ | | | | | / | | \ \__/ \__/ -''' +''') diff -r 93d27886c099 -r 62e329839625 bin/lqn --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/lqn Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +/home/sjl/bin/lqn.core --script ~/src/lqn/bin/lqn-sh.lisp "$@" diff -r 93d27886c099 -r 62e329839625 bin/mark --- a/bin/mark Sun May 18 14:59:11 2025 -0400 +++ b/bin/mark Wed Aug 27 16:19:24 2025 -0400 @@ -4,6 +4,8 @@ EVENT="$1" shift +HOST=$(hostname) +DIR="$HOME/Sync/marks/$HOST/" -mkdir -p "$HOME/.marks" -echo "$(date --iso-8601=seconds --utc)" "$@" >> "$HOME/.marks/$EVENT" +mkdir -p "$DIR" +echo "$(date --iso-8601=seconds --utc)" "$@" >> "$DIR/$EVENT" diff -r 93d27886c099 -r 62e329839625 bin/minimap2-index --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/minimap2-index Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# minimap2-index \ +# /nfs/turbo/boylelab/slosh/reference-genomes/hg38_no_alt/seq/GCA_000001405.15_GRCh38_no_alt_analysis_set.fna \ +# map-ont/ \ +# -x map-ont +reference="$1" +shift +output_dir="$1" +shift + +# remaining opts are e.g. -x ont + +minimap="/nfs/turbo/boylelab/slosh/software/minimap2-2.30_x64-linux/minimap2" + +mkdir -p "$output_dir" + +{ + echo Minimap version: "$("$minimap" --version)" + + echo Indexing command: " " + echo \ + "$minimap" -t 8 -d "$output_dir/index.mmi" "$reference" "$@" + + echo + echo Output: + "$minimap" -t 8 -d "$output_dir/index.mmi" "$reference" "$@" +} >> "$output_dir"/README.txt 2>&1 + + + diff -r 93d27886c099 -r 62e329839625 bin/mklatex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/mklatex Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail + +NAME="$1" + +pdflatex "$NAME".tex diff -r 93d27886c099 -r 62e329839625 bin/mklatex-bib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/mklatex-bib Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -euo pipefail + +NAME="$1" + +pdflatex "$NAME".tex +biber "$NAME" +pdflatex "$NAME".tex +pdflatex "$NAME".tex diff -r 93d27886c099 -r 62e329839625 bin/mkxelatex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/mkxelatex Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail + +NAME="$1" + +xelatex "$NAME".tex diff -r 93d27886c099 -r 62e329839625 bin/mkxelatex-bib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/mkxelatex-bib Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -euo pipefail + +NAME="$1" + +xelatex "$NAME".tex +bibtex "$NAME" +xelatex "$NAME".tex +xelatex "$NAME".tex + diff -r 93d27886c099 -r 62e329839625 bin/nicedate --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/nicedate Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +date --utc +%Y-%m-%dT%H-%M-%SZ diff -r 93d27886c099 -r 62e329839625 bin/pspg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/pspg Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +/usr/bin/pspg --vertical-cursor --style 5 "$@" diff -r 93d27886c099 -r 62e329839625 bin/remap-hggit-mapfile --- a/bin/remap-hggit-mapfile Sun May 18 14:59:11 2025 -0400 +++ b/bin/remap-hggit-mapfile Wed Aug 27 16:19:24 2025 -0400 @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 from __future__ import print_function import collections @@ -22,11 +22,11 @@ def hg(*args): l = ["hg", "--repository", hg_dir] + list(args) - return subprocess.check_output(l).strip() + return subprocess.check_output(l).strip().decode('utf-8') def git(*args): l = ["git", "-C", git_dir] + list(args) - return subprocess.check_output(l).strip() + return subprocess.check_output(l).strip().decode('utf-8') def find_hg_root_revision(): rev = hg('log', '-r', 'roots(all())', nodetempl).split() diff -r 93d27886c099 -r 62e329839625 bin/rsync-file-pattern --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/rsync-file-pattern Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# USAGE: rsync-file-pattern PATTERN SOURCE DEST +# rsync-file-pattern '*.ipynb' ./ vm:path/to/foo/ + +# Goal: given a source and dest, sync any files inside the source that match +# a given pattern. Rsync's syntax for this is utterly deranged, so I'm making +# a script so I don't have to search for this every time. + +pattern="$1" +shift + +source="$1" +shift + +dest="$1" +shift + + +rsync -av \ + --prune-empty-dirs \ + --include='*/' \ + --include="$pattern" \ + --exclude='*' \ + "${source}" "${dest}" \ + "$@" + diff -r 93d27886c099 -r 62e329839625 bin/sb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/sb Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -e + +sbcl --eval '(ql:quickload :losh :silent t)' --eval '(in-package :losh-user)' "$@" diff -r 93d27886c099 -r 62e329839625 bin/st-apl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/st-apl Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +st -f 'BQN386 Unicode:style=Regular:size=12' "$@" diff -r 93d27886c099 -r 62e329839625 bin/subtree-cpu-usage --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/subtree-cpu-usage Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail + +x="$1" +pidstat -h -u -p $(descendent-pids "$x" | tr -s '\n' ',' | sed -e 's/,$//') 5 1 diff -r 93d27886c099 -r 62e329839625 bin/sv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/sv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +column -s ' ' -t "$@" diff -r 93d27886c099 -r 62e329839625 bin/switch-yubikeys --- a/bin/switch-yubikeys Sun May 18 14:59:11 2025 -0400 +++ b/bin/switch-yubikeys Wed Aug 27 16:19:24 2025 -0400 @@ -1,6 +1,4 @@ #!/usr/bin/env bash -set -euo pipefail - grep -rl shadowed-private-key ~/.gnupg/private-keys-v1.d/ | xargs rm gpg --card-status diff -r 93d27886c099 -r 62e329839625 bin/t. --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/t. Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +stumpish terminal-in "$(pwd)" diff -r 93d27886c099 -r 62e329839625 bin/temps --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/temps Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,50 @@ +#!/usr/bin/env bash + +set -euo pipefail + +function find_names { + grep . /sys/class/hwmon/hwmon*/name +} + +function find_temp_numbers { + dir="$1" + find "/sys/class/hwmon/$dir/" -name 'temp*_input' \ + | xargs -n1 basename \ + | tr -dc '0-9\n' \ + | sort -n +} + +function display_temp { + dir="$1" + n="$2" + + set +e + + if test -e "/sys/class/hwmon/$dir/temp${n}_label"; then + paste \ + <(cat "/sys/class/hwmon/$dir/temp${n}_label") \ + <(cat "/sys/class/hwmon/$dir/temp${n}_input" 2>&1) + else + paste \ + <(echo '???') \ + <(cat "/sys/class/hwmon/$dir/temp${n}_input") + fi + + set -e +} + +if test -z "${1:-}"; then + find_names +else + dir=$(find_names | grep "$1" | cut -d / -f 5) + + find_temp_numbers "$dir" | while read -r n; do + display_temp "$dir" "$n" + done + # paste \ + # <(grep . "/sys/class/hwmon/$dir/"temp*_label | sort) \ + # <(grep . "/sys/class/hwmon/$dir/"temp*_input | sort) \ + # | tr -s ':' ' ' \ + # | awk '/Core/ {print $2, $3, $5/1000.0 }' \ + # | sort -n -k2 +fi diff -r 93d27886c099 -r 62e329839625 bin/tqn --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/tqn Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +/home/sjl/bin/lqn.core --script ~/src/lqn/bin/tqn-sh.lisp "$@" diff -r 93d27886c099 -r 62e329839625 bin/trst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/trst Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +tr ' ' $'\t' diff -r 93d27886c099 -r 62e329839625 bin/tsv2csv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/tsv2csv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +import sys +import csv + +def run_file(f): + w = csv.writer(sys.stdout) + for row in csv.reader(f, delimiter='\t'): + w.writerow(row) + +def run(paths): + for path in paths: + if path == '-': + run_file(sys.stdin) + else: + with open(path) as f: + run_file(f) + +if __name__ == '__main__': + run(sys.argv[1:] or ['-']) diff -r 93d27886c099 -r 62e329839625 bin/tv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/tv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +column -s $'\t' -t "$@" diff -r 93d27886c099 -r 62e329839625 bin/tvs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/tvs Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +csvconcat "$@" | tv diff -r 93d27886c099 -r 62e329839625 bin/um-pass --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/um-pass Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail + +echo Retrieving password, press yubikey... > /dev/tty +pass show umich.edu/slosh | head -1 | tr -d '\n' diff -r 93d27886c099 -r 62e329839625 bin/unboxify --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/unboxify Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +import sys + +for line in sys.stdin: + for ch in line: + sys.stdout.write({ + '┤': '+', + '├': '+', + '┴': '+', + '┬': '+', + '┼': '+', + '└': '+', + '┘': '+', + '┐': '+', + '┌': '+', + '│': '|', + '—': '-', + }.get(ch, ch)) + diff -r 93d27886c099 -r 62e329839625 bin/watch-latex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/watch-latex Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +NAME="$1" +shift + +echo "$NAME".tex "$@" | peat "mklatex $NAME" diff -r 93d27886c099 -r 62e329839625 bin/watch-xelatex --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/watch-xelatex Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +NAME="$1" +shift + +echo "$NAME".tex "$@" | peat "mkxelatex $NAME" diff -r 93d27886c099 -r 62e329839625 bin/watch-xelatex-bib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/watch-xelatex-bib Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +NAME="$1" +shift + +echo "$NAME".tex "$@" | peat "mkxelatex-bib $NAME" diff -r 93d27886c099 -r 62e329839625 bootstrap.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bootstrap.markdown Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,177 @@ +# Bootstrapping a New Machine + +Notes for myself for the next time I set up a new laptop or whatever. + +First, back up everything if necessary: + +* Faster on wired ethernet. +* Don't forget password-store! +* Don't forget hidden dotfiles! + +Install Debian. Partition everything, install nothing. + +Goal is now to get the dotfiles repo onto the machine and have everything +required to run `bootstrap.sh`. + +Boot into a command line as root (no `sudo` yet): + + apt install sudo + usermod -a -G sudo sjl + usermod -a -G netdev sjl + +Allow non-free packages: + + vim /etc/apt/sources.list + + edit to add non-free to lines, e.g.: + deb http://http.us.debian.org/debian bookworm main contrib non-free + + apt update + +Install first round of stuff: + + apt install \ + nmtui sudo make + curl wget network-manager + fish rlwrap + mercurial git + xcape + pulseaudio alsa-utils + libzstd-dev libx11-dev libxft-dev + build-essential autoconf pkg-config + bzip2 udisks2 lm-sensors htop + fonts-ubuntu w3m atool psmisc + suckless-tools trash-cli + dunst neovim python3-dulwich + silversearcher-ag + irssi + +TODO: `xautolock` is no longer in the Debian repos. Figure out how to get it. + +TODO: Need to disable networkd, remove interface from `/etc/interfaces` and +restart `NetworkManager` to get that in place. + +Set up `.ssh` and keys. + +Bootstrap lisp: + + sudo apt install sbcl + git clone https://github.com/sbcl/sbcl + git checkout sbcl-2.3.6 + SBCL_MAKE_JOBS=-j8 SBCL_MAKE_PARALLEL=8 sh make.sh --with-core-compression + sudo sh install.sh + sudo apt remove sbcl + + curl -O https://beta.quicklisp.org/quicklisp.lisp + sbcl --load quicklisp.lisp + (quicklisp-quickstart:install :path "/home/sjl/.quicklisp/") + + TODO CCL and others + +Get dotfiles: + + hg clone ssh://hsl/repos/dotfiles + cd dotfiles + ./bin/bootstrap.sh + + TODO build hg from scratch to get hg-git working maybe + TODO bootstrap script might fuck up the fish config because shit's already created, thanks a lot fish + + git clone https://github.com/sjl/z-fish + +`chsh` to `/usr/bin/fish` + +Clone repos: + + hg clone hsl://adopt adopt + cd adopt + llp + cd .. + + hg-clone-llp for lisp + + others: + + 1am + adopt + beast + bobbin + boots + cacl + chancery + cl-d-api + cl-digraph + cl-losh + cl-netpbm + cl-pcg + conserve + d + dbvolve + docs.stevelosh.com + friendly-find + jarl + peat + t + + …etc etc + + +Build st: + + git clone https://github.com/sjl/st + +Get a desktop environment up and running: + + sudo apt install xinit xdm + + git clone https://github.com/stumpwm/stumpwm + + (ql:quickload "clx") + (ql:quickload "cl-ppcre") + (ql:quickload "alexandria") + (ql:quickload "xembed") + + ./autogen.sh + ./configure + make + sudo make install + + cd ~/.stumpwm.d/ + git clone https://github.com/sjl/stumpwm-contrib modules + cd modules + git co sjl + +Set up `pass`: + + git clone sjl@redacted:password-store .password-store + sudo apt install pass scdaemon pinentry-gtk2 + gpg -a --export 5D... > public-key.txt + copy over + gpg --import < public-key.txt + +Pulseaudio crap: + + sudo apt install pulseaudio alsa-utils + pulseaudio --start + alsamixer + (m to unmute, up/down to change vol) + +Set up Firefox: + + wget 'https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64&lang=en-US' + aunpack fi… + mv firefox /opt/ + cd /opt/ + chown -R root:root firefox + ln -s /opt/firefox/firefox /usr/local/bin/firefox + sudo apt install libgtk-3-0 libdbus-glib-1-2 + finish the rest of this garbage https://wiki.debian.org/Firefox#Hardware_Video_Acceleration + +VLC (installs the world, sigh): + + sudo apt install vlc + View > Docked Playlist to unbreak the playlist + +UM VPN: + + TODO diff -r 93d27886c099 -r 62e329839625 dunstrc --- a/dunstrc Sun May 18 14:59:11 2025 -0400 +++ b/dunstrc Wed Aug 27 16:19:24 2025 -0400 @@ -22,6 +22,7 @@ browser = xdg-open frame_width = 1 frame_color = "#000000" + icon_position = off [urgency_low] background = "#ffffff" diff -r 93d27886c099 -r 62e329839625 fish/config.fish --- a/fish/config.fish Sun May 18 14:59:11 2025 -0400 +++ b/fish/config.fish Wed Aug 27 16:19:24 2025 -0400 @@ -6,13 +6,14 @@ function eg; nvim ~/.gitconfig; end function eh; nvim ~/.hgrc; end function ei; hg -R ~/src/inventory/ pull -u; and nvim ~/src/inventory/inventory.markdown; and hg -R ~/src/inventory/ ci -m 'Update inventory'; and hg -R ~/src/inventory/ push; end -function el; cd ~/Dropbox/life; nvim .; end function em; nvim ~/.mutt/muttrc; end -function es; pushd ~/src/stumpwm; e ~/.stumpwmrc; popd; end +function es; pushd ~/src/dotfiles/stumpwm; e stumpwmrc; popd; end function ev; nvim ~/.vimrc; end +function evm; nvim ~/.vimrc-minimal; end function eff; nvim ~/.config/fish/functions; end function efh; nvim ~/.local/share/fish/fish_history; end # I have visited https://github.com/fish-shell/fish-shell/issues/862 nine thousand times and I'm fucking sick of opening a web browser to figure out where the fuck fish keeps its equivalent of ~/.bash_history function essh; nvim ~/.ssh/config; end +function est; nvim ~/Sync/school/TODO; end function js; cd ~/scratch; end function jd; cd /dump; end @@ -33,6 +34,10 @@ end end +function mcd --argument dir + mkdir "$dir"; and cd "$dir" +end + alias sin singularity alias sm snakemake @@ -46,6 +51,7 @@ abbr --add ai "sudo apt install" abbr --add sc "sudo systemctl" +abbr --add paper --set-cursor=% "cp -t . ~/Sync/papers/files/%" # }}} # Completions {{{ @@ -62,6 +68,7 @@ complete -c ew -w which complete -c h -w hg complete -c g -w git +complete -c hl -w less # }}} # Bind Keys {{{ @@ -108,6 +115,7 @@ prepend_to_path "$HOME/src/hg" prepend_to_path "$HOME/bin" prepend_to_path "$HOME/.go/bin" +prepend_to_path "$HOME/bin/jdk-21.0.2/bin" set BROWSER open @@ -118,6 +126,8 @@ set -g -x PAGER 'less -iX' # set -g -x _JAVA_OPTIONS "-Djava.awt.headless=true" +set -g -x JAVA_HOME "$HOME/bin/jdk-21.0.2/" + set -g -x GPG_TTY (tty) # Less Colors for Man Pages @@ -193,9 +203,23 @@ end end +function hg-managed + set --local d "$(pwd)" + while test "/" != "$d" + if test -d "$d/.hg" + return 0 + end + set d (path dirname "$d") + end + + return 1 +end + function hg_prompt if test -z "$NOVCSPROMPT" - hg prompt --angle-brackets $hg_promptstring 2>/dev/null + if hg-managed + hg prompt --angle-brackets $hg_promptstring 2>/dev/null + end end end diff -r 93d27886c099 -r 62e329839625 fish/functions/el.fish --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fish/functions/el.fish Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,8 @@ +function el -d "Edit lab notes" + pushd ~/lab + ./pull.sh + nvim README.markdown + hg ci -m 'Update' + ./push.sh + popd +end diff -r 93d27886c099 -r 62e329839625 fish/functions/eln.fish --- a/fish/functions/eln.fish Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -function ep -d "Edit lab notes" - pushd ~/lab - hg pull -u - nvim README.markdown - hg ci -m 'Update' - hg push - popd -end diff -r 93d27886c099 -r 62e329839625 fish/functions/mutt.fish --- a/fish/functions/mutt.fish Sun May 18 14:59:11 2025 -0400 +++ b/fish/functions/mutt.fish Wed Aug 27 16:19:24 2025 -0400 @@ -1,5 +1,5 @@ set -g -x MUTT_BIN (which neomutt) function mutt - bash --login -c "cd ~/Downloads; $MUTT_BIN \$@" custom_mutt $argv + bash --login -c "cd ~/downloads; $MUTT_BIN \$@" custom_mutt $argv end diff -r 93d27886c099 -r 62e329839625 fish/functions/pj.fish --- a/fish/functions/pj.fish Sun May 18 14:59:11 2025 -0400 +++ b/fish/functions/pj.fish Wed Aug 27 16:19:24 2025 -0400 @@ -1,9 +1,9 @@ function pj -d "Prettify JSON" if test "$argv[1]" = "-C" # no color - python -m json.tool + python3 -m json.tool else - python -m json.tool | pygmentize -l json + python3 -m json.tool | pygmentize -l json end end diff -r 93d27886c099 -r 62e329839625 gitconfig --- a/gitconfig Sun May 18 14:59:11 2025 -0400 +++ b/gitconfig Wed Aug 27 16:19:24 2025 -0400 @@ -94,6 +94,7 @@ fuom = "!sh -c 'git co $(git mainbranch) && git fo && git uo' -" fuum = "!sh -c 'git co $(git mainbranch) && git fu && git uu' -" rom = "!sh -c 'git fo && git rebase origin/$(git mainbranch)' -" + jom = "!sh -c 'git join origin/$(git mainbranch)' -" recon = rebase --continue addremove = !git add . && git add -u @@ -138,20 +139,28 @@ path = ~/.gitconfig_local [credential] - helper = store - useHttpPath = true + helper = store + useHttpPath = false + +[credential "https://github.com"] + username = sjl [sendemail] smtpserver = "/home/sjl/src/dotfiles/bin/msmtp-stevelosh" [pretty] bazel = %C(auto)%H %Cgreen%cd %C(auto)%s %Cred%al %C(auto)%d + [pull] ff = only + [filter "lfs"] clean = git-lfs clean -- %f smudge = git-lfs smudge -- %f process = git-lfs filter-process required = true + [diff "lfs"] textconv = cat +[init] + defaultBranch = main diff -r 93d27886c099 -r 62e329839625 gitignore --- a/gitignore Sun May 18 14:59:11 2025 -0400 +++ b/gitignore Wed Aug 27 16:19:24 2025 -0400 @@ -17,5 +17,9 @@ *.dx64fsl .sjl-rsync-exclude sjl-jupyter +sjl-sync-*.sh +sjl-*-push.sh +sjl-*-pull.sh +*.sif *.waiting diff -r 93d27886c099 -r 62e329839625 hgignore --- a/hgignore Sun May 18 14:59:11 2025 -0400 +++ b/hgignore Wed Aug 27 16:19:24 2025 -0400 @@ -8,3 +8,4 @@ *.dx64fsl *.lx64fsl .notmylispwords +.ipynb_checkpoints diff -r 93d27886c099 -r 62e329839625 hgrc --- a/hgrc Sun May 18 14:59:11 2025 -0400 +++ b/hgrc Wed Aug 27 16:19:24 2025 -0400 @@ -125,9 +125,11 @@ # Some useful little aliases. st = status -SC +stl = !"$HG" status -SC --color=always | less -SR ? = summary fdiff = diff -U 10000000000000 + # Push to the git mirror at the same time. pg = !"$HG" push; "$HG" push git @@ -136,10 +138,9 @@ # Commit message shortcuts. cm = commit -m -cus = commit -m 'Update subrepository state' -cmm = commit -m 'Merge' -ct = commit -m 'Update TODO' TODO .TODO.done -cb = commit -m 'Close branch' --close-branch +cmore = commit -m 'More' +cmerge = commit -m 'Merge' +cus = commit -m 'Update subrepository state' # Merge shortcuts. mergelocal = !$HG --config ui.merge=internal:local merge $@ diff -r 93d27886c099 -r 62e329839625 htoprc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/htoprc Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,63 @@ +# Beware! This file is rewritten by htop when settings are changed in the interface. +# The parser is also very primitive, and not human-friendly. +htop_version=3.2.2 +config_reader_min_version=3 +fields=0 48 17 18 39 2 46 47 49 1 +hide_kernel_threads=0 +hide_userland_threads=1 +hide_running_in_container=0 +shadow_other_users=0 +show_thread_names=0 +show_program_path=1 +highlight_base_name=1 +highlight_deleted_exe=1 +shadow_distribution_path_prefix=0 +highlight_megabytes=1 +highlight_threads=1 +highlight_changes=1 +highlight_changes_delay_secs=5 +find_comm_in_cmdline=1 +strip_exe_from_cmdline=1 +show_merged_command=0 +header_margin=1 +screen_tabs=1 +detailed_cpu_time=0 +cpu_count_from_one=0 +show_cpu_usage=1 +show_cpu_frequency=0 +show_cpu_temperature=0 +degree_fahrenheit=0 +update_process_names=0 +account_guest_in_cpu_meter=0 +color_scheme=0 +enable_mouse=1 +delay=10 +hide_function_bar=0 +header_layout=two_50_50 +column_meters_0=LeftCPUs2 Memory Swap +column_meter_modes_0=1 1 1 +column_meters_1=RightCPUs2 Tasks LoadAverage Uptime +column_meter_modes_1=1 2 2 2 +tree_view=1 +sort_key=46 +tree_sort_key=0 +sort_direction=-1 +tree_sort_direction=1 +tree_view_always_by_pid=1 +all_branches_collapsed=0 +screen:Main=PID USER PRIORITY NICE M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command +.sort_key=PERCENT_CPU +.tree_sort_key=PID +.tree_view=1 +.tree_view_always_by_pid=1 +.sort_direction=-1 +.tree_sort_direction=1 +.all_branches_collapsed=0 +screen:I/O=PID USER IO_PRIORITY IO_RATE IO_READ_RATE IO_WRITE_RATE PERCENT_SWAP_DELAY PERCENT_IO_DELAY Command +.sort_key=IO_RATE +.tree_sort_key=PID +.tree_view=0 +.tree_view_always_by_pid=0 +.sort_direction=-1 +.tree_sort_direction=1 +.all_branches_collapsed=0 diff -r 93d27886c099 -r 62e329839625 lisp/batchcolor.lisp --- a/lisp/batchcolor.lisp Sun May 18 14:59:11 2025 -0400 +++ b/lisp/batchcolor.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -10,6 +10,7 @@ ;;;; Configuration ------------------------------------------------------------ (defparameter *start* 0) (defparameter *dark* t) +(defparameter *multi* t) ;;;; Errors ------------------------------------------------------------------- @@ -67,10 +68,14 @@ (defun find-color (string) (gethash string *explicits* - (let ((colors (if *dark* *dark-colors* *light-colors*))) - (aref colors - (mod (+ (djb2 string) *start*) - (length colors)))))) + (if *multi* + (let ((colors (if *dark* *dark-colors* *light-colors*))) + (aref colors + (mod (+ (djb2 string) *start*) + (length colors)))) + (if *dark* + (rgb-code 5 2 3) + (rgb-code 2 0 2))))) (defun ansi-color-start (color) (format nil "~C[38;5;~Dm" #\Escape color)) @@ -128,6 +133,13 @@ (return-from parse-explicit (cons string (rgb-code r g b)))) (error 'malformed-explicit :spec spec)) +(adopt:defparameters (*option-multicolor* *option-no-multicolor*) + (adopt:make-boolean-options 'multicolor + :help "Use different colors for different matches (the default)." + :help-no "Use a single color for everything (a useful kludge)." + :long "multicolor" + :short #\m + :initial-value t)) (adopt:defparameters (*option-randomize* *option-no-randomize*) (adopt:make-boolean-options 'randomize @@ -187,6 +199,9 @@ "If no FILEs are given, standard input will be used. A file of - stands for ~ standard input as well.~@ ~@ + As a handy kludge, the --no-multicolor option can be used to highlight ~ + everything in a single color.~@ + ~@ Overlapping capturing groups are not supported because it's not clear what ~ the result should be. For example: what should ((f)oo|(b)oo) highlight when ~ matched against 'foo'? Should it highlight 'foo' in one color? The 'f' in ~ @@ -224,7 +239,9 @@ *option-no-randomize* *option-dark* *option-light* - *option-explicit*))))) + *option-explicit* + *option-multicolor* + *option-no-multicolor*))))) (defmacro exit-on-ctrl-c (&body body) @@ -237,7 +254,8 @@ (setf *start* (if (gethash 'randomize options) (random 256 (make-random-state t)) 0) - *dark* (gethash 'dark options))) + *dark* (gethash 'dark options) + *multi* (gethash 'multicolor options))) (defun toplevel () (sb-ext:disable-debugger) diff -r 93d27886c099 -r 62e329839625 lisp/build-binary.sh diff -r 93d27886c099 -r 62e329839625 lisp/clhs.lisp --- a/lisp/clhs.lisp Sun May 18 14:59:11 2025 -0400 +++ b/lisp/clhs.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -77,7 +77,8 @@ :direction :output :if-exists :supersede :if-does-not-exist :create) - (prin1 symbols out)) + (let ((*print-length* nil)) + (prin1 symbols out))) symbols))) (defun symbol-map () diff -r 93d27886c099 -r 62e329839625 lisp/parens.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/parens.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,58 @@ +(eval-when (:compile-toplevel :load-toplevel :execute) + (ql:quickload + '(:adopt :losh :parenscript) + :silent t)) + +(defpackage :parens + (:use :cl :iterate :losh) + (:export :toplevel :*ui*)) + +(defpackage :parenscript-user + (:use :cl :parenscript)) + +(in-package :parens) + +;;;; Run ---------------------------------------------------------------------- +(defun compile-with-parenscript (in-stream out-stream) + (let ((parenscript:*parenscript-stream* out-stream)) + (ps:ps-compile-stream in-stream))) + +(defun run () + (compile-with-parenscript *standard-input* *standard-output*)) + + +;;;; User Interface ----------------------------------------------------------- +(defparameter *option-help* + (adopt:make-option 'help + :help "Display help and exit." + :long "help" + :short #\h + :reduce (constantly t))) + + +(adopt:define-string *help-text* + "parens is a helper program to invoke the parenscript compiler for standalone ~ + files, so you can just use parenscript without the Common Lisp bits.") + +(defparameter *examples* + '(("Compile:" . "cat foo.lisp | parens > out.js"))) + +(defparameter *ui* + (adopt:make-interface + :name "parens" + :usage "[OPTIONS]" + :summary "standalone parenscript compiler" + :help *help-text* + :examples *examples* + :contents (list *option-help*))) + + +(defun toplevel () + (multiple-value-bind (arguments options) (adopt:parse-options-or-exit *ui*) + (handler-case + (if (gethash 'help options) + (adopt:print-help-and-exit *ui*) + (progn (assert (null arguments)) + (run))) + (error (e) (adopt:print-error-and-exit e))))) + diff -r 93d27886c099 -r 62e329839625 lisp/weather.lisp --- a/lisp/weather.lisp Sun May 18 14:59:11 2025 -0400 +++ b/lisp/weather.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -1,6 +1,6 @@ (eval-when (:compile-toplevel :load-toplevel :execute) (ql:quickload - '(:adopt :with-user-abort :split-sequence :iterate :losh :drakma :jarl :flexi-streams :local-time) + '(:adopt :with-user-abort :split-sequence :iterate :losh :drakma :jarl :flexi-streams :local-time :safe-read) :silent t)) (defpackage :weather @@ -10,6 +10,10 @@ (in-package :weather) +(defpackage :conf + (:use) + (:export :zip-code)) + ;;;; Zip Codes ---------------------------------------------------------------- (defun load-zip-code-coordinates () @@ -28,27 +32,27 @@ ;;;; Config ------------------------------------------------------------------- (defvar *api-token* nil) +(defvar *zip-code* nil) (defun load-config () (let* ((token-paths (uiop:xdg-config-pathnames "weather/api-token")) (config-paths (uiop:xdg-config-pathnames "weather/config")) (token-path (find-if #'probe-file token-paths)) (config-paths (reverse (remove-if-not #'probe-file config-paths)))) - (declare (ignore config-paths)) ; TODO (if (null token-path) (error "Cannot find API token file at any of the following paths:~2%~ ~{ ~A~%~}~%~ Visit https://home.openweathermap.org/api_keys to get one." token-paths) (setf *api-token* (string-trim '(#\space #\newline) - (alexandria:read-file-into-string token-path)))))) + (alexandria:read-file-into-string token-path)))) + (dolist (config-path config-paths) + (with-open-file (f config-path) + (let ((config (safe-read:safe-read f (list :conf)))) + (setf *zip-code* (getf config 'conf:zip-code *zip-code*))))))) ;;;; OpenWeatherMap ----------------------------------------------------------- -;;; TODO Switch to weather.gov some day to get my taxes' worth, e.g. -;;; https://forecast.weather.gov/MapClick.php?lat=43.1577&lon=-77.6066&FcstType=digitalDWML -;;; Sadly this is XML. - (defclass* response () ((hourly :json (vector hour))) (:metaclass jarl:json-class)) @@ -84,8 +88,9 @@ (defun query-weather (latitude longitude) + (assert *api-token* () "API token not loaded, call (load-config) first.") (multiple-value-bind (body status headers uri stream needs-close reason) - (drakma:http-request (format nil "https://api.openweathermap.org/data/2.5/onecall") + (drakma:http-request (format nil "https://api.openweathermap.org/data/3.0/onecall") :redirect t :parameters `(("lat" . ,latitude) ("lon" . ,longitude) @@ -105,13 +110,16 @@ (defun display-hour (hour &optional force-date) (let* ((ts (timestamp hour)) - (h (local-time:timestamp-hour ts))) - (format t "~12A ~2,'0D:00 ~4D°F ~4D% ~{~A~^, ~}~%" + (h (local-time:timestamp-hour ts)) + (temperature (temperature hour)) + (feels-like (feels-like hour))) + (format t "~12A ~2,'0D:00 ~4D°F ~4D°f ~4D% ~{~A~^, ~}~%" (if (or force-date (zerop h)) (ymd ts) "") h - (round (temperature hour)) + (round temperature) + (round feels-like) (round (* 100 (precipitation hour))) (map 'list #'description (weather hour))))) @@ -179,7 +187,7 @@ (adopt:print-help-and-exit *ui*) (progn (load-config) - (run (or (first arguments) "48105") + (run (or (first arguments) *zip-code*) :hours (gethash 'hours options)))) (error (e) (adopt:print-error-and-exit e)))))) diff -r 93d27886c099 -r 62e329839625 lisprc --- a/lisprc Sun May 18 14:59:11 2025 -0400 +++ b/lisprc Wed Aug 27 16:19:24 2025 -0400 @@ -22,6 +22,9 @@ (defglobal ,var nil) (setf ,var ,val))) +(defun :vlime () + (load "~/src/dotfiles/vim/bundle/vlime/lisp/start-vlime.lisp")) + ;;;; Scratch Marker ----------------------------------------------------------- (defun sharp-semicolon-reader (stream sub-char numarg) diff -r 93d27886c099 -r 62e329839625 lispwords --- a/lispwords Sun May 18 14:59:11 2025 -0400 +++ b/lispwords Wed Aug 27 16:19:24 2025 -0400 @@ -92,6 +92,7 @@ (1 multiple-value-bind*) (1 do-repeat do-range do-irange do-ring-buffer do-vector do-file do-hash-set) (1 timing profile-when) +(1 recase) ; qtools (1 qtenumcase) @@ -117,7 +118,7 @@ ; ppcre (2 register-groups-bind do-register-groups) -(1 do-scans) +(1 do-scans do-matches) ; lparallel (1 pdotimes) @@ -145,6 +146,19 @@ ; boots (1 event-case) +(2 canvas) ; parsnip (1 let!) + +; sqlite +(1 execute-non-query execute-script execute-to-list execute-single execute-non-query/named execute-single/named execute-to-list/named) + +; easy-routes +(3 defroute) + +; djula +(2 render-template*) + +; cl-who +(1 who) diff -r 93d27886c099 -r 62e329839625 man/index.db Binary file man/index.db has changed diff -r 93d27886c099 -r 62e329839625 mbsyncrc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbsyncrc Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,81 @@ +# tweaked https://raw.githubusercontent.com/bm4cs/dots/Far/.mbsyncrc + +IMAPAccount fastmail +Host imap.fastmail.com +Port 993 +User steve@stevelosh.com +PassCmd "pass show mutt/ouroboros/steve@stevelosh.com | head -n 1" +SSLType IMAPS +SSLVersion TLSv1.2 +CertificateFile /etc/ssl/certs/ca-certificates.crt + +# Remote +IMAPStore mail-remote +Account fastmail + +# Local +MaildirStore mail-local +Subfolders Verbatim +Path ~/.mail2/sjl/ +Inbox ~/.mail2/sjl/INBOX + +# CONNECTIONS SPECIFY LINKS BETWEEN REMOTE AND LOCAL FOLDERS +# CONNECTIONS ARE SPECIFIED USING PATTERNS, WHICH MATCH REMOTE MAIl +# FOLDERS. SOME COMMONLY USED PATTERS INCLUDE: +# +# 1 "*" TO MATCH EVERYTHING +# 2 "!DIR" TO EXCLUDE "DIR" +# 3 "DIR" TO MATCH DIR + +Channel mail-inbox +Far :mail-remote: +Near :mail-local: +Patterns INBOX +Create Near +Sync All +Expunge Both +SyncState * + +Channel mail-sent +Far :mail-remote: +Near :mail-local: +Patterns "Sent" +Create Both +Sync All +Expunge Both +SyncState * + +Channel mail-spam +Far :mail-remote: +Near :mail-local: +Patterns "Uncaught Spam" +Create Near +Sync All +Expunge Both +SyncState * + +Channel mail-drafts +Far :mail-remote: +Near :mail-local: +Patterns "Drafts" +Create Near +Sync All +Expunge Both +SyncState * + +Channel mail-archive +Far :mail-remote: +Near :mail-local: +Patterns "Arc*" +Create Near +Sync All +Expunge Both +SyncState * + +Group mail +Channel mail-inbox +Channel mail-spam +Channel mail-drafts +Channel mail-sent +Channel mail-archive + diff -r 93d27886c099 -r 62e329839625 md-to-html/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/md-to-html/Makefile Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,6 @@ +%.html: %.markdown template.html Makefile + pandoc \ + --template template.html \ + --table-of-contents \ + -f markdown -t html \ + "$<" > "$@" diff -r 93d27886c099 -r 62e329839625 md-to-html/foo.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/md-to-html/foo.html Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,57 @@ + + + + + Some Test + + + +

Some Test

+ +

Example

+

This is a test.

+
Some code.
+

Done testing.

+ + diff -r 93d27886c099 -r 62e329839625 md-to-html/foo.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/md-to-html/foo.markdown Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,11 @@ +--- +title: Some Test +--- + +## Example + +This is a test. + + Some code. + +Done testing. diff -r 93d27886c099 -r 62e329839625 md-to-html/template.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/md-to-html/template.html Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,63 @@ + + + + + $title$ + + + +

$title$

+
+ Table of contents +
$toc$
+
+ +$body$ + + + diff -r 93d27886c099 -r 62e329839625 remote/bash_profile --- a/remote/bash_profile Sun May 18 14:59:11 2025 -0400 +++ b/remote/bash_profile Wed Aug 27 16:19:24 2025 -0400 @@ -8,6 +8,7 @@ shopt -s expand_aliases shopt -s histappend +shopt -s checkwinsize # Save multiline commands as a single history entry. shopt -s cmdhist @@ -23,12 +24,12 @@ eval "$(dircolors -b ~/.dircolors)" fi -D=$'\e[37m' -RED=$'\e[31m' -GREEN=$'\e[32m' -ORANGE=$'\e[33m' -BLUE=$'\e[34m' -PINK=$'\e[35m' +D=$'\x01\e[37m\x02' +RED=$'\x01\e[31m\x02' +GREEN=$'\x01\e[32m\x02' +ORANGE=$'\x01\e[33m\x02' +BLUE=$'\x01\e[34m\x02' +PINK=$'\x01\e[35m\x02' # CYAN=$'\e[36m' function last_return_value() { @@ -42,13 +43,22 @@ history | grep "$@" | tac | f 2- } +function mcd { + mkdir "$1" && cd "$1" +} + if [ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ]; then HOST_COLOR="$BLUE" else HOST_COLOR="$ORANGE" fi -export PS1='\n${PINK}\u ${D}at ${HOST_COLOR}\h ${D}in ${GREEN}\w${D} $(last_return_value)$ ' +PS1_HOST='\h' +if test -e ~/.cosmetic_hostname; then + PS1_HOST=$(cat ~/.cosmetic_hostname) +fi + +export PS1='\n${PINK}\u ${D}at ${HOST_COLOR}'"$PS1_HOST"' ${D}in ${GREEN}\w${D} $(last_return_value)$ ' alias ..="cd .." alias ...="cd ../.." @@ -56,8 +66,6 @@ alias .....="cd ../../../.." alias ......="cd ../../../../.." -alias js='cd ~/scratch' - alias :q=exit alias :qa=exit alias :wqa=exit @@ -101,3 +109,12 @@ export GPG_TTY export EDITOR=vim + +export _Z_CMD=j +export _Z_DATA=$HOME/.z-bash + +. $HOME/src/dotfiles/z.sh + +if [ -f $HOME/.bash_profile_sjl_local ]; then + source $HOME/.bash_profile_sjl_local +fi diff -r 93d27886c099 -r 62e329839625 remote/bin/arblogs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/arblogs Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail + +sudo journalctl -fu arb_sequencing_worker "$@" \ + | batchcolor '(ERROR|WARNING|INFO|[0-9]{8}_[0-9]{4}_[-A-Z0-9]+_[A-Z0-9]+_[a-z0-9]{8}|Checking for.* in )' \ + | cut -d ' ' -f 6- diff -r 93d27886c099 -r 62e329839625 remote/bin/bclogs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/bclogs Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +set -euo pipefail + +sudo journalctl -fu arb_basecalling_worker "$@" \ + | batchcolor '(ERROR|WARNING|INFO|[0-9]{8}_[0-9]{4}_[-A-Z0-9]+_[A-Z0-9]+_[a-z0-9]{8}|Checking for.* in )' \ + | cut -d ' ' -f 6- diff -r 93d27886c099 -r 62e329839625 remote/bin/cax --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/cax Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/cax \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/csv2tsv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/csv2tsv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/csv2tsv \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/csvconcat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/csvconcat Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/csvconcat \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/cux --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/cux Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/cux \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/cv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/cv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/cv \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/cvs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/cvs Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/cvs \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/f, --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/f, Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/f, \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/fnums --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/fnums Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/fnums \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/lesss --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/lesss Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/lesss \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/lines --- a/remote/bin/lines Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../../lisp/bin/lines \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/minimap2-index --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/minimap2-index Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/minimap2-index \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/mksb --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/mksb Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +set -euo pipefail + +name="$1" + +read -p "Account? " +acct="$REPLY" + +read -p "Hours? " +hours="$REPLY" + +read -p "CPUs? " +cpus="$REPLY" + +read -p "Memory (gb)? " +mem_gb="$REPLY" +mem_mb=$(( mem_gb * 1024 )) + +cat << EOF > "$name".sbat +#!/usr/bin/env bash + +#SBATCH --job-name=$name +#SBATCH --mail-type=END +#SBATCH --nodes=1 +#SBATCH --ntasks-per-node=1 +#SBATCH --cpus-per-task=$cpus +#SBATCH --mem=$mem_mb +#SBATCH --time=$hours:00:00 +#SBATCH --account=$acct +#SBATCH --partition=standard +#SBATCH --output=slurm-%x-%j.log +#SBATCH --export=NONE + +set -euo pipefail + +my_job_header +echo +echo Arguments: "\$@" +echo + +EOF + +chmod u+x "$name.sbat" + +"$EDITOR" "$name.sbat" diff -r 93d27886c099 -r 62e329839625 remote/bin/nicedate --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/nicedate Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/nicedate \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/ont-basecalling-model-info --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/ont-basecalling-model-info Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +set -euo pipefail + +bam_file="$1" + +module load Bioinformatics samtools >/dev/null 2>&1 + +# view all the SAM headers +# only look at @RG +# pull out the basecall_model=… field +# coalesce + +samtools view -H "$bam_file" \ + | grep -P '^@RG' \ + | grep -P -o $'basecall_model=[^ \t]+' \ + | sort | uniq -c + +samtools view -H "$bam_file" \ + | grep -P '^@RG' \ + | grep -P -o $'modbase_models=[^ \t]+' \ + | sort | uniq -c diff -r 93d27886c099 -r 62e329839625 remote/bin/potential-to-bed --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/potential-to-bed Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -euo pipefail + +cut -f 1-4,8- | awk -F'\t' -v OFS='\t' '{print $1, $2, $3, $4 " " $5}' diff -r 93d27886c099 -r 62e329839625 remote/bin/run-igv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/run-igv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail + +module load openjdk +~/src/igv/build/IGV-dist/igv.sh diff -r 93d27886c099 -r 62e329839625 remote/bin/slurm-shell --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/slurm-shell Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -euo pipefail + +read -p "Account? " +acct="$REPLY" + +read -p "Hours? " +hours="$REPLY" + +read -p "CPUs? " +cpus="$REPLY" + +read -p "Memory (gb)? " +mem_gb="$REPLY" +mem_kb=$(( mem_gb * 1024 * 1024 / cpus )) + +read -p "X11? " +case $REPLY in + y | yes | Y | YES) + x11="--x11" + ;; + + *) + x11="" + ;; +esac + +if test -z "$x11"; then + exec salloc --account="$acct" --nodes=1 --ntasks-per-node=1 --mem-per-cpu="$mem_kb"K --cpus-per-task="$cpus" --time="$hours":00:00 +else + exec salloc --account="$acct" --nodes=1 --ntasks-per-node=1 --mem-per-cpu="$mem_kb"K --cpus-per-task="$cpus" --time="$hours":00:00 --x11 +fi diff -r 93d27886c099 -r 62e329839625 remote/bin/sv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/sv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/sv \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/temps --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/temps Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/temps \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/trst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/trst Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/trst \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/tsv2csv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/tsv2csv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/tsv2csv \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/tv --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/tv Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/tv \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bin/tvs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/bin/tvs Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../../bin/tvs \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/bootstrap.sh --- a/remote/bootstrap.sh Sun May 18 14:59:11 2025 -0400 +++ b/remote/bootstrap.sh Wed Aug 27 16:19:24 2025 -0400 @@ -21,12 +21,21 @@ mkdir -p ~/.config/fish mkdir -p ~/.config/nvim +mkdir -p ~/.config/htop mkdir -p ~/bin +mkdir -p ~/.vim +mkdir -p ~/.terminfo/s +ensure_link "src/dotfiles/bash_profile" ".bash_profile" +ensure_link "src/dotfiles/config.fish" ".config/fish/config.fish" +ensure_link "src/dotfiles/dircolors" ".dircolors" +ensure_link "src/dotfiles/ffignore" ".ffignore" ensure_link "src/dotfiles/gitconfig" ".gitconfig" ensure_link "src/dotfiles/gitignore" ".gitignore" -ensure_link "src/dotfiles/bash_profile" ".bash_profile" -ensure_link "src/dotfiles/dircolors" ".dircolors" -ensure_link "src/dotfiles/ffignore" ".ffignore" -ensure_link "src/dotfiles/config.fish" ".config/fish/config.fish" +ensure_link "src/dotfiles/htoprc" ".config/htop/htoprc" ensure_link "src/dotfiles/hushlogin" ".hushlogin" +ensure_link "src/dotfiles/st" ".terminfo/s/st" +ensure_link "src/dotfiles/st-256color" ".terminfo/s/st-256color" +ensure_link "src/dotfiles/vim-colors" ".vim/colors" +ensure_link "src/dotfiles/vimrc" ".vimrc" +ensure_link "src/dotfiles/vimrc-remote-local" ".vimrc_remote_local" diff -r 93d27886c099 -r 62e329839625 remote/htoprc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/htoprc Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../htoprc \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/st Binary file remote/st has changed diff -r 93d27886c099 -r 62e329839625 remote/st-256color Binary file remote/st-256color has changed diff -r 93d27886c099 -r 62e329839625 remote/vim-colors --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/vim-colors Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../vim/bundle/badwolf/colors/ \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/vimrc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/vimrc Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../vim/vimrc-minimal \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 remote/vimrc-remote-local --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/vimrc-remote-local Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +colorscheme badwolf diff -r 93d27886c099 -r 62e329839625 remote/z.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/remote/z.sh Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,267 @@ +# Copyright (c) 2009 rupa deadwyler. Licensed under the WTFPL license, Version 2 + +# maintains a jump-list of the directories you actually use +# +# INSTALL: +# * put something like this in your .bashrc/.zshrc: +# . /path/to/z.sh +# * cd around for a while to build up the db +# * PROFIT!! +# * optionally: +# set $_Z_CMD in .bashrc/.zshrc to change the command (default z). +# set $_Z_DATA in .bashrc/.zshrc to change the datafile (default ~/.z). +# set $_Z_MAX_SCORE lower to age entries out faster (default 9000). +# set $_Z_NO_RESOLVE_SYMLINKS to prevent symlink resolution. +# set $_Z_NO_PROMPT_COMMAND if you're handling PROMPT_COMMAND yourself. +# set $_Z_EXCLUDE_DIRS to an array of directories to exclude. +# set $_Z_OWNER to your username if you want use z while sudo with $HOME kept +# +# USE: +# * z foo # cd to most frecent dir matching foo +# * z foo bar # cd to most frecent dir matching foo and bar +# * z -r foo # cd to highest ranked dir matching foo +# * z -t foo # cd to most recently accessed dir matching foo +# * z -l foo # list matches instead of cd +# * z -e foo # echo the best match, don't cd +# * z -c foo # restrict matches to subdirs of $PWD +# * z -x # remove the current directory from the datafile +# * z -h # show a brief help message + +[ -d "${_Z_DATA:-$HOME/.z}" ] && { + echo "ERROR: z.sh's datafile (${_Z_DATA:-$HOME/.z}) is a directory." +} + +_z() { + + local datafile="${_Z_DATA:-$HOME/.z}" + + # if symlink, dereference + [ -h "$datafile" ] && datafile=$(readlink "$datafile") + + # bail if we don't own ~/.z and $_Z_OWNER not set + [ -z "$_Z_OWNER" -a -f "$datafile" -a ! -O "$datafile" ] && return + + _z_dirs () { + [ -f "$datafile" ] || return + + local line + while read line; do + # only count directories + [ -d "${line%%\|*}" ] && echo "$line" + done < "$datafile" + return 0 + } + + # add entries + if [ "$1" = "--add" ]; then + shift + + # $HOME and / aren't worth matching + [ "$*" = "$HOME" -o "$*" = '/' ] && return + + # don't track excluded directory trees + if [ ${#_Z_EXCLUDE_DIRS[@]} -gt 0 ]; then + local exclude + for exclude in "${_Z_EXCLUDE_DIRS[@]}"; do + case "$*" in "$exclude"*) return;; esac + done + fi + + # maintain the data file + local tempfile="$datafile.$RANDOM" + local score=${_Z_MAX_SCORE:-9000} + _z_dirs | awk -v path="$*" -v now="$(date +%s)" -v score=$score -F"|" ' + BEGIN { + rank[path] = 1 + time[path] = now + } + $2 >= 1 { + # drop ranks below 1 + if( $1 == path ) { + rank[$1] = $2 + 1 + time[$1] = now + } else { + rank[$1] = $2 + time[$1] = $3 + } + count += $2 + } + END { + if( count > score ) { + # aging + for( x in rank ) print x "|" 0.99*rank[x] "|" time[x] + } else for( x in rank ) print x "|" rank[x] "|" time[x] + } + ' 2>/dev/null >| "$tempfile" + # do our best to avoid clobbering the datafile in a race condition. + if [ $? -ne 0 -a -f "$datafile" ]; then + env rm -f "$tempfile" + else + [ "$_Z_OWNER" ] && chown $_Z_OWNER:"$(id -ng $_Z_OWNER)" "$tempfile" + env mv -f "$tempfile" "$datafile" || env rm -f "$tempfile" + fi + + # tab completion + elif [ "$1" = "--complete" -a -s "$datafile" ]; then + _z_dirs | awk -v q="$2" -F"|" ' + BEGIN { + q = substr(q, 3) + if( q == tolower(q) ) imatch = 1 + gsub(/ /, ".*", q) + } + { + if( imatch ) { + if( tolower($1) ~ q ) print $1 + } else if( $1 ~ q ) print $1 + } + ' 2>/dev/null + + else + # list/go + local echo fnd last list opt typ + while [ "$1" ]; do case "$1" in + --) while [ "$1" ]; do shift; fnd="$fnd${fnd:+ }$1";done;; + -*) opt=${1:1}; while [ "$opt" ]; do case ${opt:0:1} in + c) fnd="^$PWD $fnd";; + e) echo=1;; + h) echo "${_Z_CMD:-z} [-cehlrtx] args" >&2; return;; + l) list=1;; + r) typ="rank";; + t) typ="recent";; + x) sed -i -e "\:^${PWD}|.*:d" "$datafile";; + esac; opt=${opt:1}; done;; + *) fnd="$fnd${fnd:+ }$1";; + esac; last=$1; [ "$#" -gt 0 ] && shift; done + [ "$fnd" -a "$fnd" != "^$PWD " ] || list=1 + + # if we hit enter on a completion just go there + case "$last" in + # completions will always start with / + /*) [ -z "$list" -a -d "$last" ] && builtin cd "$last" && return;; + esac + + # no file yet + [ -f "$datafile" ] || return + + local cd + cd="$( < <( _z_dirs ) awk -v t="$(date +%s)" -v list="$list" -v typ="$typ" -v q="$fnd" -F"|" ' + function frecent(rank, time) { + # relate frequency and time + dx = t - time + return int(10000 * rank * (3.75/((0.0001 * dx + 1) + 0.25))) + } + function output(matches, best_match, common) { + # list or return the desired directory + if( list ) { + if( common ) { + printf "%-10s %s\n", "common:", common > "/dev/stderr" + } + cmd = "sort -n >&2" + for( x in matches ) { + if( matches[x] ) { + printf "%-10s %s\n", matches[x], x | cmd + } + } + } else { + if( common && !typ ) best_match = common + print best_match + } + } + function common(matches) { + # find the common root of a list of matches, if it exists + for( x in matches ) { + if( matches[x] && (!short || length(x) < length(short)) ) { + short = x + } + } + if( short == "/" ) return + for( x in matches ) if( matches[x] && index(x, short) != 1 ) { + return + } + return short + } + BEGIN { + gsub(" ", ".*", q) + hi_rank = ihi_rank = -9999999999 + } + { + if( typ == "rank" ) { + rank = $2 + } else if( typ == "recent" ) { + rank = $3 - t + } else rank = frecent($2, $3) + if( $1 ~ q ) { + matches[$1] = rank + } else if( tolower($1) ~ tolower(q) ) imatches[$1] = rank + if( matches[$1] && matches[$1] > hi_rank ) { + best_match = $1 + hi_rank = matches[$1] + } else if( imatches[$1] && imatches[$1] > ihi_rank ) { + ibest_match = $1 + ihi_rank = imatches[$1] + } + } + END { + # prefer case sensitive + if( best_match ) { + output(matches, best_match, common(matches)) + exit + } else if( ibest_match ) { + output(imatches, ibest_match, common(imatches)) + exit + } + exit(1) + } + ')" + + if [ "$?" -eq 0 ]; then + if [ "$cd" ]; then + if [ "$echo" ]; then echo "$cd"; else builtin cd "$cd"; fi + fi + else + return $? + fi + fi +} + +alias ${_Z_CMD:-z}='_z 2>&1' + +[ "$_Z_NO_RESOLVE_SYMLINKS" ] || _Z_RESOLVE_SYMLINKS="-P" + +if type compctl >/dev/null 2>&1; then + # zsh + [ "$_Z_NO_PROMPT_COMMAND" ] || { + # populate directory list, avoid clobbering any other precmds. + if [ "$_Z_NO_RESOLVE_SYMLINKS" ]; then + _z_precmd() { + (_z --add "${PWD:a}" &) + : $RANDOM + } + else + _z_precmd() { + (_z --add "${PWD:A}" &) + : $RANDOM + } + fi + [[ -n "${precmd_functions[(r)_z_precmd]}" ]] || { + precmd_functions[$(($#precmd_functions+1))]=_z_precmd + } + } + _z_zsh_tab_completion() { + # tab completion + local compl + read -l compl + reply=(${(f)"$(_z --complete "$compl")"}) + } + compctl -U -K _z_zsh_tab_completion _z +elif type complete >/dev/null 2>&1; then + # bash + # tab completion + complete -o filenames -C '_z --complete "$COMP_LINE"' ${_Z_CMD:-z} + [ "$_Z_NO_PROMPT_COMMAND" ] || { + # populate directory list. avoid clobbering other PROMPT_COMMANDs. + grep "_z --add" <<< "$PROMPT_COMMAND" >/dev/null || { + PROMPT_COMMAND="$PROMPT_COMMAND"$'\n''(_z --add "$(command pwd '$_Z_RESOLVE_SYMLINKS' 2>/dev/null)" 2>/dev/null &);' + } + } +fi diff -r 93d27886c099 -r 62e329839625 sqliterc --- a/sqliterc Sun May 18 14:59:11 2025 -0400 +++ b/sqliterc Wed Aug 27 16:19:24 2025 -0400 @@ -1,5 +1,7 @@ .timer on .headers on -.mode tabs +.mode columns + +.prompt "\nsqlite> " "> " .nullvalue ∅' diff -r 93d27886c099 -r 62e329839625 stumpwm/applications.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/applications.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,37 @@ +(in-package :stumpwm-user) + +(defcommand igv () () + (run-or-raise "igv" '(:class "org-broad-igv-ui-Main"))) + +(defcommand spotify () () + (run-or-raise "spotify" '(:class "Spotify"))) + +(defcommand zoom-meeting () () + (run-or-raise "echom 'No meeting running.'" '(:class "zoom" :title "Meeting"))) + +(defcommand files () () + (run-shell-command "open $HOME")) + +(defcommand browser () () + (run-or-raise "firefox" '(:class "firefox"))) + +(defcommand vlc () () + (run-or-raise "vlc" '(:class "vlc"))) + +(defcommand terminal () () + (run-shell-command (format nil "st -f 'Ubuntu Mono:size=~D'" *terminal-font-size*))) + +(defcommand terminal-in (path) ((:string "Working directory: ")) + (run-shell-command + (format nil "st -f 'Ubuntu Mono:size=~D' env -C '~A' fish" ; todo actually escape this + *terminal-font-size* path))) + +(defcommand terminal-apl () () + (run-shell-command "st -f 'BQN386 Unicode:style=Regular:size=12'")) + +(defcommand gcontrol () () + (run-or-raise "gcontrol" '(:class "Gnome-control-center"))) + +(defcommand papers () () + (run-or-raise "jabref" '(:class "org.jabref.gui.MainApplication"))) + diff -r 93d27886c099 -r 62e329839625 stumpwm/bioinf.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/bioinf.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,74 @@ +(in-package :stumpwm-user) + + +(defun random-base () + (random-elt "GCAT")) + +(defun random-dna-string (n) + (let ((result (make-string n))) + (dotimes (i n) + (setf (char result i) (random-base))) + result)) + +(defcommand random-dna (n) ((:integer "Length: ")) + (pbcopy (random-dna-string n))) + +(defun random-fasta-string (entries entry-length) + (str:join #\newline + (loop :for i :from 0 :below entries + :collect (format nil ">seq ~D" i) + :collect (random-dna-string entry-length)))) + +(defcommand random-fasta + (entries entry-length) + ((:integer "Entries: ") + (:integer "Entry Length: ")) + (check-type entries (integer 1 *)) + (check-type entry-length (integer 1 *)) + (pbcopy (random-fasta-string entries entry-length))) + + +(defun kmers-of (k seq) + (loop :for start :from 0 + :for end :from k :to (length seq) + :collect (subseq seq start end))) + +(defun kmerized-string (k seq) + (with-output-to-string (s) + (loop :for i :from 0 + :for kmer :in (kmers-of k seq) + :do (format s "~,,V,@A~%" i kmer)))) + +(defcommand kmerize (k) ((:integer "k: ")) + (pbcopy (kmerized-string k (pbpaste)))) + +(defun reverse-complement (seq) + (nreverse (map 'string (lambda (base) + (case base + (#\A #\T) + (#\C #\G) + (#\G #\C) + (#\T #\A) + (#\N #\N) + (#\a #\t) + (#\c #\g) + (#\g #\c) + (#\t #\a) + (#\n #\n) + (t #\?))) + seq))) + +(defcommand revcomp () () + (pbcopy (reverse-complement (pbpaste)))) + +(defcommand rev () () + (pbcopy (reverse (pbpaste)))) + + +#; Scratch -------------------------------------------------------------------- + +(random-fasta-string 10 100) + +(format nil "~,,99,@A" "hello") + +(kmers-of 3 "ACTTAC") diff -r 93d27886c099 -r 62e329839625 stumpwm/brightness.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/brightness.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,26 @@ +(in-package :stumpwm-user) + +(defparameter *brightness-values* #(0 1 5 10 20 30 40 55 70 85 100)) +(defvar *brightness-index* 5) + +(defun brightness () + (aref *brightness-values* *brightness-index*)) + +(defun set-brightness (value) + (run-and-echo-shell-command + (hostcase + ((:gro :juss) (format nil "light -S ~D" value)) + (t (message "Not sure how to set brightness on this machine."))))) + +(defun rotate-brightness (delta) + (setf *brightness-index* + (mod+ *brightness-index* delta (length *brightness-values*))) + (set-brightness (brightness))) + + +(defcommand rotate-brightness-up () () + (rotate-brightness 1)) + +(defcommand rotate-brightness-down () () + (rotate-brightness -1)) + diff -r 93d27886c099 -r 62e329839625 stumpwm/budget.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/budget.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,51 @@ +(in-package :stumpwm-user) + +(defparameter *tz/eastern* + (local-time:find-timezone-by-location-name "US/Eastern")) + +(defparameter *budget/start* + (local-time:encode-timestamp 0 0 0 0 29 8 2023 :timezone *tz/eastern*)) + +(defun budget/per-day () + (first (losh:read-all-from-file "/home/sjl/Sync/budget/per-day"))) + +(defun budget/elapsed () + (local-time:timestamp-difference (local-time:now) *budget/start*)) + +(defun budget/days-elapsed () + (floor (/ (budget/elapsed) (* 60 60 24)))) + +(defun budget/in () + (* (budget/days-elapsed) (budget/per-day))) + +(defun budget/out () + (loop :for path :in (directory "/home/sjl/Sync/budget/hosts/*/total") + :summing (print (first (read-all-from-file (print path)))))) + +(defun budget/current () + (- (budget/in) (budget/out))) + +(defcommand budget-dump () () + (message + (sh '("sh" "-c" "tail -n 5 /home/sjl/Sync/budget/hosts/*/records") + :result-type 'string))) + +(defcommand budget () () + (message "$~D" (budget/current))) + +(defmacro with-budget-file ((f file &rest open-args) &body body) + `(with-open-file + (,f (format nil "/home/sjl/Sync/budget/hosts/~(~A~)/~A" *host* ,file) + ,@open-args) + ,@body)) + +(defcommand spend (amount what) ((:integer "Amount: $") (:string "For: ")) + (let ((current (with-budget-file (total "total") + (first (read-all-from-file total)))) + (timestamp (local-time:to-rfc3339-timestring (local-time:now)))) + (with-budget-file (total "total" :direction :output :if-exists :supersede) + (print (+ current amount) total)) + (with-budget-file (records "records" :direction :output :if-exists :append :if-does-not-exist :create) + (print (list timestamp amount what) records)) + (message "Spent $~D for ~A at ~A" amount what timestamp))) + diff -r 93d27886c099 -r 62e329839625 stumpwm/clipboard.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/clipboard.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,12 @@ +(in-package :stumpwm-user) + +(defcommand generate-random-uuid () () + (pbcopy (string-downcase (princ-to-string (uuid:make-v4-uuid)))) + (message "Copied random UUID to clipboard.")) + +(defcommand bee-movie-script () () + (run-shell-command "pbeecopy") + (message "Copied the entire Bee Movie script to clipboard.")) + +#; Scratch -------------------------------------------------------------------- + diff -r 93d27886c099 -r 62e329839625 stumpwm/config.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/config.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,32 @@ +(in-package :stumpwm-user) + +(set-prefix-key (kbd "C-space")) +(local-time:reread-timezone-repository) + +(set-focus-color "#aaaaaa") +(set-win-bg-color "#111111") +(set-unfocus-color "#444444") +(setf *normal-border-width* 1 + *default-bg-color* #x222222 + *window-border-style* :thin + (xlib:window-background (screen-root (current-screen))) *default-bg-color*) + +(defvar *redirected* (redirect-all-output (data-dir-file "debug" "log"))) + +(setf *mouse-focus-policy* :click + *message-window-gravity* :center + *input-window-gravity* :center + *debug-level* 0 + *resize-increment* 75 + *new-frame-action* :empty + *window-format* "(%n%m%60t)" + *window-name-source* :title + *maximum-completions* 20 + *shell-program* "/home/sjl/src/dotfiles/bin/bash-dammit" + losh:*pbcopy-command* "/home/sjl/src/dotfiles/bin/pbcopy" + losh:*pbpaste-command* "/home/sjl/src/dotfiles/bin/pbpaste") + +(defun stumpwm::input-insert-hyphen-or-space (input key) + ;; Unbreak typing + (declare (ignore key)) + (input-insert-char input #\space)) diff -r 93d27886c099 -r 62e329839625 stumpwm/external-screens.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/external-screens.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,26 @@ +(in-package :stumpwm-user) + +(defcommand screen-laptop () () + (only) + (hostcase + ((:gro :juss) (loop :with laptop = "eDP" + :with extern = (hostcase (:gro "DisplayPort-0") + (:juss "HDMI-A-0")) + :for (output commands) :in `((,laptop ("--auto")) + (,laptop ("--primary")) + (,extern ("--off"))) + :do (progn (uiop:run-program `("xrandr" "--output" ,output ,@commands))))) + (t (message "Not configured on this system.")))) + +(defcommand screen-external () () + (only) + (hostcase + ((:gro :juss) (loop :with laptop = "eDP" + :with extern = (hostcase (:gro "DisplayPort-0") + (:juss "HDMI-A-0")) + :for (output commands) :in `((,extern ("--auto")) + (,extern ("--primary")) + (,laptop ("--off"))) + :do (uiop:run-program `("xrandr" "--output" ,output ,@commands)))) + (t (message "Not configured on this system.")))) + diff -r 93d27886c099 -r 62e329839625 stumpwm/icelandic.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/icelandic.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,50 @@ +(in-package :stumpwm-user) + + +(defun send-keys (keys &key (win (current-window)) (sleep 0)) + (dolist (k keys) + (send-key (kbd k) win) + (sleep sleep))) + +(defmacro defmultikey (name key compose-keys) + ;; Unfortunately we can't reliably autogen the name with something like + ;; (symb 'mk- compose-key) here because things like đ (th) and Đ (TH) would + ;; case fold to the same name. + `(progn + (defcommand ,name () () + (send-keys '("Multi_key" ,@(map 'list #'string compose-keys)))) + (define-key *top-map* + (kbd ,key) ,(string name)))) + +(defmacro defmultikeys (&rest bindings) + `(progn ,@(loop for binding :in bindings :collect `(defmultikey ,@binding)))) + +(defmultikeys + (isk-l-á "M-a" "'a") + (isk-u-Á "M-A" "'A") + (isk-l-é "M-e" "'e") + (isk-u-É "M-E" "'E") + (isk-l-í "M-i" "'i") + (isk-u-Í "M-I" "'I") + (isk-l-ó "M-o" "'o") + (isk-u-Ó "M-O" "'O") + (isk-l-ö "M-m" "\"o") + (isk-u-Ö "M-M" "\"O") + (isk-l-ú "M-u" "'u") + (isk-u-Ú "M-U" "'U") + (isk-l-ý "M-y" "'y") + (isk-u-Ý "M-Y" "'Y") + (isk-l-þ "M-t" "th") + (isk-u-Þ "M-T" "TH") + (isk-l-đ "M-d" "dh") + (isk-u-Đ "M-D" "DH") + (isk-l-æ "M-h" "ae") + (isk-u-Æ "M-H" "AE")) + + +(defcommand thinkpad-ret () () + (send-key (kbd "RET"))) + +(defcommand thinkpad-bs () () + (send-key (kbd "BackSpace"))) + diff -r 93d27886c099 -r 62e329839625 stumpwm/igv.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/igv.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,105 @@ +(defpackage :stumpwm-user/igv + (:use :cl :losh) + (:import-from :stumpwm :defcommand :echo) + (:export + :igv/supplementary-on + :igv/supplementary-off + :igv/group-none + :igv/group-selected + :igv/clear-read-selections + :igv/select-reads + :igv/goto + :igv/goto-read + :igv/zoom-in + :igv/zoom-out + :igv/init)) + +(in-package :stumpwm-user/igv) + + +;;;; Implementation ----------------------------------------------------------- +(defun send-igv-command (string &key want-resp) + (usocket:with-client-socket (socket stream "127.0.0.1" 60151) + ;; Do this here instead of passing :timeout above because that only sets + ;; *read* timeout and we don't want to permahang stump when IGV hangs and + ;; can't read. + (setf (sb-impl::fd-stream-timeout (usocket:socket-stream socket)) 5.0f0) + (unwind-protect (progn (write-line string stream) + (force-output stream) + (when want-resp + (read-line stream))) + (usocket:socket-close socket)))) + +(defun send-igv-batch-file (path) + (send-igv-command (alexandria:read-file-into-string path))) + +(defun alignment-tracks% () + (str:split #\, (send-igv-command "alignmentTrackNames ," :want-resp t))) + +(defun group% (option) + (send-igv-command (format nil "group ~A" (ecase option + ((:selected) "selected") + ((nil) "none"))))) + +(defun select-reads% () + (dolist (track-name (alignment-tracks%)) + (let ((read-names (ppcre:all-matches-as-strings + "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" + (pbpaste)))) + (send-igv-command (format nil "selectByName ~A ~A ," track-name (str:join "," read-names))) + (echo (format nil "Selected ~D read~:P." (length read-names)))))) + +(defun goto% () + (ppcre:register-groups-bind (chr start end) + ("(chr[A-Za-z0-9_]+)[\\s:]+([\\d,]+)(?:[\\s:]+)?([\\d,]+)?" (pbpaste)) + (send-igv-command (format nil "goto ~A:~A~@[-~A~]" chr start end)))) + +(defun clear-read-selections% () + (dolist (track-name (alignment-tracks%)) + (send-igv-command (format nil "clearSelections ~A" track-name)))) + +(defun zoom-in% () + (send-igv-command "zoomin")) + +(defun zoom-out% () + (send-igv-command "zoomout")) + + +;;;; Commands ----------------------------------------------------------------- +(defcommand igv/supplementary-on () () + (send-igv-command "preference SAM.FILTER_SUPPLEMENTARY_ALIGNMENTS FALSE") + (echo "Supplementary alignments now on.")) + +(defcommand igv/supplementary-off () () + (send-igv-command "preference SAM.FILTER_SUPPLEMENTARY_ALIGNMENTS TRUE") + (echo "Supplementary alignments now off.")) + +(defcommand igv/group-none () () + (group% nil)) + +(defcommand igv/group-selected () () + (group% :selected)) + +(defcommand igv/clear-read-selections () () + (clear-read-selections%)) + +(defcommand igv/select-reads () () + (select-reads%) + (group% :selected)) + +(defcommand igv/goto () () + (goto%)) + +(defcommand igv/zoom-in () () + (zoom-in%)) + +(defcommand igv/zoom-out () () + (zoom-out%)) + +(defcommand igv/goto-read () () + (clear-read-selections%) + (goto%) + (select-reads%)) + +(defcommand igv/init () () + (send-igv-batch-file "/home/sjl/bin/igv.batch")) diff -r 93d27886c099 -r 62e329839625 stumpwm/key-mapping.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/key-mapping.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,279 @@ +(in-package :stumpwm-user) + +(defcommand nop () () + nil) + + +;;; Conventions: +;;; +;;; * Hyper-dir: move focus +;;; * Hyper-Shift-dir: move window +;;; * Hyper-Shift-Control-dir: swap window +;;; * Hyper-F*: hardware +;;; * Shift-F*: timers +;;; * Hyper-Super-*: layout +;;; * Hyper-*: miscellaneous +;;; * Super-GAMERMOUSE: duplicate stuff to avoid swapping back + + +(defmacro define-top-keys (&body keyforms) + `(progn ,@(loop :for form :in keyforms + :collect `(define-key *top-map* + (kbd ,(first form)) + ,(second form))))) + + +(define-top-keys ;; miscellaneous + ("H-m" "terminal") + ("H-M" "toggle-zoom-mute") + ("H-SunPageUp" "st-font-up") + ("H-SunPageDown" "st-font-down") + ("H-z" "fullscreen") + ("H-Z" "end-zoom") + ("C-S-F1" "bht") + ("H-F4" "switch-yubikeys") + ("H-\\" "pass-personal") + ("H-|" "generate-password") + ("s-1" "pass-um-1") + ("s-2" "pass-um-2") + ("H-b" "browser") + ("H-O" "spotify") + ("H-o" "files") + ("H-t" "zoom-meeting") + ("H-P" "papers") + ("F26" "prev") + ("S-F26" "next") + ("H-q" "exec lock-screen") + ("H-y" "screenshot") + ("H-Y" "delayed-screenshot") + ("H-r" "rain") + ("H-V" "vlc") + ("H-e" "budget") + ("H-E" "spend") + ("S-XF86AudioMute" "terminal-font-size-show") + ("S-XF86AudioRaiseVolume" "terminal-font-size-down") ; todo unfuck the backwards mapping in qmk + ("S-XF86AudioLowerVolume" "terminal-font-size-up") + ("C-BackSpace" "clear-notifications")) + + +(define-top-keys ;; clipboard + ("H-c" "show-clipboard-history") + ("H-C" "clear-clipboard-history") + ("H-u" "generate-random-uuid") + ("H-B" "bee-movie-script")) + +(define-top-keys ;; movement + ("H-h" "move-focus* left") + ("H-j" "move-focus down") + ("H-k" "move-focus up") + ("H-l" "move-focus* right") + + ("H-H" "move-window left") + ("H-J" "move-window down") + ("H-K" "move-window up") + ("H-L" "move-window right") + + ("H-1" "gselect 1") + ("H-2" "gselect 2") + ("H-3" "gselect 3") + ("H-4" "gselect 4") + ("H-5" "gselect 5") + ("H-6" "gselect 6") + + ("KP_Insert" "vgroups") + ("KP_End" "gselect 1") + ("KP_Down" "gselect 2") + ("KP_Page_Down" "gselect 3") + ("KP_Left" "gselect 4") + ("KP_Begin" "gselect 5") + ("KP_Right" "gselect 6") + ("KP_Home" "gselect 7") + ("KP_Up" "gselect 8") + ("KP_Page_Up" "gselect 9") + + ("H-!" "gmove 1") + ("H-@" "gmove 2") + ("H-#" "gmove 3") + ("H-$" "gmove 4") + ("H-%" "gmove 5") + ("H-^" "gmove 6") + + ("C-H-H" "exchange-direction left") + ("C-H-J" "exchange-direction down") + ("C-H-K" "exchange-direction up") + ("C-H-L" "exchange-direction right") + + ("H-`" "next") + ("S-H-`" "prev") + ("H-n" "next-in-frame") + ("H-p" "prev-in-frame") + ("H-N" "pull-hidden-next") + + ("H-," "pull-from-windowlist") + ("H-less" "title") + + ("H-." "ggo") + ("H-greater" "grename") + ) + +(define-top-keys ;; splitting + ("H-s" "sane-vsplit") + ("H-v" "sane-hsplit") + ("H-=" "balance-frames")) + +(define-top-keys ;; killing + ("H-w" "delete") + ("H-W" "kill") + ("H-BackSpace" "remove") + ("S-H-BackSpace" "kill-and-remove") + ("H-Delete" "gkill")) + +(define-top-keys ;; naming + ("H-'" "title") + ("H-\"" "grename")) + +(define-top-keys ;; sound + ("H-F1" "mute") + ("H-F2" "volume-down") + ("H-F3" "volume-up") + ("XF86AudioMute" "mute") + ("XF86AudioRaiseVolume" "volume-down") ; todo unfuck the backwards mapping in qmk + ("XF86AudioLowerVolume" "volume-up")) + +(define-top-keys ;; screen + ("H-F5" "rotate-brightness-down") + ("H-F6" "rotate-brightness-up") + ("H-F7" "screen-laptop") + ("H-F8" "screen-external")) + +(define-top-keys ;; layout + ("s-H-o" "only") + ("s-H-n" "restore-from-file notes") + ("s-H-t" "restore-from-file thirds") + ("s-H-m" "restore-from-file dev") + ("s-H-s" "restore-from-file streaming") + ("s-H-w" "restore-from-file work") + ("s-H-z" "restore-from-file zoom")) + +(define-top-keys ;; timers + ("s-F7" "tea-timer") + ("s-F9" "run-pop-timer") + ("s-F8" "set-pop-timer") + ("s-p" "posture-start") + ("s-P" "posture-stop") + ("s-y" "posture-answer-yes") + ("s-h" "posture-answer-meh") + ("s-n" "posture-answer-no") + ("s-\\" "posture-toggle-pause") + ("s-o" "posture-snooze")) + +(define-top-keys ;; stump + ("Pause" "terminal") ; jesus christ + ("H-F9" "sleep-machine") + ("H-F10" "toggle-stumptray") + ("H-F11" "toggle-current-mode-line") + ("H-F12" "refresh-heads")) + +(defvar *keymap/igv* (make-sparse-keymap)) + +(define-key *keymap/igv* (kbd "s") "igv/supplementary-on") +(define-key *keymap/igv* (kbd "S") "igv/supplementary-off") +(define-key *keymap/igv* (kbd "g") "igv/group-selected") +(define-key *keymap/igv* (kbd "G") "igv/group-none") +(define-key *keymap/igv* (kbd "r") "igv/select-reads") +(define-key *keymap/igv* (kbd "R") "igv/clear-read-selections") +(define-key *keymap/igv* (kbd "l") "igv/goto") +(define-key *keymap/igv* (kbd "L") "igv/goto-read") +(define-key *keymap/igv* (kbd "i") "igv/init") +(define-key *keymap/igv* (kbd "H-i") "igv") + +(define-top-keys ;; alternate maps + ("H-i" *keymap/igv*)) + + +;;; The G A M E R M O U S E: +;;; +;;; +----------+----------+----------+ _____ +;;; | | ^ | | / \ +--------+ +;;; | igv | | | igv | | | | | +;;; | z out | move | z in | group | | group | | +;;; +----------+----------+----------+ <----- | | -----> | | +;;; | | | | | | | | +;;; | move | | move | | | | | +;;; | <-- | | --> | \_____/ | kill | +;;; +----------+----------+----------+ | | +;;; | | move | | | | +;;; | | | | | +---------+ | | +;;; | | v | | | | | | +;;; +----------+----------+----------+ | next | | | +;;; | split | FULL | split | | | +--------+ +;;; | [-] | SCREEN | [|] | +---------+ +;;; | | | | | | +;;; +----------+----------+----------+ | prev | +;;; | | +;;; +---------+ +(define-top-keys ;; GAMER MOUSE + ;; Super layer + ("s-!" "igv/zoom-out") ("s-@" "move-window up") ("s-#" "igv/zoom-in") + ("s-$" "move-window left") ("s-%" "nop") ("s-^" "move-window right") + ("s-&" "nop") ("s-*" "move-window down") ("s-(" "nop") + ("s-)" "sane-vsplit") ("s-_" "fullscreen") ("s-+" "sane-hsplit") + + ("M-s-Left" "gprev") ("M-s-Right" "gnext") + + ("s-Home" "next-in-frame") + ("s-End" "prev-in-frame") + + ("s-Delete" "remove") + + ;; Hyper-Super layer + ("H-s-!" "nop") ("H-s-@" "resize-direction up") ("H-s-#" "nop") + ("H-s-$" "resize-direction left") ("H-s-%" "fullscreen") ("H-s-^" "resize-direction right") + ("H-s-&" "nop") ("H-s-*" "resize-direction down") ("H-s-(" "nop") + ("H-s-)" "nop") ("H-s-_" "nop") ("H-s-+" "nop") + + ) + +(define-top-keys ;; Single-key keyboard + ("S-C-F1" "igv")) + + +(define-remapped-keys + '(("st-256color" + ("s-c" . "C-C") + ("s-v" . "C-V") + ("C-=" . "S-C-SunPageUp") + ("C--" . "S-C-SunPageDown") + ("C-0" . "S-C-Home")) + ("(firefox|Google-chrome|Chromium-browser)" + ("s-[" . "C-S-Tab") + ("s-]" . "C-Tab") + ("C-M-Left" . "C-S-Tab") + ("C-M-Right" . "C-Tab") + ("C-a" . "Home") + ("C-e" . "End") + ;; I always try to hit ctrl-d to kill a browser window because I'm so used + ;; to terminal windows, and it ends up bookmarking the damn page. In the + ;; interest of not having a random collection of bookmarks grow over time, + ;; I'll just add a mapping to compensate for my stupid brain. + ("C-d" . "C-w") + ;; todo debug why this breaks a really fast C-a-k roll + ;; ("C-a" . "Home") + ;; ("C-e" . "End") + ("s-a" . "C-a") + ("s-d" . "C-d") + ("s-l" . "C-l") + ("s-t" . "C-t") + ("s-w" . "C-w") + ("s-r" . "C-r") + ("s-f" . "C-f") + ("s-z" . "C-z") + ("s-x" . "C-x") + ("s-c" . "C-c") + ("s-v" . "C-v")) + ("" + ("s-z" . "C-z") + ("s-x" . "C-x") + ("s-c" . "C-c") + ("s-v" . "C-v")))) + diff -r 93d27886c099 -r 62e329839625 stumpwm/local-share-stumpwm/522.dump --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/local-share-stumpwm/522.dump Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,52 @@ +#S(GDUMP + :NUMBER 3 + :NAME "code" + :TREE (((#S(FDUMP + :NUMBER 0 + :X 0 + :Y 0 + :WIDTH 1200 + :HEIGHT 1020 + :WINDOWS (31457288) + :CURRENT 31457288) + #S(FDUMP + :NUMBER 3 + :X 0 + :Y 1020 + :WIDTH 1200 + :HEIGHT 420 + :WINDOWS (29360133) + :CURRENT 29360133)) + ((#S(FDUMP + :NUMBER 1 + :X 1200 + :Y 0 + :WIDTH 1735 + :HEIGHT 1440 + :WINDOWS (33554437) + :CURRENT 33554437) + (#S(FDUMP + :NUMBER 4 + :X 2935 + :Y 0 + :WIDTH 985 + :HEIGHT 720 + :WINDOWS (37748741) + :CURRENT 37748741) + #S(FDUMP + :NUMBER 5 + :X 2935 + :Y 720 + :WIDTH 985 + :HEIGHT 720 + :WINDOWS NIL + :CURRENT NIL))) + #S(FDUMP + :NUMBER 2 + :X 3920 + :Y 0 + :WIDTH 1200 + :HEIGHT 1440 + :WINDOWS (16977044) + :CURRENT 16977044)))) + :CURRENT 1) \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 stumpwm/local-share-stumpwm/notes.dump --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/local-share-stumpwm/notes.dump Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,44 @@ +#S(GDUMP + :NUMBER 2 + :NAME "notes" + :TREE (((#S(FDUMP + :NUMBER 0 + :X 0 + :Y 0 + :WIDTH 2560/3 + :HEIGHT 720 + :WINDOWS (25165829) + :CURRENT 25165829) + #S(FDUMP + :NUMBER 4 + :X 0 + :Y 720 + :WIDTH 2560/3 + :HEIGHT 720 + :WINDOWS (35651589) + :CURRENT 35651589)) + (#S(FDUMP + :NUMBER 1 + :X 2560/3 + :Y 0 + :WIDTH 2560/3 + :HEIGHT 1440 + :WINDOWS (27262981) + :CURRENT 27262981) + (#S(FDUMP + :NUMBER 2 + :X 5120/3 + :Y 0 + :WIDTH 2560/3 + :HEIGHT 720 + :WINDOWS (29360133) + :CURRENT 29360133) + #S(FDUMP + :NUMBER 3 + :X 5120/3 + :Y 720 + :WIDTH 2560/3 + :HEIGHT 720 + :WINDOWS (33554437) + :CURRENT 33554437))))) + :CURRENT 1) \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 stumpwm/local-share-stumpwm/uw-test.dump --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/local-share-stumpwm/uw-test.dump Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,7 @@ +#S(GDUMP + :NUMBER 1 + :NAME "Default" + :TREE ((#S(FDUMP :NUMBER 0 :X 0 :Y 0 :WIDTH 640 :HEIGHT 1440 :WINDOWS NIL :CURRENT NIL) + (#S(FDUMP :NUMBER 1 :X 640 :Y 0 :WIDTH 3840 :HEIGHT 1440 :WINDOWS NIL :CURRENT NIL) + #S(FDUMP :NUMBER 2 :X 4480 :Y 0 :WIDTH 640 :HEIGHT 1440 :WINDOWS NIL :CURRENT NIL)))) + :CURRENT 1) diff -r 93d27886c099 -r 62e329839625 stumpwm/miscellaneous.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/miscellaneous.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,112 @@ +(in-package :stumpwm-user) + +(defcommand sane-hsplit () () + (hsplit) + (move-focus :right)) + +(defcommand sane-vsplit () () + (vsplit) + (move-focus :down)) + + +(defcommand move-focus* (direction) + ((:direction "Enter a direction: ")) + (labels ((in-float-p () + (typep (current-group) 'stumpwm::float-group)) + (focus-first-frame () + (unless (in-float-p) + ;; After moving to a new group we don't know which frame is + ;; focused, and unfortunately Stump doesn't give us a nice way to + ;; say "focus the leftmost frame" so we'll just move the focus + ;; a bunch of times and hope it's enough. Sigh. + (loop :repeat 15 + :until (eql (current-frame) + (progn (move-focus (ecase direction + (:left :right) + (:right :left))) + (current-frame)))))) + (next-group () + (ecase direction + (:right (gnext)) + (:left (gprev))) + (focus-first-frame))) + (unless (in-float-p) + (banish)) + (if (in-float-p) + (next-group) + (let ((frame (current-frame))) + (move-focus direction) + (when (eql frame (current-frame)) + (next-group)))))) + +(defcommand toggle-current-mode-line () () + (toggle-mode-line (current-screen) (current-head))) + +(defcommand toggle-stumptray () () + (run-commands "stumptray")) + +(defcommand kill-and-remove () () + (run-commands "kill" "remove")) + +(defcommand sleep-machine () + () + (hostcase + ((:gro :juss) + (run-shell-command "exec lock-screen") + (run-shell-command "systemctl suspend")) + (t (message "Not sleeping this machine for safety.")))) + +(defcommand copy-clhs-url (s) + ((:string "Symbol: ")) + (run-shell-command (format nil "clhs --url 'http://www.lispworks.com/documentation/HyperSpec/' --quiet --open echon '~A' | pbcopy" s))) + +(defcommand describe-window () () + (show-window-properties)) + +(defcached (weather :seconds 120) () + (losh:sh '("/home/sjl/src/dotfiles/lisp/bin/weather" "48105" "-H" "36") :result-type 'list)) + +(defcommand rain () () + (_ (weather) + (mapcar (lambda (line) (ppcre:regex-replace " 1[0-9]:00 " line "^6\\&^*")) _) + (message "~{~A~^~%~}" _))) + +(defcommand mark (thing) ((:string "Mark: ")) + (run-shell-command (format nil "mark ~A" thing))) + +(defcommand clear-notifications () () + (run-shell-command "dunstctl close-all")) + +(defcommand start-vm () () + (echo "Starting VM.") + (run-shell-command "/home/sjl/vms/run")) + + +(defcommand toggle-zoom-mute () () + (when-let-window (win "^Zoom Meeting.*") + ;; Zoom stupidly won't accept the shortcut unless it's in focus + (unless (eql (window-group win) (current-group)) + ;; jesus christ stump just export switch-to-group come on + (gselect (princ-to-string (group-number (window-group win))))) + (focus-window win t) + (meta (kbd "M-a")))) + +(defcommand end-zoom () () + (when-let-window (win "^Zoom Meeting.*") + (kill-window win) + (message "Killed meeting"))) + + +(defcommand ggo () () + (let* ((current-screen (current-screen)) + (current-group (stumpwm::screen-current-group current-screen)) + (all-groups (sort (copy-seq (screen-groups current-screen)) #'< :key #'group-number)) + (groups (mapcar (lambda (group) + (list (format nil "~2D~A~A" + (group-number group) + (if (eql current-group group) #\* #\space) + (group-name group)) + group)) + all-groups)) + (selected (select-from-menu current-screen groups))) + (when selected (stumpwm::switch-to-group (second selected))))) diff -r 93d27886c099 -r 62e329839625 stumpwm/modeline.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/modeline.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,51 @@ +(in-package :stumpwm-user) + +(defun ensure-mode-line () + (when (not (stumpwm::head-mode-line (current-head))) + (toggle-mode-line (current-screen) (current-head)))) + + +(defun configure-modeline () + (setf + *time-modeline-string* + "%a %b %e %H:%M" + + cpu::*cpu-usage-modeline-fmt* + "^[~A~3D%^]" + + cpu::*cpu-modeline-fmt* + "[%c] [%f]" + + mem::*mem-modeline-fmt* + "%p" + + *screen-mode-line-format* + (append + (list "[^B" + '(:eval (princ-to-string (group-number (current-group)))) + ":%n^b@%h] %W^>") + + (list "(V %V) ") + + ;; battery and brightness for laptops + (hostcase + ((:gro :juss) + (list "(B %B)" + " (BR " + '(:eval (princ-to-string (brightness))) + "%) "))) + + ;; temperature + (list "(TEMP %S) ") + + ;; cpu, mem, time, tray + (list "(CPU %C) (MEM%M) %d %T") + )) + + (setf *mode-line-timeout* 10) + (setf *mode-line-background-color* "#111111") + + (ensure-mode-line)) + +(configure-modeline) + diff -r 93d27886c099 -r 62e329839625 stumpwm/modules.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/modules.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,9 @@ +(in-package :stumpwm-user) + +(load-module "pass") +(load-module "battery-portable") +(load-module "cpu") +(load-module "hostname") +(load-module "mem") +(load-module "stumptray") +(load-module "clipboard-history") diff -r 93d27886c099 -r 62e329839625 stumpwm/package.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/package.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +(in-package :stumpwm-user) + +(shadow :window) + +(use-package :losh) diff -r 93d27886c099 -r 62e329839625 stumpwm/passwords.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/passwords.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,23 @@ +(in-package :stumpwm-user) + +(defcommand pass-personal () () + (let ((pass:*password-store* "/home/sjl/.password-store/") + (pass:*pass-notification-message* t)) + (pass:pass-copy))) + +(defcommand pass-um-1 () () + (echo "Copying UM level 1 password, touch key.") + (run-shell-command "pass -c umich.edu/slosh")) + +(defcommand pass-um-2 () () + (echo "Copying UM level 2 password, touch key.") + (run-shell-command "pass -c umich.edu/l2")) + +(defcommand switch-yubikeys () () + (echo (run-shell-command "switch-yubikeys" t))) + +(defcommand generate-password () () + (run-shell-command "genpass | pbc") + (message "Generated a fresh password and copied it to the clipboard.")) + + diff -r 93d27886c099 -r 62e329839625 stumpwm/posture.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/posture.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,84 @@ +(in-package :stumpwm-user) + +(defparameter *posture-thread* nil) +(defparameter *posture-should-stop* nil) +(defparameter *posture-paused* nil) +(defparameter *posture-snooze* nil) +(defparameter *posture-current* 30) +(defparameter *posture-min* 5) +(defparameter *posture-max* (hours->seconds 2)) + +(defun posture-paused-p () + ;; this is the dumbest shit ever, but I can't figure out how to call into + ;; stumpish from the setguid slock process + (or *posture-paused* (probe-file "/tmp/.posture-pause"))) + +(defun posture-snoozed-p () + (and *posture-snooze* + (< (get-universal-time) *posture-snooze*))) + +(defcommand posture-pause () () + (message "Pausing posture.") + (setf *posture-paused* t)) + +(defcommand posture-unpause () () + (message "Unpausing posture.") + (setf *posture-paused* nil)) + +(defcommand posture-toggle-pause () () + (if (setf *posture-paused* (not *posture-paused*)) + (message "Posture is now paused.") + (message "Posture is now unpaused."))) + +(defcommand posture-snooze (hours) + ((:real "Snooze for how many hours? ")) + (setf *posture-snooze* (+ (hours->seconds hours) (get-universal-time)))) + +(defun posture-update (delta) + (setf *posture-current* + (clamp *posture-min* *posture-max* (* *posture-current* delta)))) + +(defun posture-query () + (speak "Is your posture okay?")) + +(defcommand posture-answer-yes () () + (message "Good work.") + (run-shell-command "echo $(epochseconds) 1.0 >> ~/.posture.log") + (posture-update 11/10)) + +(defcommand posture-answer-meh () () + (message "Better than nothing.") + (run-shell-command "echo $(epochseconds) 0.5 >> ~/.posture.log")) + +(defcommand posture-answer-no () () + (message "Try harder.") + (run-shell-command "echo $(epochseconds) 0.0 >> ~/.posture.log") + (posture-update 8/10)) + +(defun posture% () + (if *posture-should-stop* + nil + (progn (unless (or (posture-paused-p) (posture-snoozed-p)) + (posture-query) + (sleep 10)) + *posture-current*))) + +(defun posture-running-p () + (and *posture-thread* (sb-thread:thread-alive-p *posture-thread*))) + +(defcommand posture-stop () () + (setf *posture-should-stop* t)) + +(defcommand posture-start () () + (setf *posture-should-stop* nil) + (if (posture-running-p) + (message "Posture loop was already running.") + (setf *posture-thread* + (sb-thread:make-thread + (lambda () + (loop :for seconds = (posture%) + :while seconds + :do (sleep seconds)) + (message "Posture loop exiting.")) + :name "Posture thread")))) + diff -r 93d27886c099 -r 62e329839625 stumpwm/screenshots.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/screenshots.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,8 @@ +(in-package :stumpwm-user) + +(defcommand delayed-screenshot () () + (run-shell-command "sleep 10 && screenshot")) + +(defcommand screenshot () () + (run-shell-command "screenshot")) + diff -r 93d27886c099 -r 62e329839625 stumpwm/sensors.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/sensors.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,48 @@ +(in-package :stumpwm-user) + +(defun ? (obj &rest keys) + (if (null keys) + obj + (apply #'? (etypecase obj + (hash-table (gethash (first keys) obj))) + (rest keys)))) + +(defun parse-sensors () + ;; sensors -j is stupid and will output errors before the actual output on + ;; standard out, instead of putting them on standard err like a reasonable + ;; program, e.g.: + ;; + ;; ERROR: Can't get value of subfeature temp1_input: Can't read + ;; { + ;; "iwlwifi_1-virtual-0":{ … }, + ;; … + ;; + ;; So we'll have to drop the `ERROR` lines before we can get to the actual + ;; goddamn JSON. UNIX programs are so great. + (let ((s (losh:sh '("sensors" "-j") :result-type 'stream))) + (loop :while (char= #\E (peek-char nil s)) :do (read-line s)) + (jarl:read t s))) + +(defun sensors% (&aux (sensors (parse-sensors))) + (hostcase + (:ouroboros (format nil "[CPU ~D°C] [GPU ~D°C ~D°C ~D°C]" + (round (? sensors "nct6779-isa-0290" "CPUTIN" "temp2_input")) + (round (? sensors "amdgpu-pci-4500" "edge" "temp1_input")) + (round (? sensors "amdgpu-pci-4500" "junction" "temp2_input")) + (round (? sensors "amdgpu-pci-4500" "mem" "temp3_input")))) + ((:gro :juss) (format nil "[CPU ~D°C] [GPU ~D°C]" + (round (? sensors "thinkpad-isa-0000" "CPU" "temp1_input")) + (round (? sensors "amdgpu-pci-0400" "edge" "temp1_input")))) + (t "?"))) + +(defcached (sensors :seconds 10.0) + (sensors%)) + +(defun sensors-modeline (ml) + (declare (ignore ml)) + (sensors)) + +(add-screen-mode-line-formatter #\S #'sensors-modeline) + +#; Scratch -------------------------------------------------------------------- + diff -r 93d27886c099 -r 62e329839625 stumpwm/sound.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/sound.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,40 @@ +(in-package :stumpwm-user) + +(defun volume% () + (_ (run-shell-command "amixer sget Master" t) + (string-grep "Front Left:" _ :first-only t) + (string-split "[]" _) + second + (string-trim "%" _) + parse-integer)) + +(defcached (volume :seconds 30) + (volume%)) + +(defcommand mute () () + (run-shell-command "mute") + (volume/uncache) + (message "Muted.")) + +(defcommand volume-up () () + (run-shell-command "amixer -q sset Master 5%+") + (volume/uncache) + (message "Volume: ~D%" (volume))) + +(defcommand volume-down () () + (run-shell-command "amixer -q sset Master 5%-") + (volume/uncache) + (message "Volume: ~D%" (volume))) + +(defun volume-modeline (ml) + (declare (ignore ml)) + (format nil "~D%" (volume))) + +(defcommand bht () () + (run-shell-command (format nil "amixer -q sset Master 50%; bht; amixer -q sset Master ~D%" (volume))) + (volume/uncache)) + +(add-screen-mode-line-formatter #\V #'volume-modeline) + +#; Scratch -------------------------------------------------------------------- +(volume) diff -r 93d27886c099 -r 62e329839625 stumpwm/stumpconfig.asd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/stumpconfig.asd Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,40 @@ +(asdf:defsystem :stumpconfig + :description "My StumpWM configuration." + :author "Steve Losh " + + :depends-on (:losh + :split-sequence + :alexandria + :parse-number + :str + :cl-ppcre + :bordeaux-threads + :jarl + :local-time + :usocket + :uuid) + + :serial t + :components ((:file "package") + (:file "modules") + (:file "config") + (:file "utils") + (:file "posture") + (:file "budget") + (:file "screenshots") + (:file "sound") + (:file "brightness") + (:file "passwords") + (:file "terminal-fonts") + (:file "clipboard") + (:file "applications") + (:file "timers") + (:file "icelandic") + (:file "sensors") + (:file "modeline") + (:file "vlime") + (:file "external-screens") + (:file "miscellaneous") + (:file "igv") + (:file "bioinf") + (:file "key-mapping"))) diff -r 93d27886c099 -r 62e329839625 stumpwm/stumpwmrc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/stumpwmrc Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,20 @@ +(in-package :stumpwm-user) + +(ql:quickload :stumpconfig) + +(defvar *tray-loaded* + (run-commands "stumptray")) + +(defvar *dunst* + (run-shell-command "/usr/bin/dunst -conf ~/.dunstrc")) + +(defvar *clip* + (clipboard-history:start-clipboard-manager)) + +(when (probe-file "/home/sjl/.stumpwmrc.local") + (load "/home/sjl/.stumpwmrc.local")) + + +#; Scratch -------------------------------------------------------------------- + +(princ *window-format*) diff -r 93d27886c099 -r 62e329839625 stumpwm/terminal-fonts.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/terminal-fonts.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,36 @@ +(in-package :stumpwm-user) + +(defun read-terminal-font-size-from-config () + (if (probe-file "/home/sjl/.terminal-font") + (with-open-file (f "/home/sjl/.terminal-font") + (read f)) + 11)) + +(defvar *terminal-font-size* (read-terminal-font-size-from-config)) + +(defcommand reload-terminal-font-size () () + (setf *terminal-font-size* (read-terminal-font-size-from-config))) + +(defcommand terminal-font-size-show () () + (message "~D" *terminal-font-size*)) + +(defcommand terminal-font-size-up () () + (message "~D" (incf *terminal-font-size*))) + +(defcommand terminal-font-size-down () () + (message "~D" (setf *terminal-font-size* (max 6 (1- *terminal-font-size*))))) + +(defcommand st-font-up () () + (loop :repeat 7 :do (meta (kbd "C-S-SunPageUp")))) + +(defcommand st-font-down () () + (loop :repeat 7 :do (meta (kbd "C-S-SunPageDown")))) + +(defcommand st-font-reset () () + (meta (kbd "C-S-Home"))) + +(defcommand tfont (size) + ((:integer "Size: ")) + (setf *terminal-font-size* size)) + + diff -r 93d27886c099 -r 62e329839625 stumpwm/timers.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/timers.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,38 @@ +(in-package :stumpwm-user) + +(defparameter *pop-timer-minutes* nil) +(defparameter *pop-timer-seconds* nil) + +(defun pop-timer () + (if (or (null *pop-timer-minutes*) + (null *pop-timer-seconds*)) + (message "Pop timer is not configured.") + (progn + (message "Setting pop timer for ~D:~2,'0D." + *pop-timer-minutes* *pop-timer-seconds*) + (let* ((warning-time 30) + (total-time (+ (* *pop-timer-minutes* 60) *pop-timer-seconds*)) + (initial-time (- total-time warning-time))) + (sb-thread:make-thread + (lambda () + (if (plusp initial-time) + (progn (sleep initial-time) + (speak "Pop soon.") + (sleep warning-time)) + (sleep total-time)) + (speak "Pop!")) + :name "Pop Timer"))))) + +(defcommand run-pop-timer () () + (pop-timer)) + +(defcommand set-pop-timer (minutes seconds) + ((:integer "Minutes: ") + (:integer "Seconds: ")) + (setf *pop-timer-minutes* minutes + *pop-timer-seconds* seconds)) + +(defcommand tea-timer (seconds) + ((:integer "Seconds: ")) + (run-shell-command (format nil "tea ~D" seconds))) + diff -r 93d27886c099 -r 62e329839625 stumpwm/utils.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/utils.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,156 @@ +(in-package :stumpwm-user) + +(defun send-key% (key &optional (win (current-window))) + "Send key press and key release events for KEY to window WIN." + ;; from https://github.com/alezost/stumpwm-config/blob/master/utils.lisp + (let ((xwin (window-xwin win))) + (multiple-value-bind (code state) (stumpwm::key-to-keycode+state key) + (flet ((send (event) + (xlib:send-event xwin event (xlib:make-event-mask event) + :display *display* + :root (screen-root (window-screen win)) + :x 0 :y 0 :root-x 0 :root-y 0 + :window xwin :event-window xwin + :code code + :state state))) + (send :key-press) + (send :key-release) + (xlib:display-finish-output *display*))))) + +(defcommand send-key (key &optional (win (current-window))) (:key) + "Send key press and key release events for KEY to window WIN." + (send-key% key win)) + + +(defun string-contains (needle string) + (and (search needle string :test #'char=) t)) + +(defun string-grep (needle text &key first-only) + (_ text + (split-sequence:split-sequence #\newline _) + (if first-only + (find needle _ :test #'string-contains) + (remove-if-not (alexandria:curry #'string-contains needle) _)))) + +(defun string-split (delimiters string) + (split-sequence:split-sequence delimiters string + :test (lambda (bag ch) + (find ch bag :test #'char=)))) + +(defun run-and-echo-shell-command (command &rest args) + (message command) + (apply #'run-shell-command command args)) + + +(defun mod+ (n increment modulo) + (mod (+ n increment) modulo)) + + +(defmacro defcached ((name &key seconds) &body body) + (let ((seconds (coerce seconds 'double-float))) + (with-gensyms (ttl next value) + `(let ((,ttl ,seconds) + (,next nil) + (,value nil)) + (defun ,name () + (when (or (null ,next) + (>= (get-internal-real-time) ,next)) + (setf ,next (+ (get-internal-real-time) + (* internal-time-units-per-second ,ttl)) + ,value (progn ,@body))) + ,value) + (defun ,(symb name '/uncache) () + (setf ,next nil ,value nil)))))) + + +(defun current-frame () + (stumpwm::tile-group-current-frame (current-group))) + + +(defun keywordize (string) + (_ string + (string-trim (string #\newline) _) + string-upcase + (intern _ (find-package :keyword)))) + +(defparameter *host* (keywordize (machine-instance))) + + +(defmacro ehostcase (&body clauses) + `(ecase *host* ,@clauses)) + +(defmacro hostcase (&body clauses) + `(case *host* ,@clauses)) + + +(defcommand speak (text) + ((:string "Text: ")) + (message text) + (run-shell-command (format nil "~~/src/dotfiles/bin/say '~A'" text))) + + +(defun seconds->hours (seconds) + (/ seconds 60 60)) + +(defun hours->seconds (hours) + (* hours 60 60)) + + +(define-stumpwm-type :integer (input prompt) + ;; Annoyingly, StumpWM's built-in :number type isn't actually number, but is + ;; actually just integers. Define a better-named type here. + (when-let ((n (or (argument-pop input) + (read-one-line (current-screen) prompt)))) + (handler-case + (parse-integer n) + (parse-error (c) + (declare (ignore c)) + (throw 'error "Integer required."))))) + +(define-stumpwm-type :real (input prompt) + (when-let ((n (or (argument-pop input) + (read-one-line (current-screen) prompt)))) + (handler-case + (let ((result (parse-number:parse-number n))) + (assert (typep result 'real)) + result) + (error (c) + (declare (ignore c)) + (throw 'error "Real required."))))) + + +(defun window-match-p (query window) + "Return whether `window` matches `query`. + + `query` must be of the form `(query-type query-value)`. + + `query-type` must be one of `:title` or `:class`. + + `query-value` must either be a string (which must be matched exactly) or + a PPCRE scanner. + + " + (destructuring-bind (query-type query) query + (let ((value (ecase query-type + (:title (window-title window)) + (:class (window-class window))))) + (etypecase query + (string (string= query value)) + (function (ppcre:scan query value)))))) + +(defun all-windows () + "Return a fresh list of all windows on all screens. Yes, all of them." + (mapcan #'screen-windows *screen-list*)) + +(defun find-window (query) + "Find and return the first window that matches `query` under `window-match-p`." + (find-if (lambda (w) (window-match-p query w)) (all-windows))) + +(defun find-windows (query) + "Find and return a fresh list of all windows that match `query` under `window-match-p`." + (remove-if-not (lambda (w) (window-match-p query w)) (all-windows))) + +(defmacro when-let-window ((symbol title-query) &body body) + `(when-let ((,symbol (find-window `(:title ,(ppcre:create-scanner ,title-query))))) + ,@body)) + diff -r 93d27886c099 -r 62e329839625 stumpwm/vlime.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stumpwm/vlime.lisp Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,15 @@ +(in-package :stumpwm-user) + +(defcommand vlime () () + (load "~/src/dotfiles/vim/bundle/vlime/lisp/start-vlime.lisp") + (message "Started VLIME")) + +(defcommand vlime-port (port) ((:integer "Port: ")) + "Start VLIME on the given port. + + Good for bootstrapping a VLIME connection when you accidentally started a + VLIME instance on another port that you don't want to mess with. + + " + (funcall (read-from-string "vlime-loader::run") port) + (message "Started VLIME")) diff -r 93d27886c099 -r 62e329839625 stumpwmrc --- a/stumpwmrc Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,951 +0,0 @@ -(in-package :stumpwm-user) -(shadow :window) - -(ql:quickload '(:losh :split-sequence :alexandria :parse-number :str :cl-ppcre :bordeaux-threads :jarl :local-time) - :silent t) - -(use-package :losh) - -;;;; Config ------------------------------------------------------------------- -(set-prefix-key (kbd "C-space")) -(local-time:reread-timezone-repository) - -(defvar *redirected* (redirect-all-output (data-dir-file "debug" "log"))) - -(setf *mouse-focus-policy* :click - *message-window-gravity* :center - *input-window-gravity* :center - *debug-level* 0 - *resize-increment* 75 - *new-frame-action* :empty - *window-format* "(%n%m%20t)" - *window-name-source* :title - *maximum-completions* 20 - *shell-program* "/home/sjl/src/dotfiles/bin/bash-dammit" - losh:*pbcopy-command* "/home/sjl/src/dotfiles/bin/pbcopy" - losh:*pbpaste-command* "/home/sjl/src/dotfiles/bin/pbpaste") - - -;;;; Utils -------------------------------------------------------------------- -(defun string-contains (needle string) - (and (search needle string :test #'char=) t)) - -(defun string-grep (needle text &key first-only) - (_ text - (split-sequence:split-sequence #\newline _) - (if first-only - (find needle _ :test #'string-contains) - (remove-if-not (alexandria:curry #'string-contains needle) _)))) - -(defun string-split (delimiters string) - (split-sequence:split-sequence delimiters string - :test (lambda (bag ch) - (find ch bag :test #'char=)))) - -(defun run-and-echo-shell-command (command &rest args) - (message command) - (apply #'run-shell-command command args)) - - -(defun mod+ (n increment modulo) - (mod (+ n increment) modulo)) - - -(defun volume () - (_ (run-shell-command "amixer sget Master" t) - (string-grep "Front Left:" _ :first-only t) - (string-split "[]" _) - second - (string-trim "%" _) - parse-integer)) - - -(defun current-frame () - (stumpwm::tile-group-current-frame (current-group))) - - -(defun keywordize (string) - (_ string - (string-trim (string #\newline) _) - string-upcase - (intern _ (find-package :keyword)))) - -(defparameter *host* (keywordize (machine-instance))) - - -(defmacro ehostcase (&body clauses) - `(ecase *host* ,@clauses)) - -(defmacro hostcase (&body clauses) - `(case *host* ,@clauses)) - - -(defcommand speak (text) - ((:string "Text: ")) - (message text) - (run-shell-command (format nil "~~/src/dotfiles/bin/say '~A'" text))) - - -(defun seconds->hours (seconds) - (/ seconds 60 60)) - -(defun hours->seconds (hours) - (* hours 60 60)) - - -(define-stumpwm-type :integer (input prompt) - ;; Annoyingly, StumpWM's built-in :number type isn't actually number, but is - ;; actually just integers. Define a better-named type here. - (when-let ((n (or (argument-pop input) - (read-one-line (current-screen) prompt)))) - (handler-case - (parse-integer n) - (parse-error (c) - (declare (ignore c)) - (throw 'error "Integer required."))))) - -(define-stumpwm-type :real (input prompt) - (when-let ((n (or (argument-pop input) - (read-one-line (current-screen) prompt)))) - (handler-case - (let ((result (parse-number:parse-number n))) - (assert (typep result 'real)) - result) - (error (c) - (declare (ignore c)) - (throw 'error "Real required."))))) - - -(defun window-match-p (query window) - "Return whether `window` matches `query`. - - `query` must be of the form `(query-type query-value)`. - - `query-type` must be one of `:title` or `:class`. - - `query-value` must either be a string (which must be matched exactly) or - a PPCRE scanner. - - " - (destructuring-bind (query-type query) query - (let ((value (ecase query-type - (:title (window-title window)) - (:class (window-class window))))) - (etypecase query - (string (string= query value)) - (function (ppcre:scan query value)))))) - -(defun all-windows () - "Return a fresh list of all windows on all screens. Yes, all of them." - (mapcan #'screen-windows *screen-list*)) - -(defun find-window (query) - "Find and return the first window that matches `query` under `window-match-p`." - (find-if (lambda (w) (window-match-p query w)) (all-windows))) - -(defun find-windows (query) - "Find and return a fresh list of all windows that match `query` under `window-match-p`." - (remove-if-not (lambda (w) (window-match-p query w)) (all-windows))) - -(defmacro when-let-window ((symbol title-query) &body body) - `(when-let ((,symbol (find-window `(:title ,(ppcre:create-scanner ,title-query))))) - ,@body)) - - -;;;; Posture ------------------------------------------------------------------ -(defparameter *posture-thread* nil) -(defparameter *posture-should-stop* nil) -(defparameter *posture-paused* nil) -(defparameter *posture-snooze* nil) -(defparameter *posture-current* 30) -(defparameter *posture-min* 5) -(defparameter *posture-max* (hours->seconds 2)) - -(defun posture-paused-p () - ;; this is the dumbest shit ever, but I can't figure out how to call into - ;; stumpish from the setguid slock process - (or *posture-paused* (probe-file "/tmp/.posture-pause"))) - -(defun posture-snoozed-p () - (and *posture-snooze* - (< (get-universal-time) *posture-snooze*))) - -(defcommand posture-pause () () - (message "Pausing posture.") - (setf *posture-paused* t)) - -(defcommand posture-unpause () () - (message "Unpausing posture.") - (setf *posture-paused* nil)) - -(defcommand posture-toggle-pause () () - (if (setf *posture-paused* (not *posture-paused*)) - (message "Posture is now paused.") - (message "Posture is now unpaused."))) - -(defcommand posture-snooze (hours) - ((:real "Snooze for how many hours? ")) - (setf *posture-snooze* (+ (hours->seconds hours) (get-universal-time)))) - -(defun posture-update (delta) - (setf *posture-current* - (clamp *posture-min* *posture-max* (* *posture-current* delta)))) - -(defun posture-query () - (speak "Is your posture okay?")) - -(defcommand posture-answer-yes () () - (message "Good work.") - (run-shell-command "echo $(epochseconds) 1.0 >> ~/.posture.log") - (posture-update 11/10)) - -(defcommand posture-answer-meh () () - (message "Better than nothing.") - (run-shell-command "echo $(epochseconds) 0.5 >> ~/.posture.log")) - -(defcommand posture-answer-no () () - (message "Try harder.") - (run-shell-command "echo $(epochseconds) 0.0 >> ~/.posture.log") - (posture-update 8/10)) - -(defun posture% () - (if *posture-should-stop* - nil - (progn (unless (or (posture-paused-p) (posture-snoozed-p)) - (posture-query) - (sleep 10)) - *posture-current*))) - -(defun posture-running-p () - (and *posture-thread* (sb-thread:thread-alive-p *posture-thread*))) - -(defcommand posture-stop () () - (setf *posture-should-stop* t)) - -(defcommand posture-start () () - (setf *posture-should-stop* nil) - (if (posture-running-p) - (message "Posture loop was already running.") - (setf *posture-thread* - (sb-thread:make-thread - (lambda () - (loop :for seconds = (posture%) - :while seconds - :do (sleep seconds)) - (message "Posture loop exiting.")) - :name "Posture thread")))) - - -;;;; Budget ------------------------------------------------------------------ -(defparameter *tz/eastern* - (local-time:find-timezone-by-location-name "US/Eastern")) - -(defparameter *budget/start* - (local-time:encode-timestamp 0 0 0 0 29 8 2023 :timezone *tz/eastern*)) - -(defun budget/per-day () - (first (losh:read-all-from-file "/home/sjl/Sync/budget/per-day"))) - -(defun budget/elapsed () - (local-time:timestamp-difference (local-time:now) *budget/start*)) - -(defun budget/days-elapsed () - (floor (/ (budget/elapsed) (* 60 60 24)))) - -(defun budget/in () - (* (budget/days-elapsed) (budget/per-day))) - -(defun budget/out () - (loop :for path :in (directory "/home/sjl/Sync/budget/hosts/*/total") - :summing (print (first (read-all-from-file (print path)))))) - -(defun budget/current () - (- (budget/in) (budget/out))) - -(defcommand budget-dump () () - (message - (sh '("sh" "-c" "tail -n 5 /home/sjl/Sync/budget/hosts/*/records") - :result-type 'string))) - -(defcommand budget () () - (message "$~D" (budget/current))) - -(defmacro with-budget-file ((f file &rest open-args) &body body) - `(with-open-file - (,f (format nil "/home/sjl/Sync/budget/hosts/~(~A~)/~A" *host* ,file) - ,@open-args) - ,@body)) - -(defcommand spend (amount what) ((:integer "Amount: $") (:string "For: ")) - (let ((current (with-budget-file (total "total") - (first (read-all-from-file total)))) - (timestamp (local-time:to-rfc3339-timestring (local-time:now)))) - (with-budget-file (total "total" :direction :output :if-exists :supersede) - (print (+ current amount) total)) - (with-budget-file (records "records" :direction :output :if-exists :append :if-does-not-exist :create) - (print (list timestamp amount what) records)) - (message "Spent $~D for ~A at ~A" amount what timestamp))) - - -;;;; Load --------------------------------------------------------------------- -(load-module "pass") - -;;;; Screenshotting ----------------------------------------------------------- -(defcommand screenshot () () - (run-shell-command "screenshot")) - -(defcommand save-fucked-screenshot () () - (run-shell-command "broken-screenshot")) - -(defcommand delete-fucked-screenshot () () - (run-shell-command "delete-broken-screenshot")) - - -;;;; Brightness --------------------------------------------------------------- -(defparameter *brightness-values* #(0 1 5 10 20 30 40 55 70 85 100)) -(defvar *brightness-index* 5) - -(defun brightness () - (aref *brightness-values* *brightness-index*)) - -(defun set-brightness (value) - (run-and-echo-shell-command - (hostcase - ((:gro) (format nil "xrandr --output ~A --brightness ~D" - (hostcase (:gro "eDP")) - (/ value 100.0))) - (t (message "Not sure how to set brightness on this machine."))))) - -(defun rotate-brightness (delta) - (setf *brightness-index* - (mod+ *brightness-index* delta (length *brightness-values*))) - (set-brightness (brightness))) - - -(defcommand rotate-brightness-up () () - (rotate-brightness 1)) - -(defcommand rotate-brightness-down () () - (rotate-brightness -1)) - - -;;;; Miscellaneous ------------------------------------------------------------ -(defcommand sane-hsplit () () - (hsplit) - (move-focus :right)) - -(defcommand sane-vsplit () () - (vsplit) - (move-focus :down)) - - -(defcommand move-focus* (direction) - ((:direction "Enter a direction: ")) - (labels ((in-float-p () - (typep (current-group) 'stumpwm::float-group)) - (focus-first-frame () - (unless (in-float-p) - ;; After moving to a new group we don't know which frame is - ;; focused, and unfortunately Stump doesn't give us a nice way to - ;; say "focus the leftmost frame" so we'll just move the focus - ;; a bunch of times and hope it's enough. Sigh. - (loop :repeat 15 - :until (eql (current-frame) - (progn (move-focus (ecase direction - (:left :right) - (:right :left))) - (current-frame)))))) - (next-group () - (ecase direction - (:right (gnext)) - (:left (gprev))) - (focus-first-frame))) - (unless (in-float-p) - (banish)) - (if (in-float-p) - (next-group) - (let ((frame (current-frame))) - (move-focus direction) - (when (eql frame (current-frame)) - (next-group)))))) - -(defcommand screen-laptop () () - (only) - (loop :with laptop = "eDP-1" - :with extern = "DP-1" - :for (output commands) :in `((,laptop ("--auto")) - (,laptop ("--primary")) - (,extern ("--off"))) - :do (progn (uiop:run-program `("xrandr" "--output" ,output ,@commands))))) - -(defcommand screen-external () () - (only) - (loop :with laptop = "eDP-1" - :with extern = "DP-1" - :for (output commands) :in `( - ;; (,laptop ("--off")) - (,extern ("--auto")) - (,extern ("--primary")) - (,laptop ("--auto")) - (,laptop ("--left-of" ,extern)) - ) - :do (uiop:run-program `("xrandr" "--output" ,output ,@commands)))) - -(defcommand vlime () () - (load "~/src/dotfiles/vim/bundle/vlime/lisp/start-vlime.lisp") - (message "Started VLIME")) - -(defcommand vlime-port (port) ((:integer "Port: ")) - "Start VLIME on the given port. - - Good for bootstrapping a VLIME connection when you accidentally started a - VLIME instance on another port that you don't want to mess with. - - " - (funcall (read-from-string "vlime-loader::run") port) - (message "Started VLIME")) - -(defcommand toggle-current-mode-line () () - (toggle-mode-line (current-screen) (current-head))) - -(defcommand toggle-stumptray () () - (run-commands "stumptray")) - -(defcommand pass-personal () () - (let ((pass:*password-store* "/home/sjl/.password-store/") - (pass:*pass-notification-message* t)) - (pass:pass-copy))) - -(defcommand generate-password () () - (run-shell-command "genpass | pbc") - (message "Generated a fresh password and copied it to the clipboard.")) - -(defcommand kill-and-remove () () - (run-commands "kill" "remove")) - -(defcommand sleep-machine () - () - (hostcase - ((:gro) - (run-shell-command "exec lock-screen") - (run-shell-command "systemctl suspend")) - (t (message "Not sleeping this machine for safety.")))) - -(defcommand copy-clhs-url (s) - ((:string "Symbol: ")) - (run-shell-command (format nil "clhs --url 'http://www.lispworks.com/documentation/HyperSpec/' --quiet --open echon '~A' | pbcopy" s))) - -(defcommand describe-window () () - (show-window-properties)) - -(defcommand rain () () - (_ '("/home/sjl/src/dotfiles/lisp/bin/weather" "-H" "36") - (losh:sh _ :result-type 'list) - (mapcar (lambda (line) (ppcre:regex-replace " 1[0-9]:00 " line "^6\\&^*")) _) - (message "~{~A~^~%~}" _))) - -(defcommand mark (thing) ((:string "Mark: ")) - (run-shell-command (format nil "mark ~A" thing))) - -(defcommand toggle-zoom-mute () () - (when-let-window (win "^Zoom Meeting.*") - ;; Zoom stupidly won't accept the shortcut unless it's in focus - (unless (eql (window-group win) (current-group)) - ;; jesus christ stump just export switch-to-group come on - (gselect (princ-to-string (group-number (window-group win))))) - (focus-window win t) - (meta (kbd "M-a")))) - -(defcommand end-zoom () () - (when-let-window (win "^Zoom Meeting.*") - (kill-window win)) - (sleep 2) - (when-let-window (win "^Zoom -.*") - (kill-window win))) - -(defcommand clear-notifications () () - (run-shell-command "dunstctl close-all")) - - - -;;;; Terminal Fonts ----------------------------------------------------------- -(defcommand reload-terminal-font-size () - () - (setf *terminal-font-size* - (if (probe-file "/home/sjl/.terminal-font") - (with-open-file (f "/home/sjl/.terminal-font") - (read f)) - 11))) - -(defparameter *terminal-font-size* (if (probe-file "/home/sjl/.terminal-font") - (with-open-file (f "/home/sjl/.terminal-font") - (read f)) - 11)) - -(defcommand st-font-up () - () - (loop :repeat 7 :do (meta (kbd "C-S-SunPageUp")))) - -(defcommand st-font-down () - () - (loop :repeat 7 :do (meta (kbd "C-S-SunPageDown")))) - -(defcommand st-font-reset () - () - (meta (kbd "C-S-Home"))) - - -;;;; Clipboard/Data Generation ------------------------------------------------ -(load-module "clipboard-history") -(clipboard-history:start-clipboard-manager) - -(defcommand generate-random-uuid () () - (run-shell-command "uuidgen | tr -d '\\n' | ~/src/dotfiles/bin/pbcopy") - (message "Copied random UUID to clipboard.")) - -(defcommand bee-movie-script () () - (run-shell-command "pbeecopy") - (message "Copied the entire Bee Movie script to clipboard.")) - -(defcommand urlize-jira-issue () () - (let ((issue (str:trim (pbpaste)))) - (if (ppcre:scan "^[A-Z0-9]+-\\d+$" issue) - (let* ((endpoint (str:trim (run-shell-command "grep endpoint .jira.d/config.yml | sed -e 's/.*: //'" t))) - (url (format nil "~A/browse/~A" endpoint issue))) - (pbcopy url) - (message "Copied ~A to the clipboard." url)) - (message "Clipboard does not look like a JIRA issue.")))) - - -;;;; Applications ------------------------------------------------------------- -(defcommand spotify () () - (run-or-raise "spotify" '(:class "Spotify"))) - -(defcommand files () () - (run-shell-command "open $HOME")) - -(defcommand browser () () - (run-or-raise "firefox" '(:class "firefox"))) - -(defcommand vlc () () - (run-or-raise "vlc" '(:class "vlc"))) - -(defcommand terminal () () - (run-shell-command (format nil "st -f 'Ubuntu Mono:size=~D'" *terminal-font-size*))) - -(defcommand gcontrol () () - (run-or-raise "gcontrol" '(:class "Gnome-control-center"))) - -(defcommand zoom () () - (when-let-window (w "^Zoom Meeting.*") - (focus-window w t))) - - -;;;; Timers ------------------------------------------------------------------- -(defparameter *pop-timer-minutes* nil) -(defparameter *pop-timer-seconds* nil) - -(defun pop-timer () - (if (or (null *pop-timer-minutes*) - (null *pop-timer-seconds*)) - (message "Pop timer is not configured.") - (progn - (message "Setting pop timer for ~D:~2,'0D." - *pop-timer-minutes* *pop-timer-seconds*) - (let* ((warning-time 30) - (total-time (+ (* *pop-timer-minutes* 60) *pop-timer-seconds*)) - (initial-time (- total-time warning-time))) - (sb-thread:make-thread - (lambda () - (if (plusp initial-time) - (progn (sleep initial-time) - (speak "Pop soon.") - (sleep warning-time)) - (sleep total-time)) - (speak "Pop!")) - :name "Pop Timer"))))) - -(defcommand run-pop-timer () () - (pop-timer)) - -(defcommand set-pop-timer (minutes seconds) - ((:integer "Minutes: ") - (:integer "Seconds: ")) - (setf *pop-timer-minutes* minutes - *pop-timer-seconds* seconds)) - -(defcommand tea-timer (seconds) - ((:integer "Seconds: ")) - (run-shell-command (format nil "tea ~D" seconds))) - - -;;;; Isk ---------------------------------------------------------------------- -(defcommand send-key (key &optional (win (current-window))) (:key) - "Send key press and key release events for KEY to window WIN." - ;; from https://github.com/alezost/stumpwm-config/blob/master/utils.lisp - (let ((xwin (window-xwin win))) - (multiple-value-bind (code state) (stumpwm::key-to-keycode+state key) - (flet ((send (event) - (xlib:send-event xwin event (xlib:make-event-mask event) - :display *display* - :root (screen-root (window-screen win)) - :x 0 :y 0 :root-x 0 :root-y 0 - :window xwin :event-window xwin - :code code - :state state))) - (send :key-press) - (send :key-release) - (xlib:display-finish-output *display*))))) - -(defun send-keys (keys &key (win (current-window)) (sleep 0)) - (dolist (k keys) - (send-key (kbd k) win) - (sleep sleep))) - -(defmacro defmultikey (name key compose-keys) - ;; Unfortunately we can't reliably autogen the name with something like - ;; (symb 'mk- compose-key) here because things like đ (th) and Đ (TH) would - ;; case fold to the same name. - `(progn - (defcommand ,name () () - (send-keys '("Multi_key" ,@(map 'list #'string compose-keys)))) - (define-key *top-map* - (kbd ,key) ,(string name)))) - -(defmacro defmultikeys (&rest bindings) - `(progn ,@(loop for binding :in bindings :collect `(defmultikey ,@binding)))) - -(defmultikeys - (isk-l-á "M-a" "'a") - (isk-u-Á "M-A" "'A") - (isk-l-é "M-e" "'e") - (isk-u-É "M-E" "'E") - (isk-l-í "M-i" "'i") - (isk-u-Í "M-I" "'I") - (isk-l-ó "M-o" "'o") - (isk-u-Ó "M-O" "'O") - (isk-l-ö "M-m" "\"o") - (isk-u-Ö "M-M" "\"O") - (isk-l-ú "M-u" "'u") - (isk-u-Ú "M-U" "'U") - (isk-l-ý "M-y" "'y") - (isk-u-Ý "M-Y" "'Y") - (isk-l-þ "M-t" "th") - (isk-u-Þ "M-T" "TH") - (isk-l-đ "M-d" "dh") - (isk-u-Đ "M-D" "DH") - (isk-l-æ "M-h" "ae") - (isk-u-Æ "M-H" "AE")) - - -;;;; Key Mapping -------------------------------------------------------------- -;;; Conventions: -;;; -;;; * Hyper-dir: move focus -;;; * Hyper-Shift-dir: move window -;;; * Hyper-Shift-Control-dir: swap window -;;; * Hyper-F*: hardware -;;; * Shift-F*: timers -;;; * Hyper-Super-*: layout -;;; * Hyper-*: miscellaneous - -(defmacro define-top-keys (&body keyforms) - `(progn ,@(loop :for form :in keyforms - :collect `(define-key *top-map* - (kbd ,(first form)) - ,(second form))))) - - -(define-top-keys ;; miscellaneous - ("H-m" "terminal") - ("H-M" "mark") - ("H-SunPageUp" "st-font-up") - ("H-SunPageDown" "st-font-down") - ("H-Home" "st-font-reset") - ("H-\\" "pass-personal") - ("H-|" "generate-password") - ("H-b" "browser") - ("H-O" "spotify") - ("H-o" "files") - ("H-z" "zoom") - ("H-Z" "toggle-zoom-mute") - ("C-H-Z" "end-zoom") - ("F26" "prev") - ("S-F26" "next") - ("H-q" "exec lock-screen") - ("H-y" "screenshot") - ("H-g" "gcontrol") - ("H-f" "save-fucked-screenshot") - ("H-F" "delete-fucked-screenshot") - ("H-R" "loadrc") - ("H-r" "rain") - ("H-V" "vlc") - ("H-4" "budget") - ("H-$" "spend") - ("C-BackSpace" "clear-notifications") - ) - -(define-top-keys ;; clipboard - ("H-c" "show-clipboard-history") - ("H-C" "clear-clipboard-history") - ("H-u" "generate-random-uuid") - ("H-B" "bee-movie-script") - ("M-H-u" "urlize-jira-issue")) - -(define-top-keys ;; movement - ("H-h" "move-focus* left") - ("H-j" "move-focus down") - ("H-k" "move-focus up") - ("H-l" "move-focus* right") - - ("H-H" "move-window left") - ("H-J" "move-window down") - ("H-K" "move-window up") - ("H-L" "move-window right") - - ("H-1" "gselect 1") - ("H-2" "gselect 2") - ("H-3" "gselect 3") - - ("H-!" "gmove 1") - ("H-@" "gmove 2") - ("H-#" "gmove 3") - - ("C-H-H" "exchange-direction left") - ("C-H-J" "exchange-direction down") - ("C-H-K" "exchange-direction up") - ("C-H-L" "exchange-direction right") - - ("H-`" "next") - ("H-~" "prev") ;; " - ("H-n" "next-in-frame") - ("H-p" "prev-in-frame") - ("H-N" "pull-hidden-next") - ("H-P" "prev-in-frame") - - ("H-," "pull-from-windowlist")) - -(define-top-keys ;; splitting - ("H-s" "sane-vsplit") - ("H-v" "sane-hsplit") - ("H-=" "balance-frames")) - -(define-top-keys ;; killing - ("H-w" "delete") - ("H-W" "kill") - ("H-BackSpace" "remove") - ("S-H-BackSpace" "kill-and-remove")) - -(define-top-keys ;; naming - ("H-'" "title")) - -(define-top-keys ;; sound - ("H-F1" "mute") - ("H-F2" "exec amixer -q sset Master 5%-") - ("H-F3" "exec amixer -q sset Master 5%+")) - -(define-top-keys ;; screen - ("H-F5" "rotate-brightness-down") - ("H-F6" "rotate-brightness-up") - ("H-F7" "screen-laptop") - ("H-F8" "screen-external")) - -(define-top-keys ;; layout - ("s-H-t" "restore-from-file thirds") - ("s-H-m" "restore-from-file dev") - ("s-H-s" "restore-from-file streaming") - ("s-H-w" "restore-from-file work") - ("s-H-z" "restore-from-file zoom")) - -(define-top-keys ;; timers - ("s-F7" "tea-timer") - ("s-F9" "run-pop-timer") - ("s-F8" "set-pop-timer") - ("s-p" "posture-start") - ("s-P" "posture-stop") - ("s-y" "posture-answer-yes") - ("s-h" "posture-answer-meh") - ("s-n" "posture-answer-no") - ("s-\\" "posture-toggle-pause") - ("s-o" "posture-snooze")) - -(define-top-keys ;; stump - ("Pause" "terminal") ; jesus christ - ("H-F9" "sleep-machine") - ("H-F10" "toggle-stumptray") - ("H-F11" "toggle-current-mode-line") - ("H-F12" "refresh-heads")) - - -;; (stumpwm::unbind-remapped-keys) -(define-remapped-keys - '(("st-256color" - ("s-c" . "C-C") - ("s-v" . "C-V") - ("C-=" . "S-C-SunPageUp") - ("C--" . "S-C-SunPageDown") - ("C-0" . "S-C-Home")) - ("(firefox|Google-chrome|Chromium-browser)" - ("s-1" . "C-S-Tab") - ("s-2" . "C-Tab") - ("C-a" . "Home") - ("C-e" . "End") - ;; I always try to hit ctrl-d to kill a browser window because I'm so used - ;; to terminal windows, and it ends up bookmarking the damn page. In the - ;; interest of not having a random collection of bookmarks grow over time, - ;; I'll just add a mapping to compensate for my stupid brain. - ("C-d" . "C-w") - ;; todo debug why this breaks a really fast C-a-k roll - ;; ("C-a" . "Home") - ;; ("C-e" . "End") - ("s-a" . "C-a") - ("s-d" . "C-d") - ("s-l" . "C-l") - ("s-t" . "C-t") - ("s-w" . "C-w") - ("s-r" . "C-r") - ("s-f" . "C-f") - ("s-z" . "C-z") - ("s-x" . "C-x") - ("s-c" . "C-c") - ("s-v" . "C-v")) - ("" - ("s-z" . "C-z") - ("s-x" . "C-x") - ("s-c" . "C-c") - ("s-v" . "C-v")))) - - -;;;; Sensors ------------------------------------------------------------------ -(defun ? (obj &rest keys) - (if (null keys) - obj - (apply #'? (etypecase obj - (hash-table (gethash (first keys) obj))) - (rest keys)))) - -(defun parse-sensors () - ;; sensors -j is stupid and will output errors before the actual output on - ;; standard out, instead of putting them on standard err like a reasonable - ;; program, e.g.: - ;; - ;; ERROR: Can't get value of subfeature temp1_input: Can't read - ;; { - ;; "iwlwifi_1-virtual-0":{ … }, - ;; … - ;; - ;; So we'll have to drop the `ERROR` lines before we can get to the actual - ;; goddamn JSON. UNIX programs are so great. - (let ((s (losh:sh '("sensors" "-j") :result-type 'stream))) - (loop :while (char= #\E (peek-char nil s)) :do (read-line s)) - (jarl:read t s))) - -(defparameter *sensors-refresh-delay* 5.0 "How long between sensor refreshes (in seconds).") -(defparameter *sensors-next-refresh* nil) -(defparameter *sensors-cache* nil) - -(defun sensors% (&aux (sensors (parse-sensors))) - (hostcase - (:ouroboros (format nil "[CPU ~D°C] [GPU ~D°C ~D°C ~D°C]" - (round (? sensors "nct6779-isa-0290" "CPUTIN" "temp2_input")) - (round (? sensors "amdgpu-pci-4500" "edge" "temp1_input")) - (round (? sensors "amdgpu-pci-4500" "junction" "temp2_input")) - (round (? sensors "amdgpu-pci-4500" "mem" "temp3_input")))) - (:gro (format nil "[CPU ~D°C] [GPU ~D°C]" - (round (? sensors "thinkpad-isa-0000" "CPU" "temp1_input")) - (round (? sensors "amdgpu-pci-0600" "edge" "temp1_input")))) - (t "?"))) - -(defun sensors (&aux (now (get-internal-real-time))) - (if (or (null *sensors-next-refresh*) - (>= now *sensors-next-refresh*)) - (setf *sensors-next-refresh* (+ now (* internal-time-units-per-second *sensors-refresh-delay*)) - *sensors-cache* (sensors%)) - *sensors-cache*)) - -(defun sensors-modeline (ml) - (declare (ignore ml)) - (sensors)) - -(add-screen-mode-line-formatter #\S #'sensors-modeline) - - -;;;; Modeline ----------------------------------------------------------------- -(load-module "battery-portable") -(load-module "cpu") -(load-module "hostname") -(load-module "mem") - -(defun ensure-mode-line () - (when (not (stumpwm::head-mode-line (current-head))) - (toggle-mode-line (current-screen) (current-head)))) - - -(defun configure-modeline () - (setf - *time-modeline-string* - "%a %b %e %H:%M" - - cpu::*cpu-usage-modeline-fmt* - "^[~A~3D%^]" - - cpu::*cpu-modeline-fmt* - "[%c] [%f]" - - mem::*mem-modeline-fmt* - "%b" - - *screen-mode-line-format* - (append - (list "[^B%n^b@%h] %W^>") - - #+todo-some-day (list ;; "(V " - ;; ;; '(:eval (volume)) - ;; ")" - " ") - - ;; battery and brightness for laptops - (hostcase - ((:gro) - '("(B %B)" - " (BR " - (:eval (princ-to-string (brightness))) - "%)"))) - - ;; temp, cpu, mem, time, tray - #+no (list "(TEMP %S) (CPU %C) (MEM %M) %d %T") - (list "(CPU %C) (MEM %M) %d %T") - )) - - (setf *mode-line-timeout* 10) - (setf *mode-line-background-color* "#111111") - - (ensure-mode-line) - ) - -(configure-modeline) - - -;;;; System Tray -------------------------------------------------------------- -(load-module "stumptray") -(defvar *tray-loaded* (run-commands "stumptray")) - - -;;;; Unbreak Typing ----------------------------------------------------------- -(defun stumpwm::input-insert-hyphen-or-space (input key) - (declare (ignore key)) - (input-insert-char input #\space)) - - -;;;; Startup ------------------------------------------------------------------ -;; (defvar *dropbox* - ;; (run-shell-command "~/.dropbox-dist/dropboxd")) - -#+no(defvar *dunst* - (run-shell-command "/usr/bin/dunst -conf ~/.dunstrc")) - -(when (probe-file "/home/sjl/.stumpwmrc.local") - (load "/home/sjl/.stumpwmrc.local")) - - -#;;; Scratch ------------------------------------------------------------------ diff -r 93d27886c099 -r 62e329839625 vim/custom-dictionary.utf-8.add --- a/vim/custom-dictionary.utf-8.add Sun May 18 14:59:11 2025 -0400 +++ b/vim/custom-dictionary.utf-8.add Wed Aug 27 16:19:24 2025 -0400 @@ -336,3 +336,235 @@ skald dwarven tradeoff +Snakefile +Snakemake +melanosomes +melanosome +threonine +multiomics +ANOVA +μL +Opentrons +walkthrough +nanopore +intron +retrotranspose +retrotransposition +transposons +retrotransposon +transposon +retrotransposons +wildcard +PIBS +Thinkpad +HG545 +Lenovo +methylation +CpG +thermocycler +CAS9 +RNP +gDNA +QuickCIP +dephosphorylation +labware +thermocycling +Torrin +thermocycle +Neisseria +Gonorrhoeae +Azithromycin +Ceftriaxone +Quinolone +Quinolones +folates +sulfanilamide +prodrug +diethylene +Prontosil +transpeptidase +lactam +crosslinking +crosslink +Unicycler +FASTQs +Jupyter +topoisomerases +topoisomerase +quinolone +ribosomes +macrolide +Macrolides +Trimmomatic +microbiome +BI529 +BS522 +BS521 +NCBI +conda +Dhatri +OOMs +BI602 +lactamase +backends +webapp +webapps +B2 +ggplot2 +AMRFinder +AMRFinderPlus +BI545 +PIBS800 +isoforms +gyrase +handwave +SNPs +Prensner +acetylation +arginine +histone +histones +octamer +heterochromatin +trimethylated +BIOINF +astrocyte +Armis +Taubman +H3K27M +polycomb +Cristian +DBvolve +sqlite +Bree +Midgewater +Chetwood +noncanonical +XRT +Snakemake's +RiboTIE +rawdogging +multimapping +Riboseq +X11 +JS +GRSA +CCTC +BLASTs +mosaicism +amyloid +microcentrifuge +P1000 +P10 +Trypan +mL +vortexer +OOM +Nanopal +Slurm +hardcode +SDS +dropwise +vortexing +segfaulting +segfaulted +IGV +hardcoding +nonlocal +basecalling +systemd +basecall +basecalls +basecaller +basecalled +Cas9 +samtools +mux +hostnames +wifi +Minimap2 +hedera +Ansible +SMaHT +NOP +unboxing +NUCs +Torrin's +Margit +hederas +auth +MinKNOW +MinION +deduplicate +snakemake +repo's +pericentromeric +MEI +inodes +AluYb +AluYa +FASTQ +BAM +pseudobulk +MEIs +sneakernet +CADIA +deduplicates +unmerged +DCMB +EECS +GM12878 +WGS +VCFs +traceback +ethernet +reenabled +deduplicated +dedupe +Alu +Alus +coreutils +CRISPR +overcounting +speedrun +FF6 +kimchi +SAA +DJ'ed +TA'ed +wildcards +counterintuitive +ish +ECC +Ypsi +etouffée +Ansibilize +fstab +Datura +Ansibilized +indels +DSBs +NHEJ +LINEs +LRS +SV +SRS +HC +transposase +ATAC +clusterfuck +Kerrytown +Friendsgiving +LVM +basecaller +flowcell +reparse +venv +env +concat +Beszel +basecallers +untar +unclustered +helicase +reauthenticate diff -r 93d27886c099 -r 62e329839625 vim/ftplugin/nextflow/folding.vim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/ftplugin/nextflow/folding.vim Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,16 @@ +setlocal foldmethod=expr +setlocal foldexpr=GetNextflowFold(v:lnum) + +function! GetNextflowFold(lnum) + let line = getline(a:lnum) + + if line =~ '^\S.*{$' + return '>1' + elseif line =~ '^}$' + return '<1' + elseif line =~ '^\S' + return 0 + else + return "=" + end +endfunction diff -r 93d27886c099 -r 62e329839625 vim/ftplugin/snakemake/folding.vim --- a/vim/ftplugin/snakemake/folding.vim Sun May 18 14:59:11 2025 -0400 +++ b/vim/ftplugin/snakemake/folding.vim Wed Aug 27 16:19:24 2025 -0400 @@ -9,16 +9,25 @@ let thisline = getline(a:lnum) - " blank lines end folds + " two blank lines end folds if thisline =~? '\v^\s*$' + if ActualPreviousLineNonblank(a:lnum) + return "=" + endif return '-1' " start fold on top level rules or python objects elseif thisline =~? '\v^(rule|def|checkpoint|class)' return ">1" elseif thisline =~? '\v^\S' - if PreviousLineIndented(a:lnum) && NextRuleIndented(a:lnum) - return ">1" + if IsEmpty(a:lnum+1) + if IsEmpty(a:lnum+2) + return ">1" + endif endif + return "0" + " if PreviousLineIndented(a:lnum) && NextRuleIndented(a:lnum) + " return ">1" + " endif endif return "=" @@ -59,3 +68,35 @@ return 0 endfunction + +function! ActualPreviousLineNonblank(lnum) + let current = a:lnum - 1 + + if current >= 1 + let thisline = getline(current) + if thisline =~? '\v^\s*\S' + return 1 + else + return 0 + endif + endwhile + + return 0 +endfunction + +function! IsEmpty(lnum) + let numlines = line('$') + if a:lnum > numlines + return 0 + elseif a:lnum < 1 + return 0 + else + let thisline = getline(a:lnum) + if thisline =~? '\v^$' + return 1 + else + return 0 + endif + endif +endfunction + diff -r 93d27886c099 -r 62e329839625 vim/syntax/htmlten.vim --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/syntax/htmlten.vim Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,38 @@ +" based on the htmldjango syntax + +if exists("b:current_syntax") + finish +endif + +if !exists("main_syntax") + let main_syntax = 'html' +endif + +runtime! syntax/html.vim +unlet b:current_syntax + +syn region tenArgument contained start=/"/ skip=/\\"/ end=/"/ + +syn match tenError "%}\|}}\|#}" +syn match tenTagError contained "#}\|{{\|[^%]}}\|[#]" +syn match tenVarError contained "#}\|{%\|%}\|[<>!#]" + +syn cluster tenBlocks add=tenTagBlock,tenVarBlock,tenComment,tenComBlock + +syn region tenTagBlock start="{%" end="%}" contains=tenArgument,tenTagError display containedin=ALLBUT,@djangoBlocks +syn region tenVarBlock start="{{" end="}}" contains=tenArgument,tenVarError display containedin=ALLBUT,@djangoBlocks +syn region tenComment start="{%\s*comment\(\s\+.\{-}\)\?%}" end="{%\s*endcomment\s*%}" containedin=ALLBUT,@tenBlocks +syn region tenComBlock start="{#" end="#}" containedin=ALLBUT,@tenBlocks + + +hi def link tenTagBlock PreProc +hi def link tenVarBlock PreProc +hi def link tenComment Comment +hi def link tenComBlock Comment + +hi def link tenArgument Constant +hi def link tenError Error +hi def link tenTagError Error +hi def link tenVarError Error + +let b:current_syntax = "htmlten" diff -r 93d27886c099 -r 62e329839625 vim/syntax/lisp.vim --- a/vim/syntax/lisp.vim Sun May 18 14:59:11 2025 -0400 +++ b/vim/syntax/lisp.vim Wed Aug 27 16:19:24 2025 -0400 @@ -63,8 +63,9 @@ " start prefixparameters modifiers directive syn match lispStringFormatDirective contained /\v[~](([-+]?[0-9]*|'.),?)*(:\@|\@:|:|\@)?./ +syn match lispStringAprilComment contained /\v⍝(.)*/ -syn region lispString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=lispStringFormatDirective,@Spell +syn region lispString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=lispStringFormatDirective,lispStringAprilComment,@Spell if exists("g:lisp_instring") syn region lispInString keepend matchgroup=Delimiter start=+"(+rs=s+1 skip=+|.\{-}|+ matchgroup=Delimiter end=+)"+ contains=@lispBaseListCluster,lispInStringString @@ -106,6 +107,7 @@ hi def link lispAtomMark lispMark hi def link lispInStringString lispString hi def link lispStringFormatDirective SpecialChar + hi def link lispStringAprilComment lispComment hi def link lispAtom Identifier hi def link lispAtomBarSymbol Special diff -r 93d27886c099 -r 62e329839625 vim/ultisnips-bullshit/README.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/ultisnips-bullshit/README.markdown Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,5 @@ +This directory would be named "snippets" like a reasonable person would +immediately think to name it, except that UltiSnips hardcodes that one +particular directory name and magically parses it as some other snippet format, +which fails with an inscrutable error. So we have to name it something else. +Great first 30 second experience, UltiSnips. diff -r 93d27886c099 -r 62e329839625 vim/ultisnips-bullshit/html.snippets --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/ultisnips-bullshit/html.snippets Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,191 @@ +snippet doctype "HTML - 5.0 (doctype)" b + +endsnippet + +snippet html "tag: html" bi + + $1 + +endsnippet + +snippet head "tag: head" b + + $1 + +endsnippet + +snippet body "tag: body" b + + $1 + +endsnippet + +snippet nav "tag: nav" b + +endsnippet + +snippet title "tag: title" b +$1$0 +endsnippet + +snippet form "tag: form" b +
+ $0 +
+endsnippet + +snippet fieldset "tag:fieldset" b +
+ $1 + $2 +
+endsnippet + +snippet label "tag: label" b + +endsnippet + +snippet input "tag: input" b + +endsnippet + +snippet submit "tag: submit" b + +endsnippet + +snippet style "stylesheet" b + +endsnippet + +snippet main "tag: main" b +
+ $0 +
+endsnippet + +snippet header "tag: header" b +
+ $0 +
+endsnippet + +snippet footer "tag: footer" b +
+ $0 +
+endsnippet + +snippet table "tag: table" b + + $0 +
+endsnippet + +snippet thead "tag: thead" b + + $0 + +endsnippet + +snippet tbody "tag: tbody" b + + $0 + +endsnippet + +snippet tfoot "tag: tfoot" b + + $0 + +endsnippet + + +snippet tr "tag: tr" b + + $0 + +endsnippet + +snippet td "tag: td" b +$1 +endsnippet + +snippet th "tag: th" b +$1 +endsnippet + +snippet href "tag: a href" i +${2:Text} +endsnippet + +snippet " ." "class" i + class="$1" +endsnippet + +snippet P "tag: p" b +

+ $1 +

+endsnippet + +snippet p "tag: p" b +

$1

+endsnippet + +snippet legend "tag: legend" b +$1 +endsnippet + +snippet span "tag: span" b +$2 +endsnippet + +snippet div "tag: div" b +$2 +endsnippet + +snippet Div "tag: div" b + + $2 + +endsnippet + +snippet ul "tag: ul" b +
    + $1 +
+endsnippet + +snippet li "tag: li" b +
  • $1
  • +endsnippet + +snippet h1 "tag: h1" b +

    $1

    +endsnippet + +snippet h2 "tag: h2" b +

    $1

    +endsnippet + +snippet h3 "tag: h3" b +

    $1

    +endsnippet + +snippet h4 "tag: h4" b +

    $1

    +endsnippet + +snippet h5 "tag: h5" b +
    $1
    +endsnippet + +snippet h6 "tag: h6" b +
    $1
    +endsnippet + +snippet script "tag: script" b + +endsnippet diff -r 93d27886c099 -r 62e329839625 vim/ultisnips-bullshit/htmldjango.snippets --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/ultisnips-bullshit/htmldjango.snippets Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,47 @@ +extends html + +snippet % "Tag" i +{% ${1:tag} %} + $0 +{% end %} +endsnippet + +snippet { "Var" i +{{ $1 }}$0 +endsnippet + +snippet include "include" b +{% include "${1:foo.html}" %} +endsnippet + +snippet includewith "include with" b +{% include "${1:foo.html}" with ${2:var}=${3:val} ${4:only }%} +endsnippet + +snippet with "With" b +{% with ${1:var}=${2:val} %} + $0 +{% end %} +endsnippet + +snippet for "For" b +{% for ${1:var} in ${2:val} %} + $0 +{% endfor %} +endsnippet + +snippet if "If" b +{% if ${1:cond} %} + $0 +{% endif %} +endsnippet + +snippet else "Else" b +{% else %} + $0 +endsnippet + +snippet elif "Elif" b +{% elif ${1:cond} %} + $0 +endsnippet diff -r 93d27886c099 -r 62e329839625 vim/ultisnips-bullshit/htmlten.snippets --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/ultisnips-bullshit/htmlten.snippets Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,29 @@ +extends html + +snippet % "Tag" i +{% ${1:tag} %} + $0 +{% end %} +endsnippet + +snippet { "Var" i +{{ $1 }}$0 +endsnippet + +snippet section "Section (single line)" i +{% section ${1:name} %}$2{% end %} +endsnippet + +snippet Section "Section (multiline)" i +{% section ${1:name} %} + $2 +{% end %} +endsnippet + +snippet template "Template" b +{% template ${1:name} (${2::extends ${3:base}}) (&key$4) %} + +$5 + +{% end %} +endsnippet diff -r 93d27886c099 -r 62e329839625 vim/ultisnips-bullshit/markdown.snippets --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/ultisnips-bullshit/markdown.snippets Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,8 @@ +snippet scrum "Scrum template" b +Scrum: + +* Yesterday: + * $1 +* Today: + * $2 +endsnippet diff -r 93d27886c099 -r 62e329839625 vim/ultisnips-bullshit/python.snippets --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/ultisnips-bullshit/python.snippets Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,27 @@ +snippet #! "#!" b +#!/usr/bin/env python3 +endsnippet + +snippet ifmain "if main" b +if __name__ == '__main__': + ${1:pass} +endsnippet + +snippet p "print()" b +print($1) +endsnippet + +snippet i "if" b +if ${1:cond}: + ${2:pass} +endsnippet + +snippet ei "elif" b +elif ${1:cond}: + ${2:pass} +endsnippet + +snippet e "else" b +else: + ${1:pass} +endsnippet diff -r 93d27886c099 -r 62e329839625 vim/ultisnips-bullshit/r.snippets --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/ultisnips-bullshit/r.snippets Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,7 @@ +snippet lib "library()" b +library(${1:name}) +endsnippet + +snippet inst "install.packages()" b +install.packages("${1:name}") +endsnippet diff -r 93d27886c099 -r 62e329839625 vim/ultisnips-bullshit/sh.snippets --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/ultisnips-bullshit/sh.snippets Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,15 @@ +snippet sete "set -euo pipefail" b +set -euo pipefail +endsnippet + +snippet = "var" b +${1:var}="${2:val}" +endsnippet + +snippet #! "#!" b +#!/usr/bin/env bash +endsnippet + +snippet == "VAR=${$VAR:-default}" b +${1:VAR}="\$\{$1:-${2:default}\}" +endsnippet diff -r 93d27886c099 -r 62e329839625 vim/ultisnips-bullshit/tex.snippets --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/ultisnips-bullshit/tex.snippets Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,85 @@ +global !p +def math(): + return vim.eval('vimtex#syntax#in_mathzone()') == '1' +endglobal + +# Structure ------------------------------------------------------------------- +snippet b "An environment" b +\begin{$1} + $0 +\end{$1} +endsnippet + +snippet sec "\section*" b +\section*{$1}$0 +endsnippet + +snippet ssec "\subsection*" b +\subsection*{$1}$0 +endsnippet + +snippet desc "\begin{description}" b +\begin{description} + $0 +\end{description} +endsnippet + +snippet lst "\begin{lstlisting}" b +\begin{lstlisting} +$0 +\end{lstlisting} +endsnippet + +snippet i "\item[]" b +\item[$1]$0 +endsnippet + +snippet eq "Equation environment" b +\begin{equation*} +\begin{split} + $0 +\end{split} +\end{equation*} +endsnippet + +snippet jot "Set jot length (should go between equation and split envs)" b +\setlength{\jot}{${1:10}pt}$0 +endsnippet + +# Markup ---------------------------------------------------------------------- + +snippet href "The hyperref package's \href{}{} command (for url links)" +\href{${1:url}}{${2:display name}}$0 +endsnippet + +snippet url "A linked URL" +\url{${1:url}}$0 +endsnippet + +snippet fn "Footnote" +\footnote{${1:Note}}$0 +endsnippet + +snippet em "\emph{}" +\emph{${1:${VISUAL:}}}$0 +endsnippet + +# Math ------------------------------------------------------------------------ +snippet "(^|[^a-zA-Z])mm" "Inline LaTeX math" rA +`!p snip.rv = match.group(1)`\$ ${1:${VISUAL:}} \$$0 +endsnippet + +context "math()" +snippet ff "(math) \frac{}{}" +\frac{$1}{$2}$0 +endsnippet + +context "math()" +snippet rm "(math) \mathrm{}" +\mathrm{$1}$0 +endsnippet + +context "math()" +snippet __ "(math) _{}" iA +_{ $1 }$0 +endsnippet diff -r 93d27886c099 -r 62e329839625 vim/vimrc --- a/vim/vimrc Sun May 18 14:59:11 2025 -0400 +++ b/vim/vimrc Wed Aug 27 16:19:24 2025 -0400 @@ -2,8 +2,9 @@ " Author: Steve Losh " Source: https://hg.stevelosh.com/dotfiles/file/tip/vim/vimrc +" See also vimrc-minimal for the rest of this. + " Preamble ---------------------------------------------------------------- {{{ -" set shell=/bin/bash\ --login filetype off @@ -12,39 +13,12 @@ set nocompatible " }}} -" Basic options ----------------------------------------------------------- {{{ - -set modelines=0 -set autoindent -set showmode -set showcmd -set hidden -set visualbell -set ttyfast -set ruler -set backspace=indent,eol,start -set nonumber -set norelativenumber -set laststatus=2 -set history=1000 -set undofile -set undoreload=10000 -set list -set listchars=tab:▸\ ,eol:¬,extends:❯,precedes:❮ -set lazyredraw -set matchtime=3 -set showbreak=↪ -set splitbelow -set splitright -set autowrite -set autoread -set shiftround -set title -set linebreak -set colorcolumn=+1 -set diffopt+=vertical - -" Spelling +" Load Minimal ------------------------------------------------------------ {{{ + +source ~/.vimrc-minimal + +" }}} +" Spelling ---------------------------------------------------------------- {{{ " " There are three dictionaries I use for spellchecking: " @@ -63,136 +37,15 @@ set spellfile=~/.vim/custom-dictionary.utf-8.add,~/.vim-local-dictionary.utf-8.add nnoremap zG 2zg -" Don't try to highlight lines longer than 500 characters. -set synmaxcol=500 - -" Time out on key codes but not mappings. -" Basically this makes terminal Vim work sanely. -set notimeout -set ttimeout -set ttimeoutlen=10 - -" Make Vim able to edit crontab files again. -set backupskip=/tmp/*,/private/tmp/*" - -" Better Completion -set complete=.,w,b,u,t -set completeopt=longest,menuone -inoremap - -" Save when losing focus -au FocusLost * :silent! wall - -" Leader -let mapleader = "," -let maplocalleader = "\\" - -" Cursorline {{{ -" Only show cursorline in the current window and in normal mode. - -augroup cline - au! - au WinLeave,InsertEnter * set nocursorline - au WinEnter,InsertLeave * set cursorline -augroup END - -" }}} -" cpoptions+=J, dammit {{{ - -" Something occasionally removes this. If I manage to find it I'm going to -" comment out the line and replace all its characters with 'FUCK'. -augroup twospace - au! - au BufRead * :set cpoptions+=J -augroup END - -" }}} -" Trailing whitespace {{{ -" Only shown when not in insert mode so I don't go insane. - -augroup trailing - au! - au InsertEnter * :set listchars-=trail:⌴ - au InsertLeave * :set listchars+=trail:⌴ -augroup END +" Invoke spellcheck in insert mode with c-s, or c-S to do it and autotake the +" first suggestion for stuff I intentually use spellcheck to type. +inoremap +inoremap " }}} -" Wildmenu completion {{{ - -set wildmenu -set wildmode=list:longest - -set wildignore+=.hg,.git,.svn " Version control -set wildignore+=*.aux,*.out,*.toc " LaTeX intermediate files -set wildignore+=*.jpg,*.bmp,*.gif,*.png,*.jpeg " binary images -set wildignore+=*.o,*.obj,*.exe,*.dll,*.manifest " compiled object files -set wildignore+=*.spl " compiled spelling word lists -set wildignore+=*.sw? " Vim swap files -set wildignore+=*.DS_Store " OSX bullshit - -set wildignore+=*.luac " Lua byte code - -set wildignore+=migrations " Django migrations -set wildignore+=*.pyc " Python byte code - -set wildignore+=*.orig " Merge resolution files - -set wildignore+=*.fasl " Lisp FASLs -set wildignore+=*.dx64fsl " CCL -set wildignore+=*.lx64fsl " CCL - -" }}} -" Line Return {{{ - -" Make sure Vim returns to the same line when you reopen a file. -" Thanks, Amit -augroup line_return - au! - au BufReadPost * - \ if line("'\"") > 0 && line("'\"") <= line("$") | - \ execute 'normal! g`"zvzz' | - \ endif -augroup END - -" }}} -" Tabs, spaces, wrapping {{{ - -set tabstop=8 -set shiftwidth=4 -set softtabstop=4 -set expandtab -set wrap -set textwidth=80 -set formatoptions=qrn1j -set colorcolumn=+1 - -" }}} -" Backups {{{ - -set backup " enable backups -set noswapfile " it's 2013, Vim. - -set undodir=~/.vim/tmp/undo// " undo files -set backupdir=~/.vim/tmp/backup// " backups -set directory=~/.vim/tmp/swap// " swap files - -" Make those folders automatically if they don't already exist. -if !isdirectory(expand(&undodir)) - call mkdir(expand(&undodir), "p") -endif -if !isdirectory(expand(&backupdir)) - call mkdir(expand(&backupdir), "p") -endif -if !isdirectory(expand(&directory)) - call mkdir(expand(&directory), "p") -endif - -" }}} -" Color scheme {{{ - -syntax on +" Color scheme ------------------------------------------------------------ {{{ + set termguicolors -set background=dark let g:badwolf_tabline = 2 let g:badwolf_html_link_underline = 0 colorscheme goodwolf @@ -207,81 +60,11 @@ " Highlight VCS conflict markers match ErrorMsg '^\(<\|=\|>\)\{7\}\([^=].\+\)\?$' -" }}} - -" }}} -" Abbreviations & Digraphs ------------------------------------------------ {{{ - -iabbrev todo TODO - -silent! digr -. 8230 "U+2026=… HORIZONTAL ELLIPSIS -silent! digr !, 8816 "U+2270=≰ NEITHER LESS-THAN NOR EQUAL TO -silent! digr !. 8817 "U+2271=≱ NEITHER GREATER-THAN NOR EQUAL TO -silent! digr es 8337 "U+2091=ₑ SUBSCRIPT E -silent! digr xs 8339 "U+2093=ₓ SUBSCRIPT X -silent! digr ls 8343 "U+2097=ₗ SUBSCRIPT L -silent! digr ms 8344 "U+2098=ₗ SUBSCRIPT M -silent! digr ns 8345 "U+2099=ₙ SUBSCRIPT N -silent! digr ps 8346 "U+209A=ₚ SUBSCRIPT P -silent! digr ss 8347 "U+209B=ₛ SUBSCRIPT S -silent! digr ts 8348 "U+209C=ₜ SUBSCRIPT T -silent! digr >< 8652 "U+21cc=⇌ EQUILIBRIUM -silent! digr o+ 8853 "U+2295=⊕ CIRCLED PLUS -silent! digr -^ 8593 "U+2191=↑ UPWARDS ARROW - -silent! digr -- 8212 "U+2014=— EM DASH - -silent! digr // 9585 "U+2571=╱ BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT -silent! digr \\ 9586 "U+2572=╲ BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT - -silent! digr \|\| 8214 "U+2016=‖ DOUBLE VERTICAL LINE - -silent! digr ~~ 8967 "U+2307=⌇ WAVY LINE +nnoremap B :call GoodWolfToggleBoldStrings() " }}} " Convenience mappings ---------------------------------------------------- {{{ -" Fuck you, help key. -noremap :checktime -inoremap :checktime - -" Stop it, hash key. -inoremap # X# - -" Kill window -nnoremap K :q - -" Save -nnoremap s :w - -" Man -nnoremap M K - -" Clean up windows -nnoremap - :wincmd = - -" Toggle line numbers -nnoremap n :setlocal number! - -" Sort lines -nnoremap s vip:sort -vnoremap s :sort - -" Tabs -nnoremap ( :tabprev -nnoremap ) :tabnext - -" My garbage brain can't ever remember digraph codes -inoremap :help digraph-table - -" Wrap -" mnemonic: less' -S command/option -nnoremap S :set wrap! - -" Inserting blank lines -" I never use the default behavior of and this saves me a keystroke... -nnoremap o - " Copying/pasting text to the system clipboard. noremap p "+p vnoremap y "+y @@ -296,21 +79,6 @@ nnoremap o "zyiW:call Open(@z) vnoremap o "zy:call Open(@z) -" Delete to black hole register -nnoremap dD "_dd -vnoremap D "_d - -" Yank to end of line -nnoremap Y y$ - -" Reselect last-pasted text -nnoremap gv `[v`] - -" I constantly hit "u" in visual mode when I mean to "y". Use "gu" for those rare occasions. -" From https://github.com/henrik/dotfiles/blob/master/vim/config/mappings.vim -vnoremap u -vnoremap gu u - " Rebuild Ctags (mnemonic RC -> CR -> ) nnoremap :silent !myctags >/dev/null 2>&1 &:redraw! @@ -319,169 +87,15 @@ \ . synIDattr(synID(line("."),col("."),0),"name") . "> lo<" \ . synIDattr(synIDtrans(synID(line("."),col("."),1)),"name") . ">" -" Clean trailing whitespace -nnoremap ww mz:%s/\s\+$//:let @/=''`z - " Send visual selection to paste.stevelosh.com vnoremap P :w !pb && open `pbpaste` -" Select entire buffer -nnoremap vaa ggvGg_ -nnoremap Vaa ggVG - -" Fix from spellcheck -" I can never remember if it's zg or z=, and the wrong one adds the word to -" the DB (lol), so fuck it, just add an easier mapping. -nnoremap zz z= -nnoremap z= :echo "use zz you idiot" - -" "Uppercase word" mapping. -" -" This mapping allows you to press in insert mode to convert the current -" word to uppercase. It's handy when you're writing names of constants and -" don't want to use Capslock. -" -" To use it you type the name of the constant in lowercase. While your -" cursor is at the end of the word, press to uppercase it, and then -" continue happily on your way: -" -" cursor -" v -" max_connections_allowed| -" -" MAX_CONNECTIONS_ALLOWED| -" ^ -" cursor -" -" It works by exiting out of insert mode, recording the current cursor location -" in the z mark, using gUiw to uppercase inside the current word, moving back to -" the z mark, and entering insert mode again. -" -" Note that this will overwrite the contents of the z mark. I never use it, but -" if you do you'll probably want to use another mark. -inoremap mzgUiw`za - -" Panic Button -nnoremap mzggg?G`z - -" zt is okay for putting something at the top of the screen, but when I'm -" writing prose I often want to put something at not-quite-the-top of the -" screen. zh is "zoom to head level" -nnoremap zh mzzt10`z - -" Diffoff -nnoremap D :diffoff! - -" Formatting, TextMate-style -nnoremap Q gqip -vnoremap Q gq - -" Reformat line. -" I never use l as a macro register anyway. -nnoremap ql gqq - -" Indent/dedent/autoindent what you just pasted. -nnoremap > V`]< -nnoremap > V`]> -nnoremap =- V`]= - -" Keep the cursor in place while joining lines -nnoremap J mzJ`z - -" Join an entire paragraph. -" -" Useful for writing GitHub comments in actual Markdown and then translating it -" to their bastardized version of Markdown. -nnoremap j mzvipJ`z - -" Split line (sister to [J]oin lines) -" The normal use of S is covered by cc, so don't worry about shadowing it. -nnoremap S i^mwgk:silent! s/\v +$//:noh`w - -" Substitute -nnoremap :%s/ -vnoremap :s/ - -" Marks and Quotes -noremap ' ` -noremap æ ' -noremap ` - -" Select (charwise) the contents of the current line, excluding indentation. -" Great for pasting Python lines into REPLs. -nnoremap vv ^vg_ - -" Typos -command! -bang E e -command! -bang Q q -command! -bang W w -command! -bang QA qa -command! -bang Qa qa -command! -bang Wa wa -command! -bang WA wa -command! -bang Wq wq -command! -bang WQ wq -command! -bang Wqa wqa - -" Unfuck my screen -nnoremap U :syntax sync fromstart:redraw! - -" Zip Right -" -" Moves the character under the cursor to the end of the line. Handy when you -" have something like: -" -" foo -" -" And you want to wrap it in a method call, so you type: -" -" println()foo -" -" Once you hit escape your cursor is on the closing paren, so you can 'zip' it -" over to the right with this mapping. -" -" This should preserve your last yank/delete as well. -nnoremap zl :let @z=@"x$p:let @"=@z - -" Indent from insert mode -" has to be imap because we want to be able to use the "go-indent" mapping -imap gi - -" Diff Navigation -nnoremap ]d ]c -nnoremap [d [c - -" Typo navigation -nnoremap ]z ]S -nnoremap [z [S -nnoremap ]Z ]Sz= -nnoremap [Z [Sz= - -" Header Lines -nnoremap - o80a-kJ079lD - -" Insert Mode Completion {{{ - -inoremap -inoremap -inoremap - -" }}} - -" Window Resizing {{{ -" right/up : bigger -" left/down : smaller -nnoremap :vertical resize +3 -nnoremap :vertical resize -3 -nnoremap :resize +3 -nnoremap :resize -3 -" }}} - " }}} " Quick editing ----------------------------------------------------------- {{{ nnoremap eb :vsplit ~/Dropbox/bitly.txt -nnoremap ed :vsplit ~/.vim/custom-dictionary.utf-8.add +nnoremap ez :vsplit ~/.vim/custom-dictionary.utf-8.addGmzzt10`z +nnoremap eZ :vsplit ~/.vim-local-dictionary.utf-8.addGmzzt10`z nnoremap ef :vsplit ~/.config/fish/config.fish nnoremap eg :vsplit ~/.gitconfig nnoremap es :vsplit ~/.stumpwmrc @@ -492,7 +106,8 @@ nnoremap eln :vsplit ~/lab/README.markdown nnoremap eq :vsplit ~/Dropbox/quotes.txtGzz nnoremap et :vsplit ~/.tmux.conf -nnoremap ev :vsplit ~/.vimrc +nnoremap evf :vsplit ~/.vimrc +nnoremap evm :vsplit ~/.vimrc-minimal " }}} " Status Line ------------------------------------------------------------- {{{ @@ -604,191 +219,76 @@ " set statusline+=%= " }}} -" Searching and movement -------------------------------------------------- {{{ - -" Use sane regexes. -nnoremap / /\v -vnoremap / /\v - -set ignorecase -set smartcase -set incsearch -set showmatch -set hlsearch -set gdefault - -set scrolloff=5 -set sidescroll=1 -set sidescrolloff=10 - -set virtualedit+=block - -noremap :noh:call clearmatches() - -runtime macros/matchit.vim -map % -silent! unmap [% -silent! unmap ]% - -" Made D behave -nnoremap D d$ - -" Don't move on * -" I'd use a function for this but Vim clobbers the last search when you're in -" a function so fuck it, practicality beats purity. -nnoremap * :let stay_star_view = winsaveview()*:call winrestview(stay_star_view) - -" Jumping to tags. -" -" Basically, jumps to tags (like normal) and opens the tag in a new -" split instead. -" -" Both of them will align the destination line to the upper middle part of the -" screen. Both will pulse the cursor line so you can see where the hell you -" are. will also fold everything in the buffer and then unfold just -" enough for you to see the destination line. -" -function! JumpTo(jumpcommand) - execute a:jumpcommand - call FocusLine() - Pulse -endfunction -function! JumpToInSplit(jumpcommand) - execute "normal! \v" - execute a:jumpcommand - Pulse -endfunction - -function! JumpToTag() - call JumpTo("normal! \") -endfunction -function! JumpToTagInSplit() - call JumpToInSplit("normal \") -endfunction - -nnoremap :silent! call JumpToTag() -nnoremap :silent! call JumpToTagInSplit() - -" Keep search matches in the middle of the window. -nnoremap n nzzzv -nnoremap N Nzzzv - -" Same when jumping around -nnoremap g; g;zz -nnoremap g, g,zz -nnoremap zz - -" Easier to type, and I never use the default behavior. -noremap H ^ -noremap L $ -vnoremap L g_ - -" Heresy -inoremap I -inoremap A -cnoremap -cnoremap - -" go indent -nnoremap gi mzVap=`z -nnoremap gI mzgg=G`z - -" Fix linewise visual selection of various text objects -nnoremap VV V -nnoremap Vit vitVkoj -nnoremap Vat vatV -nnoremap Vab vabV -nnoremap VaB vaBV - -" Directional Keys {{{ - -" It's 2013. -noremap j gj -noremap k gk -noremap gj j -noremap gk k - -" Easy buffer navigation -noremap h -noremap j -noremap k -noremap l - -noremap v v +" Filetype-specific ------------------------------------------------------- {{{ + +" April {{{ + +augroup ft_commonlisp_april " {{{ + au! + + au FileType lisp inoremap ; ⍝ + au FileType lisp inoremap i ⍳ + au FileType lisp inoremap r ⍴ + au FileType lisp inoremap e ∊ + au FileType lisp inoremap _i ⍸ + au FileType lisp inoremap _, ⍪ + + au FileType lisp inoremap 1 ¨ + au FileType lisp inoremap F ⍨ + au FileType lisp inoremap P ⍣ + au FileType lisp inoremap R ⍤ + + au FileType lisp inoremap * × + au FileType lisp inoremap / ÷ + au FileType lisp inoremap 0 ∘ + au FileType lisp inoremap - ¯ + au FileType lisp inoremap l ⍟ + + au FileType lisp inoremap c ⌈ + au FileType lisp inoremap f ⌊ + + au FileType lisp inoremap ← + au FileType lisp inoremap < ← + au FileType lisp inoremap > → + au FileType lisp inoremap ^ ↑ + au FileType lisp inoremap v ↓ + + au FileType lisp inoremap d ∆ + au FileType lisp inoremap D ⍙ + + au FileType lisp inoremap Gk ⍋ + au FileType lisp inoremap Gj ⍒ + + au FileType lisp inoremap oo ○ + au FileType lisp inoremap o\| ⌽ + au FileType lisp inoremap o\ ⍉ + au FileType lisp inoremap o- ⊖ + + au FileType lisp inoremap A ∧ + au FileType lisp inoremap O ∨ + + au FileType lisp inoremap =< ≤ + au FileType lisp inoremap =< ≥ + au FileType lisp inoremap =/ ≠ + au FileType lisp inoremap === ≡ + au FileType lisp inoremap ==/ ≢ + + au FileType lisp inoremap q ⎕ + au FileType lisp inoremap Q ⌷ + au FileType lisp inoremap t ⊢ + + au FileType lisp inoremap u ∪ + au FileType lisp inoremap U ∩ + au FileType lisp inoremap + ⌿ + au FileType lisp inoremap [ ⊂ + au FileType lisp inoremap ] ⊃ + + au FileType lisp inoremap a ⍺ + au FileType lisp inoremap w ⍵ + au FileType lisp inoremap z ⍬ +augroup END " }}} " }}} -" Visual Mode */# from Scrooloose {{{ - -function! s:VSetSearch() - let temp = @@ - norm! gvy - let @/ = '\V' . substitute(escape(@@, '\'), '\n', '\\n', 'g') - let @@ = temp -endfunction - -vnoremap * :call VSetSearch()// -vnoremap # :call VSetSearch()?? - -" }}} -" List navigation {{{ - -nnoremap :cprevzvzz -nnoremap :cnextzvzz -nnoremap :lprevzvzz -nnoremap :lnextzvzz - -" }}} - -" }}} -" Folding ----------------------------------------------------------------- {{{ - -set foldlevelstart=0 - -" Space to toggle folds. -nnoremap za -vnoremap za - -" Make zO recursively open whatever fold we're in, even if it's partially open. -nnoremap zO zczO - -" "Focus" the current line. Basically: -" -" 1. Close all folds. -" 2. Open just the folds containing the current line. -" 3. Move the line to a bit (25 lines) down from the top of the screen. -" 4. Pulse the line. -" -" This mapping wipes out the z mark, which I never use. -" -" I use :sus for the rare times I want to actually background Vim. -function! FocusLine() - let oldscrolloff = &scrolloff - set scrolloff=0 - execute "keepjumps normal! mzzMzvzt25\`z:Pulse\" - let &scrolloff = oldscrolloff -endfunction -nnoremap :call FocusLine() - -function! MyFoldText() " {{{ - let line = getline(v:foldstart) - - let nucolwidth = &fdc + &number * &numberwidth - let windowwidth = winwidth(0) - nucolwidth - 3 - let foldedlinecount = v:foldend - v:foldstart - - " expand tabs into spaces - let onetab = strpart(' ', 0, &tabstop) - let line = substitute(line, '\t', onetab, 'g') - - let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount)) - let fillcharcount = windowwidth - len(line) - len(foldedlinecount) - return line . '…' . repeat(" ",fillcharcount) . foldedlinecount . '…' . ' ' -endfunction " }}} -set foldtext=MyFoldText() - -" }}} -" Filetype-specific ------------------------------------------------------- {{{ - " Assembly {{{ augroup ft_asm @@ -1069,6 +569,7 @@ au BufNewFile,BufRead *.paren set filetype=lisp au BufNewFile,BufRead .abclrc set filetype=lisp au BufNewFile,BufRead .lisprc set filetype=lisp + au BufNewFile,BufRead stumpwmrc set filetype=lisp au BufNewFile,BufRead .stumpwmrc set filetype=lisp au BufNewFile,BufRead .stumpwmrc.local set filetype=lisp @@ -1125,57 +626,6 @@ " Writing au FileType lisp noremap = I; => - - " April - au FileType lisp inoremap ; ⍝ - au FileType lisp inoremap i ⍳ - au FileType lisp inoremap r ⍴ - au FileType lisp inoremap e ∊ - au FileType lisp inoremap _i ⍸ - au FileType lisp inoremap _, ⍪ - au FileType lisp inoremap :~ ⍨ - au FileType lisp inoremap :^ ¨ - - au FileType lisp inoremap * × - au FileType lisp inoremap / ÷ - au FileType lisp inoremap 0 ∘ - au FileType lisp inoremap - ¯ - - au FileType lisp inoremap c ⌈ - au FileType lisp inoremap f ⌊ - - au FileType lisp inoremap < ← - au FileType lisp inoremap > → - au FileType lisp inoremap ^ ↑ - au FileType lisp inoremap v ↓ - - au FileType lisp inoremap G^ ⍋ - au FileType lisp inoremap Gv ⍒ - - au FileType lisp inoremap o\| ⌽ - au FileType lisp inoremap o/ ⍉ - au FileType lisp inoremap o- ⊖ - - au FileType lisp inoremap A ∧ - au FileType lisp inoremap O ∨ - - au FileType lisp inoremap =< ≤ - au FileType lisp inoremap =< ≥ - au FileType lisp inoremap =/ ≠ - au FileType lisp inoremap === ≡ - au FileType lisp inoremap ==/ ≢ - - au FileType lisp inoremap q ⎕ - au FileType lisp inoremap Q ⌷ - au FileType lisp inoremap t ⊢ - - au FileType lisp inoremap u ∪ - au FileType lisp inoremap U ∩ - au FileType lisp inoremap + ⌿ - au FileType lisp inoremap [ ⊂ - au FileType lisp inoremap ] ⊃ - - au FileType lisp inoremap z ⍬ augroup END " }}} " }}} @@ -1270,6 +720,9 @@ au BufNewFile,BufRead dashboard.py normal! zR au BufNewFile,BufRead local_settings.py normal! zR + au BufNewFile,BufRead *.htmldjango setlocal filetype=htmldjango + au BufNewFile,BufRead *.htmldjango.hx setlocal filetype=htmldjango + au BufNewFile,BufRead admin.py setlocal filetype=python.django au BufNewFile,BufRead urls.py setlocal filetype=python.django au BufNewFile,BufRead models.py setlocal filetype=python.django @@ -1480,11 +933,6 @@ au FileType go iabbrev enilrs if err != nil {return "", err au FileType go iabbrev enilrz if err != nil {return 0, err - au FileType go iabbrev enilrw if err != nil {return fmt.Errorf(": %w", err=Eatchar('\s') - au FileType go iabbrev enilrwn if err != nil {return nil, fmt.Errorf(": %w", err=Eatchar('\s') - au FileType go iabbrev enilrws if err != nil {return "", fmt.Errorf(": %w", err=Eatchar('\s') - au FileType go iabbrev enilrwz if err != nil {return 0, fmt.Errorf(": %w", err=Eatchar('\s') - au FileType gohtmltmpl setlocal shiftwidth=4 augroup END @@ -1501,30 +949,21 @@ " }}} " HTML, Django, Jinja, Dram, Go, Kill Me {{{ -let g:html_indent_tags = ['p', 'li'] +let g:html_indent_tags = ['p', 'li', 'div'] + +let g:html_indent_inctags = "html,body,head,tbody,div" augroup ft_html au! - au BufNewFile,BufRead *.html setlocal filetype=gohtmltmpl + au BufNewFile,BufRead *.djula setlocal filetype=htmldjango au BufNewFile,BufRead *.dram setlocal filetype=htmldjango au FileType html,jinja,htmldjango,gohtmltmpl setlocal foldmethod=manual - - " Use f to fold the current tag. - au FileType html,jinja,htmldjango,gohtmltmpl nnoremap f Vatzf - - " Use t to fold the current templatetag. - au FileType html,jinja,htmldjango nmap t viikojozf - - " Indent tag - au FileType html,jinja,htmldjango,gohtmltmpl nnoremap = Vat= - - " Django tags - au FileType jinja,htmldjango inoremap {%%} - - " Django variables - au FileType jinja,htmldjango inoremap {{}} + au FileType html,jinja,htmldjango,gohtmltmpl setlocal foldmethod=manual + + au FileType html,jinja,htmldjango,gohtmltmp inoremap a + au FileType html,jinja,htmldjango,gohtmltmp inoremap O augroup END " }}} @@ -1558,12 +997,24 @@ augroup END " }}} +" JSON {{{ + +augroup ft_json + au! + + au FileType json setlocal sw=4 +augroup END + +" }}} " Latex {{{ let g:tex_flavor = 'latex' augroup ft_latex au! + + au Filetype tex inoremap \begin{} + au Filetype tex nnoremap q :%s/[‘’]/'/ augroup END " }}} @@ -1657,8 +1108,6 @@ au Filetype markdown nnoremap 3 mzI###`zllll au Filetype markdown nnoremap 4 mzI####`zlllll - au Filetype markdown inoremap mz?^ *\*?e"zy0:noh`z"zpA* a - au Filetype markdown inoremap mz?^ *\*?e"zy0:noh`z"zpA * a au Filetype markdown inoremap mz0xx`za au Filetype markdown inoremap mzI `zlla augroup END @@ -1693,6 +1142,15 @@ augroup END " }}} +" NextFlow {{{ + +augroup ft_nextflow + au! + + " au BufRead,BufNewFile *.nf set ft=groovy +augroup END + +" }}} " Nginx {{{ augroup ft_nginx @@ -1761,17 +1219,51 @@ " }}} " Python {{{ +" Helper Functions {{{ +let g:current_python_lsp_client = 0 + +function! PythonLSPConnect() "{{{ + if g:current_python_lsp_client == 0 + lua vim.lsp.start_client({cmd={"nc", "127.0.0.1", "9898"}}) + " TODO lol + let g:current_python_lsp_client = 1 + endif +endfunction "}}} + +function! PythonLSPAttach() "{{{ + call PythonLSPConnect() + lua vim.lsp.buf_attach_client(0, 1) + call PythonLSPMappings() +endfunction "}}} + +function! PythonLSPSig() "{{{ + lua vim.lsp.buf.signature_help() + return "" +endfunction "}}} + +function! PythonLSPMappings() "{{{ + setlocal omnifunc=v:lua.vim.lsp.omnifunc + inoremap + nnoremap :lua vim.lsp.buf.definition() + nnoremap M :lua vim.lsp.buf.hover() + inoremap =PythonLSPSig() +endfunction "}}} + +" }}} + augroup ft_python au! au FileType python setlocal define=^\s*\\(def\\\\|class\\) - au FileType python setlocal textwidth=100 + au FileType python setlocal textwidth=88 " Jesus tapdancing Christ, built-in Python syntax, you couldn't let me " override this in a normal way, could you? au FileType python if exists("python_space_error_highlight") | unlet python_space_error_highlight | endif au FileType python nnoremap gi :Neoformat blackzx + + au FileType python nnoremap cc :call PythonLSPAttach() augroup END " }}} @@ -1786,6 +1278,59 @@ augroup END " }}} +" R {{{ + +let R_external_term = 'st -t "R REPL" --' +let R_args = ['--no-save', '--quiet'] +let R_save_win_pos = 0 +let R_arrange_windows = 0 +let R_assign = 0 +let R_clear_line = 1 +let R_nvim_wd = 1 +let R_user_maps_only = 1 +let R_nvimpager = 'vertical' +let R_help_w = 81 +let r_indent_ess_comments = 0 +let r_indent_ess_compatible = 0 +let r_indent_align_args = 0 + +function! s:customNvimRMappings() + " Normal Mode + nmap Or RStart + nmap Cr RClose + nmap c RClearConsole + nmap h RHelp + nmap M RShowArgs + nmap e RSendParagraph + nmap w mzviwRSendSelection'z + nmap W mzviWRSendSelection'z + nmap S RSendLine + nmap E RSendLine + nmap f RSendFile + nmap i RViewDFv + nmap I RViewDFs + nmap gi mzvip:Rformat'z + + inoremap + + " Insert Mode + inoremap A \|> + inoremap <- + inoremap A + + + " Visual Mode + vmap e RSendSelection + vmap gi :Rformat +endfunction + +augroup ft_r + au! + + autocmd filetype r setlocal shiftwidth=2 + autocmd filetype r call s:customNvimRMappings() +augroup END + +" }}} " Sh {{{ function! SendShellParagraph() "{{{ @@ -1795,6 +1340,8 @@ augroup ft_sh au! + au BufRead,BufNewFile *.sbat set ft=sh + au FileType sh nnoremap e :call NeoReplSendCurrentLine() au FileType sh nnoremap E :call SendShellParagraph() au FileType sh nnoremap F :call NeoReplSendEntireFile(1) @@ -1830,6 +1377,39 @@ augroup END " }}} +" TEN templates {{{ + +function! RecompileTENTemplates() "{{{ + let systems = split(system('ls -1 *.asd | grep -v test | cut -d. -f1 | uniq')) " its fine + if len(systems) == 0 + echom "Could not find any .asd files..." + return + elseif len(systems) > 1 + echom "Found too many any .asd files..." + return + endif + + call vlime#plugin#SendToREPL("(ql:quickload :" . systems[0] . ")") +endfunction "}}} + +augroup ft_ten + au! + + au BufNewFile,BufRead *.ten setlocal filetype=htmlten + au BufNewFile,BufRead *.ten nnoremap q :call RecompileTENTemplates() +augroup END + +" }}} +" TODOs {{{ + +augroup ft_todos + au! + + au BufWritePost /home/sjl/Sync/school/todo/TODO :silent !hg -R /home/sjl/Sync/school/todo cmore + au BufWritePost /home/sjl/Sync/school/todo/irons.markdown :silent !hg -R /home/sjl/Sync/school/todo cmore +augroup END + +" }}} " Vagrant {{{ augroup ft_vagrant @@ -1860,6 +1440,7 @@ au! au FileType yaml set shiftwidth=2 + au FileType yaml set foldmethod=marker foldmarker={{{,}}} augroup END " }}} @@ -1899,6 +1480,7 @@ vmap -< ++< vmap -^ ++^ vmap -V ++v +vmap -- +- " }}} " Clam {{{ @@ -1923,12 +1505,17 @@ au FileType lisp setlocal commentstring=;;\ %s au FileType makerlisp setlocal commentstring=;;\ %s au FileType puppet setlocal commentstring=#\ %s + au FileType snakemake setlocal commentstring=#\ %s au FileType nginx setlocal commentstring=#\ %s au FileType fish setlocal commentstring=#\ %s au FileType gnuplot setlocal commentstring=#\ %s + au FileType singularity setlocal commentstring=#\ %s au FileType cs setlocal commentstring=//\ %s + au FileType c setlocal commentstring=//\ %s + au FileType cpp setlocal commentstring=//\ %s au FileType arduino setlocal commentstring=//\ %s au FileType pandabt setlocal commentstring=//\ %s + au FileType nextflow setlocal commentstring=//\ %s augroup END " }}} @@ -2021,6 +1608,7 @@ let g:gundo_preview_bottom = 1 let g:gundo_tree_statusline = "Gundo" let g:gundo_preview_statusline = "Gundo Preview" +let g:gundo_prefer_python3 = 1 " }}} " HTML5 {{{ @@ -2043,6 +1631,16 @@ nnoremap :Neoformat +let g:neoformat_snakemake_snakefmt = { + \ 'exe': '/home/sjl/bin/venvs/tools/bin/snakefmt', + \ 'args': [], + \ 'replace': 1, + \ 'stdin': 0, + \ 'valid_exit_codes': [0] + \ } + +let g:neoformat_enabled_snakemake = ['snakefmt'] + " }}} " NeoRepl {{{ @@ -2118,7 +1716,7 @@ let g:paredit_smartjump = 1 let g:paredit_shortmaps = 0 -let g:paredit_electric_return = 0 +let g:paredit_electric_return = 1 let g:paredit_matchlines = 200 let g:paredit_disable_lisp = 1 @@ -2407,6 +2005,15 @@ let g:targets_pairs = '()b {}B []r <>' " }}} +" Ultisnips {{{ + +let g:UltiSnipsExpandTrigger = '' +let g:UltiSnipsJumpForwardTrigger = '' +let g:UltiSnipsJumpBackwardTrigger = '' + +let g:UltiSnipsSnippetDirectories=[$HOME.'/.vim/ultisnips-bullshit'] + +" }}} " Vlime {{{ @@ -2513,7 +2120,7 @@ au FileType lisp,vlime_repl,vlime_inspector,vlime_sldb,vlime_notes,vlime_xref,vlime_preview call MapVlimeKeys() " Fix - au FileType lisp inoremap =vlime#plugin#VlimeKey("cr") + au FileType lisp inoremap =vlime#plugin#VlimeKey("cr") au FileType vlime_xref nnoremap :call vlime#ui#xref#OpenCurXref() au FileType vlime_notes nnoremap :call vlime#ui#compiler_notes#OpenCurNote() au FileType vlime_sldb nnoremap :call vlime#ui#sldb#ChooseCurRestart() @@ -2533,69 +2140,7 @@ " Windowswap {{{ let g:windowswap_map_keys = 0 "prevent default bindings -nnoremap ws :call WindowSwap#EasyWindowSwap() - -" }}} - -" }}} -" Text objects ------------------------------------------------------------ {{{ - -" Folds {{{ - -onoremap if :normal! [zv]z -onoremap af :normal! [zV]z -vnoremap if :normal! ]zv[z -vnoremap af :normal! ]zV[z - -" }}} -" Shortcut for [] {{{ - -onoremap ir i[ -onoremap ar a[ -vnoremap ir i[ -vnoremap ar a[ - -" }}} -" Numbers {{{ - -" Motion for numbers. Great for CSS. Lets you do things like this: -" -" margin-top: 200px; -> daN -> margin-top: px; -" ^ ^ -" TODO: Handle floats. - -onoremap N :call NumberTextObject(0) -xnoremap N :call NumberTextObject(0) -onoremap aN :call NumberTextObject(1) -xnoremap aN :call NumberTextObject(1) -onoremap iN :call NumberTextObject(1) -xnoremap iN :call NumberTextObject(1) - -function! s:NumberTextObject(whole) - let num = '\v[0-9]' - - " If the current char isn't a number, walk forward. - while getline('.')[col('.') - 1] !~# num - normal! l - endwhile - - " Now that we're on a number, start selecting it. - normal! v - - " If the char after the cursor is a number, select it. - while getline('.')[col('.')] =~# num - normal! l - endwhile - - " If we want an entire word, flip the select point and walk. - if a:whole - normal! o - - while col('.') > 1 && getline('.')[col('.') - 2] =~# num - normal! h - endwhile - endif -endfunction +nnoremap :call WindowSwap#EasyWindowSwap() " }}} @@ -2902,6 +2447,7 @@ nnoremap 4 :call HiInterestingWord(4) nnoremap 5 :call HiInterestingWord(5) nnoremap 6 :call HiInterestingWord(6) +nnoremap 7 :call HiInterestingWord(7) " }}} " Default Highlights {{{ @@ -2912,6 +2458,7 @@ hi def InterestingWord4 guifg=#000000 ctermfg=16 guibg=#b88853 ctermbg=137 hi def InterestingWord5 guifg=#000000 ctermfg=16 guibg=#ff9eb8 ctermbg=211 hi def InterestingWord6 guifg=#000000 ctermfg=16 guibg=#ff2c4b ctermbg=195 +hi def InterestingWord7 guifg=#000000 ctermfg=16 guibg=#af5fff ctermbg=135 " }}} diff -r 93d27886c099 -r 62e329839625 vim/vimrc-minimal --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/vimrc-minimal Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,672 @@ +" .vimrc-minimal +" Author: Steve Losh +" Source: https://hg.stevelosh.com/dotfiles/file/tip/vim/vimrc + +" A minimal subset of my vimrc settings, suitable for syncing on its own to +" a server so I have some basic settings, but don't have to install the whole +" hog. + +" Preamble ---------------------------------------------------------------- {{{ + +set shell=/bin/bash\ --login + +" }}} +" Basic options ----------------------------------------------------------- {{{ + +set modelines=0 +set autoindent +set showmode +set showcmd +set hidden +set visualbell +set ttyfast +set ruler +set backspace=indent,eol,start +set nonumber +set norelativenumber +set laststatus=2 +set history=1000 +set undofile +set undoreload=10000 +set list +set listchars=tab:▸\ ,eol:¬,extends:❯,precedes:❮ +set lazyredraw +set matchtime=3 +set showbreak=↪ +set splitbelow +set splitright +set autowrite +set autoread +set shiftround +set title +set linebreak +set colorcolumn=+1 +set diffopt+=vertical + +" Don't try to highlight lines longer than 500 characters. +set synmaxcol=500 + +" Time out on key codes but not mappings. +" Basically this makes terminal Vim work sanely. +set notimeout +set ttimeout +set ttimeoutlen=10 + +" Make Vim able to edit crontab files again. +set backupskip=/tmp/*,/private/tmp/*" + +" Better Completion +set complete=.,w,b,u,t +set completeopt=longest,menuone +inoremap + +" Save when losing focus +au FocusLost * :silent! wall + +" Leader +let mapleader = "," +let maplocalleader = "\\" + +" Cursorline {{{ +" Only show cursorline in the current window and in normal mode. + +augroup cline + au! + au WinLeave,InsertEnter * set nocursorline + au WinEnter,InsertLeave * set cursorline +augroup END + +" }}} +" cpoptions+=J, dammit {{{ + +" Something occasionally removes this. If I manage to find it I'm going to +" comment out the line and replace all its characters with 'FUCK'. +augroup twospace + au! + au BufRead * :set cpoptions+=J +augroup END + +" }}} +" Trailing whitespace {{{ +" Only shown when not in insert mode so I don't go insane. + +augroup trailing + au! + au InsertEnter * :set listchars-=trail:⌴ + au InsertLeave * :set listchars+=trail:⌴ +augroup END + +" }}} +" Wildmenu completion {{{ + +set wildmenu +set wildmode=list:longest + +set wildignore+=.hg,.git,.svn " Version control +set wildignore+=*.aux,*.out,*.toc " LaTeX intermediate files +set wildignore+=*.jpg,*.bmp,*.gif,*.png,*.jpeg " binary images +set wildignore+=*.o,*.obj,*.exe,*.dll,*.manifest " compiled object files +set wildignore+=*.spl " compiled spelling word lists +set wildignore+=*.sw? " Vim swap files +set wildignore+=*.DS_Store " OSX bullshit + +set wildignore+=*.luac " Lua byte code + +set wildignore+=migrations " Django migrations +set wildignore+=*.pyc " Python byte code + +set wildignore+=*.orig " Merge resolution files + +set wildignore+=*.fasl " Lisp FASLs +set wildignore+=*.dx64fsl " CCL +set wildignore+=*.lx64fsl " CCL + +" }}} +" Line Return {{{ + +" Make sure Vim returns to the same line when you reopen a file. +" Thanks, Amit +augroup line_return + au! + au BufReadPost * + \ if line("'\"") > 0 && line("'\"") <= line("$") | + \ execute 'normal! g`"zvzz' | + \ endif +augroup END + +" }}} +" Tabs, spaces, wrapping {{{ + +set tabstop=8 +set shiftwidth=4 +set softtabstop=4 +set expandtab +set wrap +set textwidth=80 +set formatoptions=qrn1j +set colorcolumn=+1 + +" }}} +" Backups {{{ + +set backup " enable backups +set noswapfile " it's 2013, Vim. + +set undodir=~/.vim/tmp/undo// " undo files +set backupdir=~/.vim/tmp/backup// " backups +set directory=~/.vim/tmp/swap// " swap files + +" Make those folders automatically if they don't already exist. +if !isdirectory(expand(&undodir)) + call mkdir(expand(&undodir), "p") +endif +if !isdirectory(expand(&backupdir)) + call mkdir(expand(&backupdir), "p") +endif +if !isdirectory(expand(&directory)) + call mkdir(expand(&directory), "p") +endif + +" }}} +" Color scheme {{{ + +syntax on +set background=dark + +" }}} + +" }}} +" Abbreviations & Digraphs ------------------------------------------------ {{{ + +iabbrev todo TODO + +silent! digr -. 8230 "U+2026=… HORIZONTAL ELLIPSIS +silent! digr !, 8816 "U+2270=≰ NEITHER LESS-THAN NOR EQUAL TO +silent! digr !. 8817 "U+2271=≱ NEITHER GREATER-THAN NOR EQUAL TO +silent! digr es 8337 "U+2091=ₑ SUBSCRIPT E +silent! digr xs 8339 "U+2093=ₓ SUBSCRIPT X +silent! digr ls 8343 "U+2097=ₗ SUBSCRIPT L +silent! digr ms 8344 "U+2098=ₗ SUBSCRIPT M +silent! digr ns 8345 "U+2099=ₙ SUBSCRIPT N +silent! digr ps 8346 "U+209A=ₚ SUBSCRIPT P +silent! digr ss 8347 "U+209B=ₛ SUBSCRIPT S +silent! digr ts 8348 "U+209C=ₜ SUBSCRIPT T +silent! digr >< 8652 "U+21cc=⇌ EQUILIBRIUM +silent! digr o+ 8853 "U+2295=⊕ CIRCLED PLUS +silent! digr -^ 8593 "U+2191=↑ UPWARDS ARROW + +silent! digr -- 8212 "U+2014=— EM DASH + +silent! digr // 9585 "U+2571=╱ BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT +silent! digr \\ 9586 "U+2572=╲ BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + +silent! digr \|\| 8214 "U+2016=‖ DOUBLE VERTICAL LINE + +silent! digr ~~ 8967 "U+2307=⌇ WAVY LINE + +" }}} +" Convenience mappings ---------------------------------------------------- {{{ + +" Fuck you, help key. +noremap :checktime +inoremap :checktime + +" Stop it, hash key. +inoremap # X# + +" Kill window +nnoremap K :q + +" Save +nnoremap s :w + +" Man +nnoremap M K + +" Clean up windows +nnoremap - :wincmd = + +" Toggle line numbers +nnoremap n :setlocal number! + +" Sort lines +nnoremap s vip:sort +vnoremap s :sort + +" Tabs +nnoremap ( :tabprev +nnoremap ) :tabnext + +" My garbage brain can't ever remember digraph codes +inoremap :help digraph-table + +" Wrap +" mnemonic: less' -S command/option +nnoremap S :set wrap! + +" Inserting blank lines +" I never use the default behavior of and this saves me a keystroke... +nnoremap o + +" Delete to black hole register +nnoremap dD "_dd +vnoremap D "_d + +" Yank to end of line +nnoremap Y y$ + +" Reselect last-pasted text +nnoremap gv `[v`] + +" I constantly hit "u" in visual mode when I mean to "y". Use "gu" for those rare occasions. +" From https://github.com/henrik/dotfiles/blob/master/vim/config/mappings.vim +vnoremap u +vnoremap gu u + +" Clean trailing whitespace +nnoremap ww mz:%s/\s\+$//:let @/=''`z + +" Select entire buffer +nnoremap vaa ggvGg_ +nnoremap Vaa ggVG + +" Fix from spellcheck +" I can never remember if it's zg or z=, and the wrong one adds the word to +" the DB (lol), so fuck it, just add an easier mapping. +nnoremap zz z= +nnoremap z= :echo "use zz you idiot" + +" "Uppercase word" mapping. +" +" This mapping allows you to press in insert mode to convert the current +" word to uppercase. It's handy when you're writing names of constants and +" don't want to use Capslock. +" +" To use it you type the name of the constant in lowercase. While your +" cursor is at the end of the word, press to uppercase it, and then +" continue happily on your way: +" +" cursor +" v +" max_connections_allowed| +" +" MAX_CONNECTIONS_ALLOWED| +" ^ +" cursor +" +" It works by exiting out of insert mode, recording the current cursor location +" in the z mark, using gUiw to uppercase inside the current word, moving back to +" the z mark, and entering insert mode again. +" +" Note that this will overwrite the contents of the z mark. I never use it, but +" if you do you'll probably want to use another mark. +inoremap mzgUiw`za + +" Wrap Toggle +nnoremap :set nowrap! + +" zt is okay for putting something at the top of the screen, but when I'm +" writing prose I often want to put something at not-quite-the-top of the +" screen. zh is "zoom to head level" +nnoremap zh mzzt10`z + +" Diffoff +nnoremap D :diffoff! + +" Formatting, TextMate-style +nnoremap Q gqip +vnoremap Q gq + +" Reformat line. +" I never use l as a macro register anyway. +nnoremap ql gqq + +" Indent/dedent/autoindent what you just pasted. +nnoremap > V`]< +nnoremap > V`]> +nnoremap =- V`]= + +" Keep the cursor in place while joining lines +nnoremap J mzJ`z + +" Join an entire paragraph. +" +" Useful for writing GitHub comments in actual Markdown and then translating it +" to their bastardized version of Markdown. +nnoremap j mzvipJ`z + +" Split line (sister to [J]oin lines) +" The normal use of S is covered by cc, so don't worry about shadowing it. +nnoremap S i^mwgk:silent! s/\v +$//:noh`w + +" Substitute +nnoremap :%s/ +vnoremap :s/ + +" Marks and Quotes +noremap ' ` +noremap æ ' +noremap ` + +" Select (charwise) the contents of the current line, excluding indentation. +" Great for pasting Python lines into REPLs. +nnoremap vv ^vg_ + +" Typos +command! -bang E e +command! -bang Q q +command! -bang W w +command! -bang QA qa +command! -bang Qa qa +command! -bang Wa wa +command! -bang WA wa +command! -bang Wq wq +command! -bang WQ wq +command! -bang Wqa wqa + +" Unfuck my screen +nnoremap U :syntax sync fromstart:redraw! + +" Zip Right +" +" Moves the character under the cursor to the end of the line. Handy when you +" have something like: +" +" foo +" +" And you want to wrap it in a method call, so you type: +" +" println()foo +" +" Once you hit escape your cursor is on the closing paren, so you can 'zip' it +" over to the right with this mapping. +" +" This should preserve your last yank/delete as well. +nnoremap zl :let @z=@"x$p:let @"=@z + +" Diff Navigation +nnoremap ]d ]c +nnoremap [d [c + +" Typo navigation +nnoremap ]z ]S +nnoremap [z [S +nnoremap ]Z ]Sz= +nnoremap [Z [Sz= + +" Header Lines +nnoremap - o80a-kJ079lD + +" Insert Mode Completion +inoremap +inoremap +inoremap + +" Window Resizing +" right/up : bigger +" left/down : smaller +nnoremap :vertical resize +3 +nnoremap :vertical resize -3 +nnoremap :resize +3 +nnoremap :resize -3 + +" Newline without having to go to the end of the line +inoremap o + +" Spelling correct without having to exit insert mode +inoremap z= + +" }}} +" Searching and movement -------------------------------------------------- {{{ + +" Use sane regexes. +nnoremap / /\v +vnoremap / /\v + +set ignorecase +set smartcase +set incsearch +set showmatch +set hlsearch +set gdefault + +set scrolloff=5 +set sidescroll=1 +set sidescrolloff=10 + +set virtualedit+=block + +noremap :noh:call clearmatches() + +runtime macros/matchit.vim +map % +silent! unmap [% +silent! unmap ]% + +" Made D behave +nnoremap D d$ + +" Don't move on * +" I'd use a function for this but Vim clobbers the last search when you're in +" a function so fuck it, practicality beats purity. +nnoremap * :let stay_star_view = winsaveview()*:call winrestview(stay_star_view) + +" Jumping to tags. +" +" Basically, jumps to tags (like normal) and opens the tag in a new +" split instead. +" +" Both of them will align the destination line to the upper middle part of the +" screen. Both will pulse the cursor line so you can see where the hell you +" are. will also fold everything in the buffer and then unfold just +" enough for you to see the destination line. +" +function! JumpTo(jumpcommand) + execute a:jumpcommand + call FocusLine() + Pulse +endfunction +function! JumpToInSplit(jumpcommand) + execute "normal! \v" + execute a:jumpcommand + Pulse +endfunction + +function! JumpToTag() + call JumpTo("normal! \") +endfunction +function! JumpToTagInSplit() + call JumpToInSplit("normal \") +endfunction + +nnoremap :silent! call JumpToTag() +nnoremap :silent! call JumpToTagInSplit() + +" Keep search matches in the middle of the window. +nnoremap n nzzzv +nnoremap N Nzzzv + +" Same when jumping around +nnoremap g; g;zz +nnoremap g, g,zz +nnoremap zz + +" Easier to type, and I never use the default behavior. +noremap H ^ +noremap L $ +vnoremap L g_ + +" Heresy +inoremap I +inoremap A +cnoremap +cnoremap + +" go indent +nnoremap gi mzVap=`z +nnoremap gI mzgg=G`z + +" Fix linewise visual selection of various text objects +nnoremap VV V +nnoremap Vit vitVkoj +nnoremap Vat vatV +nnoremap Vab vabV +nnoremap VaB vaBV + + +" Directional Keys {{{ + +" It's 2013. +noremap j gj +noremap k gk +noremap gj j +noremap gk k + +" Easy buffer navigation +noremap h +noremap j +noremap k +noremap l + +noremap v v + +" }}} +" Visual Mode */# from Scrooloose {{{ + +function! s:VSetSearch() + let temp = @@ + norm! gvy + let @/ = '\V' . substitute(escape(@@, '\'), '\n', '\\n', 'g') + let @@ = temp +endfunction + +vnoremap * :call VSetSearch()// +vnoremap # :call VSetSearch()?? + +" }}} +" List navigation {{{ + +nnoremap :cprevzvzz +nnoremap :cnextzvzz +nnoremap :lprevzvzz +nnoremap :lnextzvzz + +" }}} + +" }}} +" Folding ----------------------------------------------------------------- {{{ + +set foldlevelstart=0 + +" Space to toggle folds. +nnoremap za +vnoremap za + +" Make zO recursively open whatever fold we're in, even if it's partially open. +nnoremap zO zczO + +" "Focus" the current line. Basically: +" +" 1. Close all folds. +" 2. Open just the folds containing the current line. +" 3. Move the line to a bit (25 lines) down from the top of the screen. +" 4. Pulse the line. +" +" This mapping wipes out the z mark, which I never use. +" +" I use :sus for the rare times I want to actually background Vim. +function! FocusLine() + let oldscrolloff = &scrolloff + set scrolloff=0 + execute "keepjumps normal! mzzMzvzt25\`z:Pulse\" + let &scrolloff = oldscrolloff +endfunction +nnoremap :call FocusLine() + +function! MyFoldText() " {{{ + let line = getline(v:foldstart) + + let nucolwidth = &fdc + &number * &numberwidth + let windowwidth = winwidth(0) - nucolwidth - 3 + let foldedlinecount = v:foldend - v:foldstart + + " expand tabs into spaces + let onetab = strpart(' ', 0, &tabstop) + let line = substitute(line, '\t', onetab, 'g') + + let line = strpart(line, 0, windowwidth - 2 -len(foldedlinecount)) + let fillcharcount = windowwidth - len(line) - len(foldedlinecount) + return line . '…' . repeat(" ",fillcharcount) . foldedlinecount . '…' . ' ' +endfunction " }}} +set foldtext=MyFoldText() + +" }}} +" Text objects ------------------------------------------------------------ {{{ + +" Folds {{{ + +onoremap if :normal! [zv]z +onoremap af :normal! [zV]z +vnoremap if :normal! ]zv[z +vnoremap af :normal! ]zV[z + +" }}} +" Shortcut for [] {{{ + +onoremap ir i[ +onoremap ar a[ +vnoremap ir i[ +vnoremap ar a[ + +" }}} +" Numbers {{{ + +" Motion for numbers. Great for CSS. Lets you do things like this: +" +" margin-top: 200px; -> daN -> margin-top: px; +" ^ ^ +" TODO: Handle floats. + +onoremap N :call NumberTextObject(0) +xnoremap N :call NumberTextObject(0) +onoremap aN :call NumberTextObject(1) +xnoremap aN :call NumberTextObject(1) +onoremap iN :call NumberTextObject(1) +xnoremap iN :call NumberTextObject(1) + +function! s:NumberTextObject(whole) + let num = '\v[0-9]' + + " If the current char isn't a number, walk forward. + while getline('.')[col('.') - 1] !~# num + normal! l + endwhile + + " Now that we're on a number, start selecting it. + normal! v + + " If the char after the cursor is a number, select it. + while getline('.')[col('.')] =~# num + normal! l + endwhile + + " If we want an entire word, flip the select point and walk. + if a:whole + normal! o + + while col('.') > 1 && getline('.')[col('.') - 2] =~# num + normal! h + endwhile + endif +endfunction + +" }}} + +" }}} +" Optional Remote-Local Vimrc --------------------------------------------- {{{ + +if filereadable(expand('~/.vimrc_remote_local')) + source ~/.vimrc_remote_local +endif + +" }}} diff -r 93d27886c099 -r 62e329839625 weechat-old/.agignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/.agignore Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,2 @@ +logs/ +urls.log diff -r 93d27886c099 -r 62e329839625 weechat-old/GandiStandardSSLCA.crt Binary file weechat-old/GandiStandardSSLCA.crt has changed diff -r 93d27886c099 -r 62e329839625 weechat-old/alias.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/alias.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,45 @@ +# +# weechat -- alias.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[cmd] +AAWAY = "allserv /away" +AME = "allchan /me" +AMSG = "allchan /msg *" +ANICK = "allserv /nick" +b = "/buffer" +BYE = "quit" +C = "buffer clear" +CHAT = "dcc chat" +CL = "buffer clear" +CLOSE = "buffer close" +EXIT = "quit" +IG = "ignore" +J = "join" +K = "kick" +KB = "kickban" +LEAVE = "part" +M = "msg" +MUB = "unban *" +N = "names" +Q = "query" +REDRAW = "window refresh" +SAY = "msg *" +SIGNOFF = "quit" +T = "topic" +UB = "unban" +V = "command core version" +W = "who" +WC = "window merge" +WI = "whois" +WII = "whois $1 $1" +WW = "whowas" + +[completion] diff -r 93d27886c099 -r 62e329839625 weechat-old/aspell.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/aspell.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,33 @@ +# +# weechat -- aspell.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[color] +misspelled = lightred +suggestion = default +suggestion_delimiter_dict = cyan +suggestion_delimiter_word = cyan + +[check] +commands = "ame,amsg,away,command,cycle,kick,kickban,me,msg,notice,part,query,quit,topic" +default_dict = "en" +during_search = off +enabled = off +real_time = off +suggestions = -1 +word_min_length = 2 + +[dict] + +[look] +suggestion_delimiter_dict = " / " +suggestion_delimiter_word = "," + +[option] diff -r 93d27886c099 -r 62e329839625 weechat-old/autosort.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/autosort.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,24 @@ +# +# weechat -- autosort.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[sorting] +case_sensitive = off +debug_log = off +replacements = "[]" +rules = "[["core", 0], ["irc", 2], ["*", 1], ["irc.irc_raw", 0], ["irc.server", 1]]" +signal_delay = 5 +signals = "buffer_opened buffer_merged buffer_unmerged buffer_renamed" +sort_limit = 100 +sort_on_config_change = on + +[v3] +helpers = "{"core_first": "${if:${buffer.full_name}!=core.weechat}", "irc_raw_first": "${if:${buffer.full_name}!=irc.irc_raw}", "irc_raw_last": "${if:${buffer.full_name}==irc.irc_raw}", "hashless_name": "${info:autosort_replace,#,,${info:autosort_escape,${buffer.name}}}", "script_or_plugin": "${if:${script_name}?${script_name}:${plugin}}"}" +rules = "["${core_first}", "${info:autosort_order,${info:autosort_escape,${script_or_plugin}},core,*,irc,bitlbee,matrix,slack}", "${script_or_plugin}", "${irc_raw_first}", "${server}", "${info:autosort_order,${type},server,*,channel,private}", "${hashless_name}", "${buffer.full_name}"]" diff -r 93d27886c099 -r 62e329839625 weechat-old/buffers.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/buffers.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,77 @@ +# +# weechat -- buffers.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[color] +current_bg = green +current_fg = black +default_bg = default +default_fg = default +hotlist_highlight_bg = default +hotlist_highlight_fg = *magenta +hotlist_low_bg = default +hotlist_low_fg = white +hotlist_message_bg = default +hotlist_message_fg = green +hotlist_private_bg = default +hotlist_private_fg = *magenta +none_channel_bg = default +none_channel_fg = 240 +number = green +number_char = green +prefix_bufname = default +queries_default_bg = default +queries_default_fg = default +queries_highlight_bg = default +queries_highlight_fg = default +queries_message_bg = default +queries_message_fg = default +suffix_bufname = default +whitelist_default_bg = default +whitelist_default_fg = default +whitelist_highlight_bg = default +whitelist_highlight_fg = default +whitelist_low_bg = default +whitelist_low_fg = default +whitelist_message_bg = default +whitelist_message_fg = default +whitelist_private_bg = default +whitelist_private_fg = default + +[look] +core_to_front = off +detach = 0 +detach_buffer_immediately = "" +detach_display_window_number = off +detach_displayed_buffers = on +detach_free_content = off +detach_query = off +hide_merged_buffers = none +hotlist_counter = off +immune_detach_buffers = "" +indenting = on +indenting_number = on +jump_prev_next_visited_buffer = off +mark_inactive = off +mouse_move_buffer = on +name_crop_suffix = "+" +name_size_max = 0 +number_char = " " +prefix = off +prefix_bufname = "" +prefix_empty = on +prefix_for_query = "" +short_names = on +show_lag = off +show_number = on +sort = number +suffix_bufname = "" +toogle_bar = on +whitelist_buffers = "" diff -r 93d27886c099 -r 62e329839625 weechat-old/buflist.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/buflist.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,41 @@ +# +# weechat -- buflist.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[look] +add_newline = on +auto_scroll = 50 +display_conditions = "${buffer.hidden}==0" +enabled = on +mouse_jump_visited_buffer = off +mouse_move_buffer = on +mouse_wheel = on +nick_prefix = off +nick_prefix_empty = on +signals_refresh = "" +sort = "number,-active" +use_items = 1 + +[format] +buffer = "${format_number}${indent}${format_nick_prefix}${color_hotlist}${format_name}" +buffer_current = "${color:,blue}${format_buffer}" +hotlist = " ${color:green}(${hotlist}${color:green})" +hotlist_highlight = "${color:magenta}" +hotlist_low = "${color:white}" +hotlist_message = "${color:green}" +hotlist_none = "${color:default}" +hotlist_private = "${color:magenta}" +hotlist_separator = "${color:default}," +indent = " " +lag = " ${color:green}[${color:brown}${lag}${color:green}]" +name = "${name}" +nick_prefix = "${color_nick_prefix}${nick_prefix}" +number = "${color:green}${number}${if:${number_displayed}?.: }" +tls_version = " ${color:default}(${if:${tls_version}==TLS1.3?${color:green}:${if:${tls_version}==TLS1.2?${color:yellow}:${color:red}}}${translate:${tls_version}}${color:default})" diff -r 93d27886c099 -r 62e329839625 weechat-old/charset.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/charset.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,18 @@ +# +# weechat -- charset.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[default] +decode = "iso-8859-1" +encode = "" + +[decode] + +[encode] diff -r 93d27886c099 -r 62e329839625 weechat-old/exec.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/exec.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,19 @@ +# +# weechat -- exec.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[command] +default_options = "" +purge_delay = 0 +shell = "${env:SHELL}" + +[color] +flag_finished = lightred +flag_running = lightgreen diff -r 93d27886c099 -r 62e329839625 weechat-old/fifo.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/fifo.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,14 @@ +# +# weechat -- fifo.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[file] +enabled = on +path = "%h/weechat_fifo" diff -r 93d27886c099 -r 62e329839625 weechat-old/fset.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/fset.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,96 @@ +# +# weechat -- fset.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[look] +auto_refresh = "*" +auto_unmark = off +condition_catch_set = "${count} >= 1" +export_help_default = on +format_number = 1 +marked_string = "*" +scroll_horizontal = 10 +show_plugins_desc = off +sort = "~name" +unmarked_string = " " +use_color_value = off +use_keys = on +use_mute = off + +[format] +export_help = "# ${description2}" +export_option = "/set ${name} ${quoted_value}" +export_option_null = "/unset ${name}" +option1 = "" +option2 = "${marked} ${name} ${type} ${value2}${newline} ${empty_name} ${_default_value}${color:darkgray} -- ${min}..${max}${newline} ${empty_name} ${description}" + +[color] +default_value = default +default_value_selected = white +description = default +description_selected = white +file = default +file_changed = brown +file_changed_selected = yellow +file_selected = white +help_default_value = white +help_description = default +help_name = white +help_quotes = darkgray +help_values = default +index = cyan +index_selected = lightcyan +line_marked_bg1 = default +line_marked_bg2 = default +line_selected_bg1 = blue +line_selected_bg2 = red +marked = brown +marked_selected = yellow +max = default +max_selected = white +min = default +min_selected = white +name = default +name_changed = brown +name_changed_selected = yellow +name_selected = white +option = default +option_changed = brown +option_changed_selected = yellow +option_selected = white +parent_name = default +parent_name_selected = white +parent_value = cyan +parent_value_selected = lightcyan +quotes = darkgray +quotes_changed = default +quotes_changed_selected = white +quotes_selected = default +section = default +section_changed = brown +section_changed_selected = yellow +section_selected = white +string_values = default +string_values_selected = white +title_count_options = cyan +title_current_option = lightcyan +title_filter = yellow +title_marked_options = lightgreen +title_sort = white +type = green +type_selected = lightgreen +unmarked = default +unmarked_selected = white +value = cyan +value_changed = brown +value_changed_selected = yellow +value_selected = lightcyan +value_undef = magenta +value_undef_selected = lightmagenta diff -r 93d27886c099 -r 62e329839625 weechat-old/icon.png Binary file weechat-old/icon.png has changed diff -r 93d27886c099 -r 62e329839625 weechat-old/logger.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/logger.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,36 @@ +# +# weechat -- logger.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[look] +backlog = 20 +backlog_conditions = "" + +[color] +backlog_end = darkgray +backlog_line = darkgray + +[file] +auto_log = on +color_lines = off +flush_delay = 120 +fsync = off +info_lines = off +mask = "$plugin.$name.weechatlog" +name_lower_case = on +nick_prefix = " <" +nick_suffix = "> " +path = "%h/logs/" +replacement_char = "_" +time_format = "%Y-%m-%d %H:%M:%S" + +[level] + +[mask] diff -r 93d27886c099 -r 62e329839625 weechat-old/lua.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/lua.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,14 @@ +# +# weechat -- lua.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +check_license = off +eval_keep_context = on diff -r 93d27886c099 -r 62e329839625 weechat-old/perl.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/perl.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,14 @@ +# +# weechat -- perl.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +check_license = off +eval_keep_context = on diff -r 93d27886c099 -r 62e329839625 weechat-old/perl/autoload/colorize_lines.pl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/perl/autoload/colorize_lines.pl Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,251 @@ +# +# Copyright (c) 2010-2013 by Nils Görs +# Copyleft (ɔ) 2013 by oakkitten +# +# colors the channel text with nick color and also highlight the whole line +# colorize_nicks.py script will be supported +# +# 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 . +# +# with version 3.0 some options were renamed or have new possible values: +# old: new: +# avail_buffer buffer +# blacklist_channels blacklist_buffers +# highlight new values + +# obsolete options: +# buffer_autoset +# hotlist_max_level_nicks_add +# highlight_regex +# highlight_words +# shuffle +# chat see option highlight + +# history: +# 3.0: large part of script rewritten +# fix: works nicely with irc colors +# improved: highlight_regex and highlight_words work in a natural way +# removed: command /colorize_lines +# removed: option shuffle +# 2.2: fix: regex with [tab] in message (patch by sqrrl) +# 2.1: fix: changing highlight color did not apply messages already displayed (reported by rafi_) +# 2.0: fix: debugging weechat::print() removed (thanks demure) +# 1.9: fix: display bug with nick_mode +# 1.8 add: option "use_irc_colors" (requested by Zertap) +# fix: empty char for nick_mode was used, even when "irc.look.nick_mode_empty" was OFF (reported by FlashCode) +# 1.7: fix: broken lines in dcc chat (reported by equatorping) +# 1.6: improved: wildcard "*" can be used for server and/or nick. (requested by ldvx) +# : add: new value, "only", for option "own_lines" (read help!) +# 1.5: sync: option weechat.look.nickmode changed in 0.3.9 to "irc.look.nick_mode" +# 1.4: fix: whole ctcp message was display in prefix (reported by : Mkaysi) +# 1.3: fix: now using weechat::buffer_get_string() instead of regex to prevent problems with dots inside server-/channelnames (reported by surfhai) +# 1.2: add: hook_modifier("colorize_lines") to use colorize_lines with another script. +# : fix: regex was too greedy and also hit tag "prefix_nick_ccc" +# 1.1: fix: problems with temporary server (reported by nand`) +# : improved: using weechat_string_has_highlight() +# 1.0: fix: irc.look.nick_prefix wasn't supported +# 0.9: added: option "own_nick" (idea by travkin) +# : new value (always) for option highlight +# : clean up code +# 0.8.1: fix: regex() +# 0.8: added: option "avail_buffer" and "nicks" (please read help-page) (suggested by ldvx) +# : fix: blacklist_buffers wasn't load at start +# : fix: nick_modes wasn't displayed since v0.7 +# : rewrote init() routine +# : thanks to stfn for hint with unescaped variables in regex. +# 0.7: fix: bug when irc.look.nick_suffix was set (reported and beta-testing by: hw2) (>= weechat 0.3.4) +# blacklist_buffers option supports servername +# clean up code +# 0.6: code optimazations. +# rename of script (rainbow_text.pl -> colorize_lines.pl) (suggested by xt and flashcode) +# 0.5: support of hotlist_max_level_nicks_add and weechat.color.chat_nick_colors (>= weechat 0.3.4) +# 0.4: support of weechat.look.highlight_regex option (>= weechat 0.3.4) +# : support of weechat.look.highlight option +# : highlighted line did not work with "." inside servername +# ; internal "autoset" function fixed +# 0.3: support of colorize_nicks.py implemented. +# : /me text displayed wrong nick colour (colour from suffix was used) +# : highlight messages will be checked case insensitiv +# 0.2: supports highlight_words_add from buffer_autoset.py script (suggested: Emralegna) +# : correct look_nickmode colour will be used (bug reported by: Emralegna) +# : /me text will be coloured, too +# 0.1: initial release +# +# Development is currently hosted at +# https://github.com/weechatter/weechat-scripts + +# use Data::Dumper +# $Data::Dumper::Useqq=1; + +use strict; +my $prgname = "colorize_lines"; +my $version = "3.0"; +my $description = "colors text in chat area with according nick color, including highlights"; + +my %config = ("buffers" => "all", # all, channel, query + "blacklist_buffers" => "", # "a,b,c" + "lines" => "on", + "highlight" => "on", # on, off, nicks + "nicks" => "", # "d,e,f", "/file" + "own_lines" => "on", # on, off, only +); + +my %help_desc = ("buffers" => "buffer type affected by the script (all/channel/query, default: all)", + "blacklist_buffers" => "comma-separated list of channels to be ignored (e.g. freenode.#weechat,*.#python)", + "lines" => "apply nickname color to the non-highlighted lines (off/on/nicks). the latter will limit highlighting to nicknames in option 'nicks'", + "highlight" => "apply highlight color to the highlighted lines (off/on/nicks). the latter will limit highlighting to nicknames in option 'nicks'", + "nicks" => "comma-separater list of nicks (e.g. freenode.cat,*.dog) OR file name starting with '/' (e.g. /file.txt). in the latter case, nicknames will get loaded from that file inside weechat folder (e.g. from ~/.weechat/file.txt). nicknames in file are newline-separated (e.g. freenode.dog\\n*.cat)", + "own_lines" => "apply nickname color to own lines (off/on/only). the latter turns off all other kinds of coloring altogether", +); + +#################################################################################################### config + +# program starts here +sub colorize_cb { + my ( $data, $modifier, $modifier_data, $string ) = @_; + + # quit if it's not a privmsg or ctcp + # or we are not supposed to + if ((index($modifier_data,"irc_privmsg") == -1) || + (index($modifier_data,"irc_ctcp") >= 0)) { + return $string; + } + + # find buffer pointer + $modifier_data =~ m/([^;]*);([^;]*);/; + my $buffer = weechat::buffer_search($1, $2); + return $string if ($buffer eq ""); + + # find buffer name, server name + # return if buffer is in a blacklist + my $buffername = weechat::buffer_get_string($buffer, "name"); + return $string if weechat::string_has_highlight($buffername, $config{blacklist_buffers}); + my $servername = weechat::buffer_get_string($buffer, "localvar_server"); + + # find stuff between \t + $string =~ m/^([^\t]*)\t(.*)/; + my $left = $1; + my $right = $2; + + # find nick of the sender + # find out if we are doing an action + my $nick = ($modifier_data =~ m/(^|,)nick_([^,]*)/) ? $2 : weechat::string_remove_color($left, ""); + my $action = ($modifier_data =~ m/\birc_action\b/) ? 1 : 0; + + ######################################## get color + + my $color = ""; + my $my_nick = weechat::buffer_get_string($buffer, "localvar_nick"); + if ($my_nick eq $nick) { + # it's our own line + # process only if own_lines is "on" or "only" (i.e. not "off") + return $string if ($config{own_lines} eq "off"); + $color = weechat::color("chat_nick_self"); + } else { + # it's someone else's line + # don't process is own_lines are "only" + # in order to get correct matching, remove colors from the string + return $string if ($config{own_lines} eq "only"); + my $right_nocolor = weechat::string_remove_color($right, ""); + if (weechat::string_has_highlight($right_nocolor, weechat::buffer_string_replace_local_var($buffer, weechat::buffer_get_string($buffer, "highlight_words"))) || + weechat::string_has_highlight($right_nocolor, weechat::config_string(weechat::config_get("weechat.look.highlight"))) || + weechat::string_has_highlight_regex($right_nocolor, weechat::config_string(weechat::config_get("weechat.look.highlight_regex"))) || + weechat::string_has_highlight_regex($right_nocolor, weechat::buffer_get_string($buffer, "highlight_regex")) + ) { + # we have a hilight! get a hilight color + # and replace the first occurance of coloring, that'd be nick color + # process only if highlight is "on" OR "nicks" & nick's in nicks + return $string if ($config{highlight} eq "off" || + ($config{highlight} eq "nicks" && !weechat::string_has_highlight("$servername.$nick", $config{nicks}))); + $color = weechat::color('chat_highlight'); + $right =~ s/\31[^\31 ]+?\Q$nick/$color$nick/ if ($action); + } else { + # that's not a highlight + # process only if lines is "on" OR "nicks" & nick's in nicks + return $string if ($config{lines} eq "off" || + ($config{lines} eq "nicks" && !weechat::string_has_highlight("$servername.$nick", $config{nicks}))); + $color = weechat::info_get('irc_nick_color', $nick); + } + } + + ######################################## inject colors and go! + + my $out = ""; + if ($action) { + # remove the first color reset - after * nick + # make other resets reset to our color + $right =~ s/\34//; + $right =~ s/\34/\34$color/g; + $out = $left . "\t" . $right . "\34" + } else { + # make other resets reset to our color + $right =~ s/\34/\34$color/g; + $out = $left . "\t" . $color . $right . "\34" + } + #weechat::print("", ""); weechat::print("", "\$str " . Dumper($string)); weechat::print("", "\$out " . Dumper($out)); + return $out; +} + +#################################################################################################### config + +# read nicknames if $conf{nisks} starts with / +# after this, $conf{nisks} is of form a,b,c,d +# if it doesnt start with /, assume it's already a,b,c,d +sub nicklist_read { + return if (substr($config{nicks}, 0, 1) ne "/"); + my $file = weechat::info_get("weechat_dir", "") . $config{nicks}; + return unless -e $file; + my $nili = ""; + open (WL, "<", $file) || DEBUG("$file: $!"); + while () { + chomp; # kill LF + $nili .= $_ . ","; + } + close WL; + chop $nili; # remove last "," + $config{nicks} = $nili; +} + +# called when a config option ha been changed +# $name = plugins.var.perl.$prgname.nicks etc +sub toggle_config_by_set { + my ($pointer, $name, $value) = @_; + $name = substr($name,length("plugins.var.perl.$prgname."),length($name)); + $config{$name} = lc($value); + nicklist_read() if ($name eq "nicks"); +} + +# read configuration from weechat OR +# set default options and +# set dectription if weechat >= 0.3.5 +# after done, read nicklist from file if needed +sub init_config { + my $weechat_version = weechat::info_get('version_number', '') || 0; + foreach my $option (keys %config){ + if (!weechat::config_is_set_plugin($option)) { + weechat::config_set_plugin($option, $config{$option}); + weechat::config_set_desc_plugin($option, $help_desc{$option}) if ($weechat_version >= 0x00030500); # v0.3.5 + } else { + $config{$option} = lc(weechat::config_get_plugin($option)); + } + } + nicklist_read(); +} + +#################################################################################################### start + +weechat::register($prgname, "Nils Görs ", $version, "GPL3", $description, "", ""); +weechat::hook_modifier("500|weechat_print","colorize_cb", ""); +init_config(); +weechat::hook_config("plugins.var.perl.$prgname.*", "toggle_config_by_set", ""); diff -r 93d27886c099 -r 62e329839625 weechat-old/python.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,14 @@ +# +# weechat -- python.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[look] +check_license = off +eval_keep_context = on diff -r 93d27886c099 -r 62e329839625 weechat-old/python/autoload/autosort.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python/autoload/autosort.py Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +../autosort.py \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 weechat-old/python/autoload/brows.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python/autoload/brows.py Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,77 @@ +import subprocess +import os + +SCRIPT_NAME = 'brows' +SCRIPT_AUTHOR = 'Steve Losh ' +SCRIPT_VERSION = '1.0' +SCRIPT_LICENSE = 'MIT/X11' +SCRIPT_DESC = 'Launch brows to view URLs' +SCRIPT_COMMAND = 'brows' + +import_ok = True + +BROWS = os.environ.get('BROWS', 'brows') + +try: + import weechat +except ImportError: + print('This is a weechat script, what are you doing, run it in weechat, jesus') + import_ok = False + +weechat_version = 0 + +def hd(fn, name, obj, attr): + return fn(weechat.hdata_get(name), obj, attr) + +def hdp(name, obj, attr): + return hd(weechat.hdata_pointer, name, obj, attr) + +def hds(name, obj, attr): + return hd(weechat.hdata_string, name, obj, attr) + +def get_lines(buffer, numlines): + lines = hdp("buffer", buffer, "own_lines") + if not lines: + # null pointer wat do + return None + + last_lines = [] + + line = hdp("lines", lines, "last_line") + for _ in range(numlines): + if not line: + # shit we're at the top of the buffer + break + + data = hdp("line", line, "data") + msg = hds("line_data", data, "message") + msg = weechat.string_remove_color(msg, "") + + last_lines.append(msg.strip()) + + line = hdp("line", line, "prev_line") + + return last_lines + +def brows(data, buffer, args, numlines=100): + lines = get_lines(buffer, numlines) + + proc = subprocess.Popen([BROWS], stdin=subprocess.PIPE) + proc.communicate(input='\n'.join(lines)) + weechat.command("", "/window refresh") + + return weechat.WEECHAT_RC_OK + + +if __name__ == '__main__' and import_ok: + if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, + SCRIPT_LICENSE, SCRIPT_DESC, '', ''): + weechat_version = weechat.info_get('version_number', '') or 0 + weechat.hook_command( + SCRIPT_COMMAND, + 'Launch brows to view URLs', + '', + '', + '', + 'brows', + '') diff -r 93d27886c099 -r 62e329839625 weechat-old/python/autoload/editor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python/autoload/editor.py Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,65 @@ +import subprocess +import os +import tempfile + +SCRIPT_NAME = 'editor' +SCRIPT_AUTHOR = 'Steve Losh ' +SCRIPT_VERSION = '1.0' +SCRIPT_LICENSE = 'MIT/X11' +SCRIPT_DESC = 'Launch an external editor to compose a message' +SCRIPT_COMMAND = 'editor' + +import_ok = True + +EDITOR = os.environ.get('EDITOR','vim') + +try: + import weechat +except ImportError: + print('This is a weechat script, what are you doing, run it in weechat, jesus') + import_ok = False + +weechat_version = 0 + + +def get_data(suffix, initial_data): + with tempfile.NamedTemporaryFile(suffix=".%s" % suffix, mode="w+") as tf: + tf.write(initial_data) + tf.flush() + + if subprocess.call([EDITOR, tf.name]) != 0: + return None + + # Reopen, because most editors do atomic write-tmp+rename saves which + # fucks with Python here. + tf.file.close() + with open(tf.name) as tf2: + return tf2.read() + +def editor(data, buffer, args): + suffix = args or "tmp" + + line = weechat.buffer_get_string(buffer, "input") + + data = get_data(suffix, line) + if data: + weechat.command(buffer, "/input delete_line") + weechat.command(buffer, data.strip()) + + weechat.command("", "/window refresh") + + return weechat.WEECHAT_RC_OK + + +if __name__ == '__main__' and import_ok: + if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, + SCRIPT_LICENSE, SCRIPT_DESC, '', ''): + weechat_version = weechat.info_get('version_number', '') or 0 + weechat.hook_command( + SCRIPT_COMMAND, + 'Open $EDITOR to compose a message', + '[file-extension]', + 'If an argument is given, it will be used as the extension for the temporary file.', + '', + 'editor', + '') diff -r 93d27886c099 -r 62e329839625 weechat-old/python/autoload/notify.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python/autoload/notify.py Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,29 @@ +import weechat, subprocess + +SCRIPT_NAME = 'notify' +SCRIPT_AUTHOR = 'Steve Losh ' +SCRIPT_VERSION = '0.0.1' +SCRIPT_LICENSE = 'MIT' +SCRIPT_DESC = 'notify-send for weechat' + +weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, '', '') + +weechat.hook_print('', 'irc_privmsg', '', 1, 'notify', '') + +def _notify(text): + subprocess.call(['notify-send', text]) + +def notify(data, buffer, date, tags, displayed, highlight, prefix, message): + # ignore if it's yourself + own_nick = weechat.buffer_get_string(buffer, 'localvar_nick') + + if prefix == own_nick or prefix == ('@%s' % own_nick): + return weechat.WEECHAT_RC_OK + + if int(highlight): + channel = weechat.buffer_get_string(buffer, 'localvar_channel') + _notify('%s %s\n%s' % (prefix, channel, message)) + elif 'notify_private' in tags: + _notify('%s [PM]\n%s' % (prefix, message)) + + return weechat.WEECHAT_RC_OK diff -r 93d27886c099 -r 62e329839625 weechat-old/python/autoload/quotes.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python/autoload/quotes.py Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,124 @@ +import subprocess, os + +SCRIPT_NAME = 'quotes' +SCRIPT_AUTHOR = 'Steve Losh ' +SCRIPT_VERSION = '1.0' +SCRIPT_LICENSE = 'MIT/X11' +SCRIPT_DESC = 'Grab quotes and shove them into a text file.' +SCRIPT_COMMAND = 'quo' +SCRIPT_COMMAND_LONG = 'quoo' +SCRIPT_COMMAND_COPY = 'cop' + +HOME = os.getenv("HOME") +QUOTE_FILE = '%s/Dropbox/quotes.txt' % HOME +COPY_FILE = '%s/.ircopy.irc' % HOME + +import_ok = True + +try: + import weechat +except ImportError: + print('This is a weechat script, what are you doing, run it in weechat, jesus') + import_ok = False + +weechat_version = 0 + +def hd(fn, name, obj, attr): + return fn(weechat.hdata_get(name), obj, attr) + +def hdp(name, obj, attr): + return hd(weechat.hdata_pointer, name, obj, attr) + +def hds(name, obj, attr): + return hd(weechat.hdata_string, name, obj, attr) + +def get_lines(buffer, numlines): + lines = hdp("buffer", buffer, "own_lines") + if not lines: + # null pointer wat do + return None + + last_lines = [] + + line = hdp("lines", lines, "last_line") + for _ in range(numlines): + if not line: + # shit we're at the top of the buffer + break + + data = hdp("line", line, "data") + msg = hds("line_data", data, "message") + pre = hds("line_data", data, "prefix") + + msg = weechat.string_remove_color(msg, "") + pre = weechat.string_remove_color(pre, "") + + last_lines.append("<%s> %s" % (pre.strip(), msg.strip())) + + line = hdp("line", line, "prev_line") + + last_lines.reverse() + return last_lines + +def quote_grab(data, buffer, args, numlines=15): + lines = get_lines(buffer, numlines) + + with open(QUOTE_FILE, 'a') as f: + f.write("\n---\n") + f.write('\n'.join(lines)) + + subprocess.call(["nvim", QUOTE_FILE, + # start at the bottom of the file + "+", + # move up N lines, where N is how many we appended + "-c", "normal! %dk" % len(lines)]) + weechat.command("", "/window refresh") + + return weechat.WEECHAT_RC_OK + +def quote_grab_long(data, buffer, args): + return quote_grab(data, buffer, args, 75) + +def quote_grab_copy(data, buffer, args): + lines = get_lines(buffer, 1000) + + with open(COPY_FILE, 'w') as f: + f.write('\n'.join(lines)) + + subprocess.call(["nvim", COPY_FILE, + # start at the bottom of the file + "+"]) + weechat.command("", "/window refresh") + + return weechat.WEECHAT_RC_OK + +if __name__ == '__main__' and import_ok: + if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, + SCRIPT_LICENSE, SCRIPT_DESC, '', ''): + weechat_version = weechat.info_get('version_number', '') or 0 + weechat.hook_command( + SCRIPT_COMMAND, + 'Appends the last 15 lines of the current buffer to your quotes ' + 'file and opens it in Vim so you can trim it.', + '', + '', + '', + 'quote_grab', + '') + weechat.hook_command( + SCRIPT_COMMAND_LONG, + 'Appends the last 75 lines of the current buffer to your quotes ' + 'file and opens it in Vim so you can trim it.', + '', + '', + '', + 'quote_grab_long', + '') + weechat.hook_command( + SCRIPT_COMMAND_COPY, + 'Open the last 1000 lines of the file in Vim so you can copy.', + '', + '', + '', + 'quote_grab_copy', + '') diff -r 93d27886c099 -r 62e329839625 weechat-old/python/autoload/urlgrab.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python/autoload/urlgrab.py Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,699 @@ +# -*- coding: utf-8 -*- +# +# UrlGrab, for weechat version >= 0.3.0 +# +# Listens to all channels for URLs, collects them in a list, and launches +# them in your favourite web server on the local host or a remote server. +# Copies url to X11 clipboard via xsel +# (http://www.vergenet.net/~conrad/software/xsel) +# +# Usage: +# +# The /url command provides access to all UrlGrab functions. Run +# '/help url' for complete command usage. +# +# In general, use '/url list' to list the entire url list for the current +# channel, and '/url ' to launch the nth url in the list. For +# example, to launch the first (and most-recently added) url in the list, +# you would run '/url 1' +# +# From the server window, you must specify a specific channel for the +# list and launch commands, for example: +# /url list weechat +# /url 3 weechat +# +# Configuration: +# +# The '/url set' command lets you get and set the following options: +# +# historysize +# The maximum number of URLs saved per channel. Default is 10 +# +# method +# Must be one of 'local' or 'remote' - Defines how URLs are launched by +# the script. If 'local', the script will run 'localcmd' on the host. +# If 'remote', the script will run 'remotessh remotehost remotecmd' on +# the local host which should normally use ssh to connect to another +# host and run the browser command there. +# +# localcmd +# The command to run on the local host to launch URLs in 'local' mode. +# The string '%s' will be replaced with the URL. The default is +# 'firefox %s'. +# +# remotessh +# The command (and arguments) used to connect to the remote host for +# 'remote' mode. The default is 'ssh -x' which will connect as the +# current username via ssh and disable X11 forwarding. +# +# remotehost +# The remote host to which we will connect in 'remote' mode. For ssh, +# this can just be a hostname or 'user@host' to specify a username +# other than your current login name. The default is 'localhost'. +# +# remotecmd +# The command to execute on the remote host for 'remote' mode. The +# default is 'bash -c "DISPLAY=:0.0 firefox '%s'"' Which runs bash, sets +# up the environment to display on the remote host's main X display, +# and runs firefox. As with 'localcmd', the string '%s' will be +# replaced with the URL. +# +# cmdoutput +# The file where the command output (if any) is saved. Overwritten +# each time you launch a new URL. Default is ~/.weechat/urllaunch.log +# +# default +# The command that will be run if no arguemnts to /url are given. +# Default is show +# +# Requirements: +# +# - Designed to run with weechat version 0.3 or better. +# http://www.weechat.org/ +# +# Acknowlegements: +# +# - Based on an earlier version called 'urlcollector.py' by 'kolter' of +# irc.freenode.net/#weechat Honestly, I just cleaned up the code a bit and +# made the settings a little more useful (to me). +# +# - With changes by Leonid Evdokimov (weechat at darkk dot net another dot ru): +# http://darkk.net.ru/weechat/urlgrab.py +# v1.1: added better handling of dead zombie-childs +# added parsing of private messages +# added default command setting +# added parsing of scrollback buffers on load +# v1.2: `historysize` was ignored +# +# - With changes by ExclusivE (exclusive_tm at mail dot ru): +# v1.3: X11 clipboard support +# +# - V1.4 Just ported it over to weechat 0.2.7 drubin AT smartcube dot co dot za +# - V1.5 1) I created a logging feature for urls, Time, Date, buffer, and url. +# 2) Added selectable urls support, similar to the iset plugin (Thanks FlashCode) +# 3) Colors/formats are configuarable. +# 4) browser now uses hook_process (Please test with remote clients) +# 5) Added /url open http://url.com functionality +# 6) Changed urls detection to use regexpressions so should be much better +# Thanks to xt of #weechat bassed on on urlbar.py +# - V1.6 FlashCode : Increase timeout for hook_process +# (from 1 second to 1 minute) +# - V1.7 FlashCode : Update WeeChat site +# - V1.8 drubin : +# - Changed remote cmd to be single option +# - Added scrolling on up and down arrow keys for /url show +# - Changed remotecmd to include options with public/private keys password auth doesn't work +# - V1.9 Specimen : +# - Changed the default command when /url is run with no arguments to 'show' +# - Removed '/url help' command, because /help is the standard way +# - V2.0 Xilov: replace "/url help" by "/help url" +# - V2.1 nand: Changed default: firefox %s to firefox '%s' (localcmd) +# - V2.2 Sébastien Helleu : fix reload of config file +# - V2.3 nand: Allowed trailing )s for unmatched (s in URLs +# - V2.4 nand: Escaped URLs via URL-encoding instead of shell escaping, fixes ' +# - V2.5 nand: Fixed some URLs that got incorrectly mangled by escaping +# - V2.6 nesthib: Fixed escaping of "=" +# Added missing quotes in default parameter (firefox '%s') +# Removed the mix of tabs and spaces in the file indentation +# - V2.7 dobbymoodge +# ( https://github.com/dobbymoodge/ ): +# - Added 'copycmd' setting, users can set command to pipe into +# for '/url copy' +# - V2.8 Simmo Saan : +# - Changed print hook to ignore filtered lines +# - V2.9 Dominik Heidler : +# - Updated script for python3 support (now python2 and 3 are both supported) +# - V3.0 Sébastien Helleu : +# - Fix python 3 compatibility (replace "has_key" by "in") +# +# Copyright (C) 2005 David Rubin +# +# 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 2 +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +# USA. +# + +from __future__ import print_function +import sys +import os +try: + import weechat + import_ok = True +except: + print("This script must be run under WeeChat.") + print("Get WeeChat now at: http://www.weechat.org/") + import_ok = False +import subprocess +import time +try: + from urllib import quote +except ImportError: + from urllib.parse import quote +import re +try: + from UserDict import UserDict +except ImportError: + from collections import UserDict + + +octet = r'(?:2(?:[0-4]\d|5[0-5])|1\d\d|\d{1,2})' +ipAddr = r'%s(?:\.%s){3}' % (octet, octet) +# Base domain regex off RFC 1034 and 1738 +label = r'[0-9a-z][-0-9a-z]*[0-9a-z]?' +domain = r'%s(?:\.%s)*\.[a-z][-0-9a-z]*[a-z]?' % (label, label) +urlRe = re.compile(r'(\w+://(?:%s|%s)(?::\d+)?(?:/[^\]>\s]*)?)' % (domain, ipAddr), re.I) + + +SCRIPT_NAME = "urlgrab" +SCRIPT_AUTHOR = "David Rubin " +SCRIPT_VERSION = "3.0" +SCRIPT_LICENSE = "GPL" +SCRIPT_DESC = "Url functionality Loggin, opening of browser, selectable links" +CONFIG_FILE_NAME= "urlgrab" +SCRIPT_COMMAND = "url" + + +def stripParens(url): + return dropChar(')', url.count(')') - url.count('('), url[::-1])[::-1] + +def dropChar(c, n, xs): + if n == 0 or xs == []: + return xs + elif xs[0] == c: + return dropChar(c, n-1, xs[1:]) + else: + return xs + +def urlGrabPrint(message): + bufferd=weechat.current_buffer() + if urlGrabSettings['output_main_buffer'] == 1 : + weechat.prnt("","[%s] %s" % ( SCRIPT_NAME, message ) ) + else : + weechat.prnt(bufferd,"[%s] %s" % ( SCRIPT_NAME, message ) ) + +def hashBufferName(bufferp): + if not weechat.buffer_get_string(bufferp, "short_name"): + bufferd = weechat.buffer_get_string(bufferp, "name") + else: + bufferd = weechat.buffer_get_string(bufferp, "short_name") + return bufferd + +def ug_config_reload_cb(data, config_file): + """ Reload configuration file. """ + return weechat.config_reload(config_file) + +class UrlGrabSettings(UserDict): + def __init__(self): + UserDict.__init__(self) + self.data = {} + self.config_file = weechat.config_new(CONFIG_FILE_NAME, + "ug_config_reload_cb", "") + if not self.config_file: + return + + section_color = weechat.config_new_section( + self.config_file, "color", 0, 0, "", "", "", "", "", "", + "", "", "", "") + section_default = weechat.config_new_section( + self.config_file, "default", 0, 0, "", "", "", "", "", "", + "", "", "", "") + + self.data['color_buffer']=weechat.config_new_option( + self.config_file, section_color, + "color_buffer", "color", "Color to display buffer name", "", 0, 0, + "red", "red", 0, "", "", "", "", "", "") + + self.data['color_url']=weechat.config_new_option( + self.config_file, section_color, + "color_url", "color", "Color to display urls", "", 0, 0, + "blue", "blue", 0, "", "", "", "", "", "") + + self.data['color_time']=weechat.config_new_option( + self.config_file, section_color, + "color_time", "color", "Color to display time", "", 0, 0, + "cyan", "cyan", 0, "", "", "", "", "", "") + + self.data['color_buffer_selected']=weechat.config_new_option( + self.config_file, section_color, + "color_buffer_selected", "color", + "Color to display buffer selected name", "", 0, 0, "red", "red", + 0, "", "", "", "", "", "") + + self.data['color_url_selected']=weechat.config_new_option( + self.config_file, section_color, + "color_url_selected", "color", "Color to display url selected", + "", 0, 0, "blue", "blue", 0, "", "", "", "", "", "") + + self.data['color_time_selected']=weechat.config_new_option( + self.config_file, section_color, + "color_time_selected", "color", "Color to display tim selected", + "", 0, 0, "cyan", "cyan", 0, "", "", "", "", "", "") + + self.data['color_bg_selected']=weechat.config_new_option( + self.config_file, section_color, + "color_bg_selected", "color", "Background for selected row", "", 0, 0, + "green", "green", 0, "", "", "", "", "", "") + + self.data['historysize']=weechat.config_new_option( + self.config_file, section_default, + "historysize", "integer", "Max number of urls to store per buffer", + "", 0, 999, "10", "10", 0, "", "", "", "", "", "") + + self.data['method']=weechat.config_new_option( + self.config_file, section_default, + "method", "string", """Where to launch URLs + If 'local', runs %localcmd%. + If 'remote' runs the following command: + '%remodecmd%'""", "", 0, 0, + "local", "local", 0, "", "", "", "", "", "") + + self.data['copycmd']=weechat.config_new_option( + self.config_file, section_default, + "copycmd", "string", + "Command to pipe into for 'url copy'. " + "E.g. to copy into the CLIPBOARD buffer " + "instead of PRIMARY, you can use 'xsel -b " + "-i' here.", "", 0, 0, + "xsel -i", "xsel -i", 0, "", "", "", "", "", "") + + self.data['localcmd']=weechat.config_new_option( + self.config_file, section_default, + "localcmd", "string", """Local command to execute""", "", 0, 0, + "firefox '%s'", "firefox '%s'", 0, "", "", "", "", "", "") + + remotecmd="ssh -x localhost -i ~/.ssh/id_rsa -C \"export DISPLAY=\":0.0\" && firefox '%s'\"" + self.data['remotecmd']=weechat.config_new_option( + self.config_file, section_default, + "remotecmd", "string", remotecmd, "", 0, 0, + remotecmd, remotecmd, 0, "", "", "", "", "", "") + + self.data['url_log']=weechat.config_new_option( + self.config_file, section_default, + "url_log", "string", """log location""", "", 0, 0, + "~/.weechat/urls.log", "~/.weechat/urls.log", 0, "", "", "", "", "", "") + + self.data['time_format']=weechat.config_new_option( + self.config_file, section_default, + "time_format", "string", """TIme format""", "", 0, 0, + "%H:%M:%S", "%H:%M:%S", 0, "", "", "", "", "", "") + + self.data['output_main_buffer']=weechat.config_new_option( + self.config_file, section_default, + "output_main_buffer", "boolean", + """Print text to main buffer or current one""", "", 0, 0, "1", "1", + 0, "", "", "", "", "", "") + weechat.config_read(self.config_file) + + def __getitem__(self, key): + if key == "historysize": + return weechat.config_integer(self.data[key]) + elif key == 'output_main_buffer': + return weechat.config_boolean(self.data[key]) + #elif key.startswith('color'): + # return weechat.config_color(self.data[key]) + else: + return weechat.config_string(self.data[key]) + + def prnt(self, name, verbose = True): + weechat.prnt( ""," %s = %s" % (name.ljust(11), self.data[name]) ) + + def prntall(self): + for key in self.names(): + self.prnt(key, verbose = False) + + def createCmd(self, url): + str ="" + if self['method'] == 'remote': + str = self['remotecmd'] % url + else: + str = self['localcmd'] % url + return str + +class UrlGrabber: + def __init__(self, historysize): + # init + self.urls = {} + self.globalUrls = [] + self.historysize = 5 + # control + self.setHistorysize(historysize) + + def setHistorysize(self, count): + if count > 1: + self.historysize = count + + def getHistorysize(self): + return self.historysize + + def addUrl(self, bufferp,url ): + global urlGrabSettings + self.globalUrls.insert(0,{"buffer":bufferp, + "url":url, "time":time.strftime(urlGrabSettings["time_format"])}) + #Log urls only if we have set a log path. + if urlGrabSettings['url_log']: + try : + index = self.globalUrls[0] + logfile = os.path.expanduser(urlGrabSettings['url_log']) + dout = open(logfile, "a") + dout.write("%s %s %s\n" % (index['time'], + index['buffer'], index['url'])) + dout.close() + except : + print("failed to log url check that %s is valid path" % urlGrabSettings['url_log']) + pass + + # check for buffer + if not bufferp in self.urls: + self.urls[bufferp] = [] + # add url + if url in self.urls[bufferp]: + self.urls[bufferp].remove(url) + self.urls[bufferp].insert(0, url) + # removing old urls + while len(self.urls[bufferp]) > self.historysize: + self.urls[bufferp].pop() + + def hasIndex( self, bufferp, index ): + return bufferp in self.urls and \ + len(self.url[bufferp]) >= index + + def hasBuffer( self, bufferp ): + return bufferp in self.urls + + + def getUrl(self, bufferp, index): + url = "" + if bufferp in self.urls: + if len(self.urls[bufferp]) >= index: + url = self.urls[bufferp][index-1] + return url + + + def prnt(self, buff): + found = True + if buff in self.urls: + if len(self.urls[buff]) > 0: + i = 1 + for url in self.urls[buff]: + urlGrabPrint("--> " + str(i) + " : " + url) + i += 1 + else: + found = False + elif buff == "*": + for b in self.urls.keys(): + self.prnt(b) + else: + found = False + + if not found: + urlGrabPrint(buff + ": no entries") + +def urlGrabCheckMsgline(bufferp, message, isdisplayed): + global urlGrab, max_buffer_length + if not message or isdisplayed == 0: + return + # Ignore output from 'tinyurl.py' and our selfs + if ( message.startswith( "[AKA] http://tinyurl.com" ) or + message.startswith("[urlgrab]") ): + return + # Check for URLs + for url in urlRe.findall(message): + urlGrab.addUrl(bufferp,stripParens(url)) + if max_buffer_length < len(bufferp): + max_buffer_length = len(bufferp) + if urlgrab_buffer: + refresh() + + +def urlGrabCheck(data, bufferp, uber_empty, tagsn, isdisplayed, ishilight, prefix, message): + urlGrabCheckMsgline(hashBufferName(bufferp), message, isdisplayed) + return weechat.WEECHAT_RC_OK + +def urlGrabCopy(bufferd, index): + global urlGrab + if bufferd == "": + urlGrabPrint( "No current channel, you must activate one" ) + elif not urlGrab.hasBuffer(bufferd): + urlGrabPrint("No URL found - Invalid channel") + else: + if index <= 0: + urlGrabPrint("No URL found - Invalid index") + return + url = urlGrab.getUrl(bufferd,index) + if url == "": + urlGrabPrint("No URL found - Invalid index") + else: + try: + pipe = os.popen(urlGrabSettings['copycmd'],"w") + pipe.write(url) + pipe.close() + urlGrabPrint("Url: %s gone to clipboard." % url) + except: + urlGrabPrint("Url: %s failed to copy to clipboard." % url) + +def urlGrabOpenUrl(url): + global urlGrab, urlGrabSettings + argl = urlGrabSettings.createCmd( quote(url, '/:#%?&+=') ) + weechat.hook_process(argl,60000, "ug_open_cb", "") + +def ug_open_cb(data, command, code, out, err): + # weechat.prnt("", out) + # weechat.prnt("", err) + return weechat.WEECHAT_RC_OK + + +def urlGrabOpen(bufferd, index): + global urlGrab, urlGrabSettings + if bufferd == "": + urlGrabPrint( "No current channel, you must specify one" ) + elif not urlGrab.hasBuffer(bufferd) : + urlGrabPrint("No URL found - Invalid channel") + else: + if index <= 0: + urlGrabPrint("No URL found - Invalid index") + return + url = urlGrab.getUrl(bufferd,index) + if url == "": + urlGrabPrint("No URL found - Invalid index") + else: + urlGrabPrint("loading %s %sly" % (url, urlGrabSettings["method"])) + urlGrabOpenUrl (url) + +def urlGrabList( args ): + global urlGrab + if len(args) == 0: + buf = hashBufferName(weechat.current_buffer()) + else: + buf = args[0] + if buf == "" or buf == "all": + buf = "*" + urlGrab.prnt(buf) + + +def urlGrabMain(data, bufferp, args): + if args[0:2] == "**": + keyEvent(data, bufferp, args[2:]) + return weechat.WEECHAT_RC_OK + + bufferd = hashBufferName(bufferp) + largs = args.split(" ") + #strip spaces + while '' in largs: + largs.remove('') + while ' ' in largs: + largs.remove(' ') + if len(largs) == 0 or largs[0] == "show": + if not urlgrab_buffer: + init() + refresh() + weechat.buffer_set(urlgrab_buffer, "display", "1") + elif largs[0] == 'open' and len(largs) == 2: + urlGrabOpenUrl(largs[1]) + elif largs[0] == 'list': + urlGrabList( largs[1:] ) + elif largs[0] == 'copy': + if len(largs) > 1: + no = int(largs[1]) + urlGrabCopy(bufferd, no) + else: + urlGrabCopy(bufferd,1) + else: + try: + no = int(largs[0]) + if len(largs) > 1: + urlGrabOpen(largs[1], no) + else: + urlGrabOpen(bufferd, no) + except ValueError: + #not a valid number so try opening it as a url.. + for url in urlRe.findall(largs[0]): + urlGrabOpenUrl(stripParens(url)) + urlGrabPrint( "Unknown command '%s'. Try '/help url' for usage" % largs[0]) + return weechat.WEECHAT_RC_OK + +def buffer_input(*kwargs): + return weechat.WEECHAT_RC_OK + +def buffer_close(*kwargs): + global urlgrab_buffer + urlgrab_buffer = None + return weechat.WEECHAT_RC_OK + +def keyEvent (data, bufferp, args): + global urlGrab , urlGrabSettings, urlgrab_buffer, current_line + if args == "refresh": + refresh() + elif args == "up": + if current_line > 0: + current_line = current_line -1 + refresh_line (current_line + 1) + refresh_line (current_line) + ugCheckLineOutsideWindow() + elif args == "down": + if current_line < len(urlGrab.globalUrls) - 1: + current_line = current_line +1 + refresh_line (current_line - 1) + refresh_line (current_line) + ugCheckLineOutsideWindow() + elif args == "scroll_top": + temp_current = current_line + current_line = 0 + refresh_line (temp_current) + refresh_line (current_line) + weechat.command(urlgrab_buffer, "/window scroll_top") + pass + elif args == "scroll_bottom": + temp_current = current_line + current_line = len(urlGrab.globalUrls) + refresh_line (temp_current) + refresh_line (current_line) + weechat.command(urlgrab_buffer, "/window scroll_bottom") + elif args == "enter": + if urlGrab.globalUrls[current_line]: + urlGrabOpenUrl (urlGrab.globalUrls[current_line]['url']) + +def refresh_line (y): + global urlGrab , urlGrabSettings, urlgrab_buffer, current_line, max_buffer_length + #Print format Time(space)buffer(max4 spaces, but lined up)url + format = "%%s%%s %%s%%-%ds%%s%%s" % (max_buffer_length+4) + + #non selected colors + color_buffer = urlGrabSettings["color_buffer"] + color_url = urlGrabSettings["color_url"] + color_time =urlGrabSettings["color_time"] + #selected colors + color_buffer_selected = urlGrabSettings["color_buffer_selected"] + color_url_selected = urlGrabSettings["color_url_selected"] + color_time_selected = urlGrabSettings["color_time_selected"] + + color_bg_selected = urlGrabSettings["color_bg_selected"] + + color1 = color_time + color2 = color_buffer + color3 = color_url + + #If this line is selected we change the colors. + if y == current_line: + color1 = "%s,%s" % (color_time_selected, color_bg_selected) + color2 = "%s,%s" % (color_buffer_selected, color_bg_selected) + color3 = "%s,%s" % (color_url_selected, color_bg_selected) + + color1 = weechat.color(color1) + color2 = weechat.color(color2) + color3 = weechat.color(color3) + text = format % (color1, + urlGrab.globalUrls[y]['time'], + color2, + urlGrab.globalUrls[y]['buffer'], + color3, + urlGrab.globalUrls[y]['url'] ) + weechat.prnt_y(urlgrab_buffer,y,text) + +def ugCheckLineOutsideWindow(): + global urlGrab , urlGrabSettings, urlgrab_buffer, current_line, max_buffer_length + if (urlgrab_buffer): + infolist = weechat.infolist_get("window", "", "current") + if (weechat.infolist_next(infolist)): + start_line_y = weechat.infolist_integer(infolist, "start_line_y") + chat_height = weechat.infolist_integer(infolist, "chat_height") + if(start_line_y > current_line): + weechat.command(urlgrab_buffer, "/window scroll -%i" %(start_line_y - current_line)) + elif(start_line_y <= current_line - chat_height): + weechat.command(urlgrab_buffer, "/window scroll +%i"%(current_line - start_line_y - chat_height + 1)) + weechat.infolist_free(infolist) + + +def refresh(): + global urlGrab + y=0 + for x in urlGrab.globalUrls: + refresh_line (y) + y += 1 + + +def init(): + global urlGrab , urlGrabSettings, urlgrab_buffer + if not urlgrab_buffer: + urlgrab_buffer = weechat.buffer_new("urlgrab", "buffer_input", "", "buffer_close", "") + if urlgrab_buffer: + weechat.buffer_set(urlgrab_buffer, "type", "free") + weechat.buffer_set(urlgrab_buffer, "key_bind_ctrl-R", "/url **refresh") + weechat.buffer_set(urlgrab_buffer, "key_bind_meta2-A", "/url **up") + weechat.buffer_set(urlgrab_buffer, "key_bind_meta2-B", "/url **down") + weechat.buffer_set(urlgrab_buffer, "key_bind_meta-ctrl-J", "/url **enter") + weechat.buffer_set(urlgrab_buffer, "key_bind_meta-ctrl-M", "/url **enter") + weechat.buffer_set(urlgrab_buffer, "key_bind_meta-meta2-1./~", "/url **scroll_top") + weechat.buffer_set(urlgrab_buffer, "key_bind_meta-meta2-4~", "/url **scroll_bottom") + weechat.buffer_set(urlgrab_buffer, "title","Lists the urls in the applications") + weechat.buffer_set(urlgrab_buffer, "display", "1") + +def completion_urls_cb(data, completion_item, bufferp, completion): + """ Complete with URLS, for command '/url'. """ + global urlGrab + bufferd = hashBufferName( bufferp) + for url in urlGrab.globalUrls : + if url['buffer'] == bufferd: + weechat.hook_completion_list_add(completion, url['url'], 0, weechat.WEECHAT_LIST_POS_SORT) + return weechat.WEECHAT_RC_OK + +def ug_unload_script(): + """ Function called when script is unloaded. """ + global urlGrabSettings + weechat.config_write(urlGrabSettings.config_file) + return weechat.WEECHAT_RC_OK + +#Main stuff +if ( import_ok and + weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, + SCRIPT_LICENSE,SCRIPT_DESC, "ug_unload_script", "") ): + urlgrab_buffer = None + current_line = 0 + max_buffer_length = 0 + urlGrabSettings = UrlGrabSettings() + urlGrab = UrlGrabber( urlGrabSettings['historysize']) + weechat.hook_print("", "", "", 1, "urlGrabCheck", "") + weechat.hook_command(SCRIPT_COMMAND, + "Url Grabber", + "[open | | show | copy [n] | [n] | list]", + "open or : opens the url\n" + "show: Opens the select buffer to allow for url selection\n" + "copy: Copies the nth url to the system clipboard\n" + "list: Lists the urls in the current buffer\n", + "open %(urlgrab_urls) || %(urlgrab_urls) || " + "copy || show || list", + "urlGrabMain", "") + weechat.hook_completion("urlgrab_urls", "list of URLs", + "completion_urls_cb", "") +else: + print("failed to load weechat") diff -r 93d27886c099 -r 62e329839625 weechat-old/python/autoload/wee_slack.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python/autoload/wee_slack.py Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1 @@ +/home/sjl/src/wee-slack/wee_slack.py \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 weechat-old/python/autosort.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python/autosort.py Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,1075 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013-2017 Maarten de Vries +# +# 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 . +# + +# +# Autosort automatically keeps your buffers sorted and grouped by server. +# You can define your own sorting rules. See /help autosort for more details. +# +# https://github.com/de-vri-es/weechat-autosort +# + +# +# Changelog: +# 3.9: +# * Remove `buffers.pl` from recommended settings. +# 3,8: +# * Fix relative sorting on script name in default rules. +# * Document a useful property of stable sort algorithms. +# 3.7: +# * Make default rules work with bitlbee, matrix and slack. +# 3.6: +# * Add more documentation on provided info hooks. +# 3.5: +# * Add ${info:autosort_escape,...} to escape arguments for other info hooks. +# 3.4: +# * Fix rate-limit of sorting to prevent high CPU load and lock-ups. +# * Fix bug in parsing empty arguments for info hooks. +# * Add debug_log option to aid with debugging. +# * Correct a few typos. +# 3.3: +# * Fix the /autosort debug command for unicode. +# * Update the default rules to work better with Slack. +# 3.2: +# * Fix python3 compatiblity. +# 3.1: +# * Use colors to format the help text. +# 3.0: +# * Switch to evaluated expressions for sorting. +# * Add `/autosort debug` command. +# * Add ${info:autosort_replace,from,to,text} to replace substrings in sort rules. +# * Add ${info:autosort_order,value,first,second,third} to ease writing sort rules. +# * Make tab completion context aware. +# 2.8: +# * Fix compatibility with python 3 regarding unicode handling. +# 2.7: +# * Fix sorting of buffers with spaces in their name. +# 2.6: +# * Ignore case in rules when doing case insensitive sorting. +# 2.5: +# * Fix handling unicode buffer names. +# * Add hint to set irc.look.server_buffer to independent and buffers.look.indenting to on. +# 2.4: +# * Make script python3 compatible. +# 2.3: +# * Fix sorting items without score last (regressed in 2.2). +# 2.2: +# * Add configuration option for signals that trigger a sort. +# * Add command to manually trigger a sort (/autosort sort). +# * Add replacement patterns to apply before sorting. +# 2.1: +# * Fix some minor style issues. +# 2.0: +# * Allow for custom sort rules. +# + + +import json +import math +import re +import sys +import time +import weechat + +SCRIPT_NAME = 'autosort' +SCRIPT_AUTHOR = 'Maarten de Vries ' +SCRIPT_VERSION = '3.9' +SCRIPT_LICENSE = 'GPL3' +SCRIPT_DESC = 'Flexible automatic (or manual) buffer sorting based on eval expressions.' + + +config = None +hooks = [] +signal_delay_timer = None +sort_limit_timer = None +sort_queued = False + + +# Make sure that unicode, bytes and str are always available in python2 and 3. +# For python 2, str == bytes +# For python 3, str == unicode +if sys.version_info[0] >= 3: + unicode = str + +def ensure_str(input): + ''' + Make sure the given type if the correct string type for the current python version. + That means bytes for python2 and unicode for python3. + ''' + if not isinstance(input, str): + if isinstance(input, bytes): + return input.encode('utf-8') + if isinstance(input, unicode): + return input.decode('utf-8') + return input + + +if hasattr(time, 'perf_counter'): + perf_counter = time.perf_counter +else: + perf_counter = time.clock + +def casefold(string): + if hasattr(string, 'casefold'): return string.casefold() + # Fall back to lowercasing for python2. + return string.lower() + +def list_swap(values, a, b): + values[a], values[b] = values[b], values[a] + +def list_move(values, old_index, new_index): + values.insert(new_index, values.pop(old_index)) + +def list_find(collection, value): + for i, elem in enumerate(collection): + if elem == value: return i + return None + +class HumanReadableError(Exception): + pass + +def parse_int(arg, arg_name = 'argument'): + ''' Parse an integer and provide a more human readable error. ''' + arg = arg.strip() + try: + return int(arg) + except ValueError: + raise HumanReadableError('Invalid {0}: expected integer, got "{1}".'.format(arg_name, arg)) + +def decode_rules(blob): + parsed = json.loads(blob) + if not isinstance(parsed, list): + log('Malformed rules, expected a JSON encoded list of strings, but got a {0}. No rules have been loaded. Please fix the setting manually.'.format(type(parsed))) + return [] + + for i, entry in enumerate(parsed): + if not isinstance(entry, (str, unicode)): + log('Rule #{0} is not a string but a {1}. No rules have been loaded. Please fix the setting manually.'.format(i, type(entry))) + return [] + + return parsed + +def decode_helpers(blob): + parsed = json.loads(blob) + if not isinstance(parsed, dict): + log('Malformed helpers, expected a JSON encoded dictionary but got a {0}. No helpers have been loaded. Please fix the setting manually.'.format(type(parsed))) + return {} + + for key, value in parsed.items(): + if not isinstance(value, (str, unicode)): + log('Helper "{0}" is not a string but a {1}. No helpers have been loaded. Please fix setting manually.'.format(key, type(value))) + return {} + return parsed + +class Config: + ''' The autosort configuration. ''' + + default_rules = json.dumps([ + '${core_first}', + '${info:autosort_order,${info:autosort_escape,${script_or_plugin}},core,*,irc,bitlbee,matrix,slack}', + '${script_or_plugin}', + '${irc_raw_first}', + '${server}', + '${info:autosort_order,${type},server,*,channel,private}', + '${hashless_name}', + '${buffer.full_name}', + ]) + + default_helpers = json.dumps({ + 'core_first': '${if:${buffer.full_name}!=core.weechat}', + 'irc_raw_first': '${if:${buffer.full_name}!=irc.irc_raw}', + 'irc_raw_last': '${if:${buffer.full_name}==irc.irc_raw}', + 'hashless_name': '${info:autosort_replace,#,,${info:autosort_escape,${buffer.name}}}', + 'script_or_plugin': '${if:${script_name}?${script_name}:${plugin}}', + }) + + default_signal_delay = 5 + default_sort_limit = 100 + + default_signals = 'buffer_opened buffer_merged buffer_unmerged buffer_renamed' + + def __init__(self, filename): + ''' Initialize the configuration. ''' + + self.filename = filename + self.config_file = weechat.config_new(self.filename, '', '') + self.sorting_section = None + self.v3_section = None + + self.case_sensitive = False + self.rules = [] + self.helpers = {} + self.signals = [] + self.signal_delay = Config.default_signal_delay, + self.sort_limit = Config.default_sort_limit, + self.sort_on_config = True + self.debug_log = False + + self.__case_sensitive = None + self.__rules = None + self.__helpers = None + self.__signals = None + self.__signal_delay = None + self.__sort_limit = None + self.__sort_on_config = None + self.__debug_log = None + + if not self.config_file: + log('Failed to initialize configuration file "{0}".'.format(self.filename)) + return + + self.sorting_section = weechat.config_new_section(self.config_file, 'sorting', False, False, '', '', '', '', '', '', '', '', '', '') + self.v3_section = weechat.config_new_section(self.config_file, 'v3', False, False, '', '', '', '', '', '', '', '', '', '') + + if not self.sorting_section: + log('Failed to initialize section "sorting" of configuration file.') + weechat.config_free(self.config_file) + return + + self.__case_sensitive = weechat.config_new_option( + self.config_file, self.sorting_section, + 'case_sensitive', 'boolean', + 'If this option is on, sorting is case sensitive.', + '', 0, 0, 'off', 'off', 0, + '', '', '', '', '', '' + ) + + weechat.config_new_option( + self.config_file, self.sorting_section, + 'rules', 'string', + 'Sort rules used by autosort v2.x and below. Not used by autosort anymore.', + '', 0, 0, '', '', 0, + '', '', '', '', '', '' + ) + + weechat.config_new_option( + self.config_file, self.sorting_section, + 'replacements', 'string', + 'Replacement patterns used by autosort v2.x and below. Not used by autosort anymore.', + '', 0, 0, '', '', 0, + '', '', '', '', '', '' + ) + + self.__rules = weechat.config_new_option( + self.config_file, self.v3_section, + 'rules', 'string', + 'An ordered list of sorting rules encoded as JSON. See /help autosort for commands to manipulate these rules.', + '', 0, 0, Config.default_rules, Config.default_rules, 0, + '', '', '', '', '', '' + ) + + self.__helpers = weechat.config_new_option( + self.config_file, self.v3_section, + 'helpers', 'string', + 'A dictionary helper variables to use in the sorting rules, encoded as JSON. See /help autosort for commands to manipulate these helpers.', + '', 0, 0, Config.default_helpers, Config.default_helpers, 0, + '', '', '', '', '', '' + ) + + self.__signals = weechat.config_new_option( + self.config_file, self.sorting_section, + 'signals', 'string', + 'A space separated list of signals that will cause autosort to resort your buffer list.', + '', 0, 0, Config.default_signals, Config.default_signals, 0, + '', '', '', '', '', '' + ) + + self.__signal_delay = weechat.config_new_option( + self.config_file, self.sorting_section, + 'signal_delay', 'integer', + 'Delay in milliseconds to wait after a signal before sorting the buffer list. This prevents triggering many times if multiple signals arrive in a short time. It can also be needed to wait for buffer localvars to be available.', + '', 0, 1000, str(Config.default_signal_delay), str(Config.default_signal_delay), 0, + '', '', '', '', '', '' + ) + + self.__sort_limit = weechat.config_new_option( + self.config_file, self.sorting_section, + 'sort_limit', 'integer', + 'Minimum delay in milliseconds to wait after sorting before signals can trigger a sort again. This is effectively a rate limit on sorting. Keeping signal_delay low while setting this higher can reduce excessive sorting without a long initial delay.', + '', 0, 1000, str(Config.default_sort_limit), str(Config.default_sort_limit), 0, + '', '', '', '', '', '' + ) + + self.__sort_on_config = weechat.config_new_option( + self.config_file, self.sorting_section, + 'sort_on_config_change', 'boolean', + 'Decides if the buffer list should be sorted when autosort configuration changes.', + '', 0, 0, 'on', 'on', 0, + '', '', '', '', '', '' + ) + + self.__debug_log = weechat.config_new_option( + self.config_file, self.sorting_section, + 'debug_log', 'boolean', + 'If enabled, print more debug messages. Not recommended for normal usage.', + '', 0, 0, 'off', 'off', 0, + '', '', '', '', '', '' + ) + + if weechat.config_read(self.config_file) != weechat.WEECHAT_RC_OK: + log('Failed to load configuration file.') + + if weechat.config_write(self.config_file) != weechat.WEECHAT_RC_OK: + log('Failed to write configuration file.') + + self.reload() + + def reload(self): + ''' Load configuration variables. ''' + + self.case_sensitive = weechat.config_boolean(self.__case_sensitive) + + rules_blob = weechat.config_string(self.__rules) + helpers_blob = weechat.config_string(self.__helpers) + signals_blob = weechat.config_string(self.__signals) + + self.rules = decode_rules(rules_blob) + self.helpers = decode_helpers(helpers_blob) + self.signals = signals_blob.split() + self.signal_delay = weechat.config_integer(self.__signal_delay) + self.sort_limit = weechat.config_integer(self.__sort_limit) + self.sort_on_config = weechat.config_boolean(self.__sort_on_config) + self.debug_log = weechat.config_boolean(self.__debug_log) + + def save_rules(self, run_callback = True): + ''' Save the current rules to the configuration. ''' + weechat.config_option_set(self.__rules, json.dumps(self.rules), run_callback) + + def save_helpers(self, run_callback = True): + ''' Save the current helpers to the configuration. ''' + weechat.config_option_set(self.__helpers, json.dumps(self.helpers), run_callback) + + +def pad(sequence, length, padding = None): + ''' Pad a list until is has a certain length. ''' + return sequence + [padding] * max(0, (length - len(sequence))) + +def log(message, buffer = 'NULL'): + weechat.prnt(buffer, 'autosort: {0}'.format(message)) + +def debug(message, buffer = 'NULL'): + if config.debug_log: + weechat.prnt(buffer, 'autosort: debug: {0}'.format(message)) + +def get_buffers(): + ''' Get a list of all the buffers in weechat. ''' + hdata = weechat.hdata_get('buffer') + buffer = weechat.hdata_get_list(hdata, "gui_buffers"); + + result = [] + while buffer: + number = weechat.hdata_integer(hdata, buffer, 'number') + result.append((number, buffer)) + buffer = weechat.hdata_pointer(hdata, buffer, 'next_buffer') + return hdata, result + +class MergedBuffers(list): + """ A list of merged buffers, possibly of size 1. """ + def __init__(self, number): + super(MergedBuffers, self).__init__() + self.number = number + +def merge_buffer_list(buffers): + ''' + Group merged buffers together. + The output is a list of MergedBuffers. + ''' + if not buffers: return [] + result = {} + for number, buffer in buffers: + if number not in result: result[number] = MergedBuffers(number) + result[number].append(buffer) + return result.values() + +def sort_buffers(hdata, buffers, rules, helpers, case_sensitive): + for merged in buffers: + for buffer in merged: + name = weechat.hdata_string(hdata, buffer, 'name') + + return sorted(buffers, key=merged_sort_key(rules, helpers, case_sensitive)) + +def buffer_sort_key(rules, helpers, case_sensitive): + ''' Create a sort key function for a list of lists of merged buffers. ''' + def key(buffer): + extra_vars = {} + for helper_name, helper in sorted(helpers.items()): + expanded = weechat.string_eval_expression(helper, {"buffer": buffer}, {}, {}) + extra_vars[helper_name] = expanded if case_sensitive else casefold(expanded) + result = [] + for rule in rules: + expanded = weechat.string_eval_expression(rule, {"buffer": buffer}, extra_vars, {}) + result.append(expanded if case_sensitive else casefold(expanded)) + return result + + return key + +def merged_sort_key(rules, helpers, case_sensitive): + buffer_key = buffer_sort_key(rules, helpers, case_sensitive) + def key(merged): + best = None + for buffer in merged: + this = buffer_key(buffer) + if best is None or this < best: best = this + return best + return key + +def apply_buffer_order(buffers): + ''' Sort the buffers in weechat according to the given order. ''' + for i, buffer in enumerate(buffers): + weechat.buffer_set(buffer[0], "number", str(i + 1)) + +def split_args(args, expected, optional = 0): + ''' Split an argument string in the desired number of arguments. ''' + split = args.split(' ', expected - 1) + if (len(split) < expected): + raise HumanReadableError('Expected at least {0} arguments, got {1}.'.format(expected, len(split))) + return split[:-1] + pad(split[-1].split(' ', optional), optional + 1, '') + +def do_sort(verbose = False): + start = perf_counter() + + hdata, buffers = get_buffers() + buffers = merge_buffer_list(buffers) + buffers = sort_buffers(hdata, buffers, config.rules, config.helpers, config.case_sensitive) + apply_buffer_order(buffers) + + elapsed = perf_counter() - start + if verbose: + log("Finished sorting buffers in {0:.4f} seconds.".format(elapsed)) + else: + debug("Finished sorting buffers in {0:.4f} seconds.".format(elapsed)) + +def command_sort(buffer, command, args): + ''' Sort the buffers and print a confirmation. ''' + do_sort(True) + return weechat.WEECHAT_RC_OK + +def command_debug(buffer, command, args): + hdata, buffers = get_buffers() + buffers = merge_buffer_list(buffers) + + # Show evaluation results. + log('Individual evaluation results:') + start = perf_counter() + key = buffer_sort_key(config.rules, config.helpers, config.case_sensitive) + results = [] + for merged in buffers: + for buffer in merged: + fullname = weechat.hdata_string(hdata, buffer, 'full_name') + results.append((fullname, key(buffer))) + elapsed = perf_counter() - start + + for fullname, result in results: + fullname = ensure_str(fullname) + result = [ensure_str(x) for x in result] + log('{0}: {1}'.format(fullname, result)) + log('Computing evaluation results took {0:.4f} seconds.'.format(elapsed)) + + return weechat.WEECHAT_RC_OK + +def command_rule_list(buffer, command, args): + ''' Show the list of sorting rules. ''' + output = 'Sorting rules:\n' + for i, rule in enumerate(config.rules): + output += ' {0}: {1}\n'.format(i, rule) + if not len(config.rules): + output += ' No sorting rules configured.\n' + log(output ) + + return weechat.WEECHAT_RC_OK + + +def command_rule_add(buffer, command, args): + ''' Add a rule to the rule list. ''' + config.rules.append(args) + config.save_rules() + command_rule_list(buffer, command, '') + + return weechat.WEECHAT_RC_OK + + +def command_rule_insert(buffer, command, args): + ''' Insert a rule at the desired position in the rule list. ''' + index, rule = split_args(args, 2) + index = parse_int(index, 'index') + + config.rules.insert(index, rule) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_update(buffer, command, args): + ''' Update a rule in the rule list. ''' + index, rule = split_args(args, 2) + index = parse_int(index, 'index') + + config.rules[index] = rule + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_delete(buffer, command, args): + ''' Delete a rule from the rule list. ''' + index = args.strip() + index = parse_int(index, 'index') + + config.rules.pop(index) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_move(buffer, command, args): + ''' Move a rule to a new position. ''' + index_a, index_b = split_args(args, 2) + index_a = parse_int(index_a, 'index') + index_b = parse_int(index_b, 'index') + + list_move(config.rules, index_a, index_b) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_rule_swap(buffer, command, args): + ''' Swap two rules. ''' + index_a, index_b = split_args(args, 2) + index_a = parse_int(index_a, 'index') + index_b = parse_int(index_b, 'index') + + list_swap(config.rules, index_a, index_b) + config.save_rules() + command_rule_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_helper_list(buffer, command, args): + ''' Show the list of helpers. ''' + output = 'Helper variables:\n' + + width = max(map(lambda x: len(x) if len(x) <= 30 else 0, config.helpers.keys())) + + for name, expression in sorted(config.helpers.items()): + output += ' {0:>{width}}: {1}\n'.format(name, expression, width=width) + if not len(config.helpers): + output += ' No helper variables configured.' + log(output) + + return weechat.WEECHAT_RC_OK + + +def command_helper_set(buffer, command, args): + ''' Add/update a helper to the helper list. ''' + name, expression = split_args(args, 2) + + config.helpers[name] = expression + config.save_helpers() + command_helper_list(buffer, command, '') + + return weechat.WEECHAT_RC_OK + +def command_helper_delete(buffer, command, args): + ''' Delete a helper from the helper list. ''' + name = args.strip() + + del config.helpers[name] + config.save_helpers() + command_helper_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_helper_rename(buffer, command, args): + ''' Rename a helper to a new position. ''' + old_name, new_name = split_args(args, 2) + + try: + config.helpers[new_name] = config.helpers[old_name] + del config.helpers[old_name] + except KeyError: + raise HumanReadableError('No such helper: {0}'.format(old_name)) + config.save_helpers() + command_helper_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + + +def command_helper_swap(buffer, command, args): + ''' Swap two helpers. ''' + a, b = split_args(args, 2) + try: + config.helpers[b], config.helpers[a] = config.helpers[a], config.helpers[b] + except KeyError as e: + raise HumanReadableError('No such helper: {0}'.format(e.args[0])) + + config.helpers.swap(index_a, index_b) + config.save_helpers() + command_helper_list(buffer, command, '') + return weechat.WEECHAT_RC_OK + +def call_command(buffer, command, args, subcommands): + ''' Call a subcommand from a dictionary. ''' + subcommand, tail = pad(args.split(' ', 1), 2, '') + subcommand = subcommand.strip() + if (subcommand == ''): + child = subcommands.get(' ') + else: + command = command + [subcommand] + child = subcommands.get(subcommand) + + if isinstance(child, dict): + return call_command(buffer, command, tail, child) + elif callable(child): + return child(buffer, command, tail) + + log('{0}: command not found'.format(' '.join(command))) + return weechat.WEECHAT_RC_ERROR + +def on_signal(data, signal, signal_data): + global signal_delay_timer + global sort_queued + + # If the sort limit timeout is started, we're in the hold-off time after sorting, just queue a sort. + if sort_limit_timer is not None: + if sort_queued: + debug('Signal {0} ignored, sort limit timeout is active and sort is already queued.'.format(signal)) + else: + debug('Signal {0} received but sort limit timeout is active, sort is now queued.'.format(signal)) + sort_queued = True + return weechat.WEECHAT_RC_OK + + # If the signal delay timeout is started, a signal was recently received, so ignore this signal. + if signal_delay_timer is not None: + debug('Signal {0} ignored, signal delay timeout active.'.format(signal)) + return weechat.WEECHAT_RC_OK + + # Otherwise, start the signal delay timeout. + debug('Signal {0} received, starting signal delay timeout of {1} ms.'.format(signal, config.signal_delay)) + weechat.hook_timer(config.signal_delay, 0, 1, "on_signal_delay_timeout", "") + return weechat.WEECHAT_RC_OK + +def on_signal_delay_timeout(pointer, remaining_calls): + """ Called when the signal_delay_timer triggers. """ + global signal_delay_timer + global sort_limit_timer + global sort_queued + + signal_delay_timer = None + + # If the sort limit timeout was started, we're still in the no-sort period, so just queue a sort. + if sort_limit_timer is not None: + debug('Signal delay timeout expired, but sort limit timeout is active, sort is now queued.') + sort_queued = True + return weechat.WEECHAT_RC_OK + + # Time to sort! + debug('Signal delay timeout expired, starting sort.') + do_sort() + + # Start the sort limit timeout if not disabled. + if config.sort_limit > 0: + debug('Starting sort limit timeout of {0} ms.'.format(config.sort_limit)) + sort_limit_timer = weechat.hook_timer(config.sort_limit, 0, 1, "on_sort_limit_timeout", "") + + return weechat.WEECHAT_RC_OK + +def on_sort_limit_timeout(pointer, remainin_calls): + """ Called when de sort_limit_timer triggers. """ + global sort_limit_timer + global sort_queued + + # If no signal was received during the timeout, we're done. + if not sort_queued: + debug('Sort limit timeout expired without receiving a signal.') + sort_limit_timer = None + return weechat.WEECHAT_RC_OK + + # Otherwise it's time to sort. + debug('Signal received during sort limit timeout, starting queued sort.') + do_sort() + sort_queued = False + + # Start the sort limit timeout again if not disabled. + if config.sort_limit > 0: + debug('Starting sort limit timeout of {0} ms.'.format(config.sort_limit)) + sort_limit_timer = weechat.hook_timer(config.sort_limit, 0, 1, "on_sort_limit_timeout", "") + + return weechat.WEECHAT_RC_OK + + +def apply_config(): + # Unhook all signals and hook the new ones. + for hook in hooks: + weechat.unhook(hook) + for signal in config.signals: + hooks.append(weechat.hook_signal(signal, 'on_signal', '')) + + if config.sort_on_config: + debug('Sorting because configuration changed.') + do_sort() + +def on_config_changed(*args, **kwargs): + ''' Called whenever the configuration changes. ''' + config.reload() + apply_config() + + return weechat.WEECHAT_RC_OK + +def parse_arg(args): + if not args: return '', None + + result = '' + escaped = False + for i, c in enumerate(args): + if not escaped: + if c == '\\': + escaped = True + continue + elif c == ',': + return result, args[i+1:] + result += c + escaped = False + return result, None + +def parse_args(args, max = None): + result = [] + i = 0 + while max is None or i < max: + i += 1 + arg, args = parse_arg(args) + if arg is None: break + result.append(arg) + if args is None: break + return result, args + +def on_info_escape(pointer, name, arguments): + result = '' + for c in arguments: + if c == '\\': + result += '\\\\' + elif c == ',': + result += '\\,' + else: + result +=c + return result + +def on_info_replace(pointer, name, arguments): + arguments, rest = parse_args(arguments, 3) + if rest or len(arguments) < 3: + log('usage: ${{info:{0},old,new,text}}'.format(name)) + return '' + old, new, text = arguments + + return text.replace(old, new) + +def on_info_order(pointer, name, arguments): + arguments, rest = parse_args(arguments) + if len(arguments) < 1: + log('usage: ${{info:{0},value,first,second,third,...}}'.format(name)) + return '' + + value = arguments[0] + keys = arguments[1:] + if not keys: return '0' + + # Find the value in the keys (or '*' if we can't find it) + result = list_find(keys, value) + if result is None: result = list_find(keys, '*') + if result is None: result = len(keys) + + # Pad result with leading zero to make sure string sorting works. + width = int(math.log10(len(keys))) + 1 + return '{0:0{1}}'.format(result, width) + + +def on_autosort_command(data, buffer, args): + ''' Called when the autosort command is invoked. ''' + try: + return call_command(buffer, ['/autosort'], args, { + ' ': command_sort, + 'sort': command_sort, + 'debug': command_debug, + + 'rules': { + ' ': command_rule_list, + 'list': command_rule_list, + 'add': command_rule_add, + 'insert': command_rule_insert, + 'update': command_rule_update, + 'delete': command_rule_delete, + 'move': command_rule_move, + 'swap': command_rule_swap, + }, + 'helpers': { + ' ': command_helper_list, + 'list': command_helper_list, + 'set': command_helper_set, + 'delete': command_helper_delete, + 'rename': command_helper_rename, + 'swap': command_helper_swap, + }, + }) + except HumanReadableError as e: + log(e) + return weechat.WEECHAT_RC_ERROR + +def add_completions(completion, words): + for word in words: + weechat.hook_completion_list_add(completion, word, 0, weechat.WEECHAT_LIST_POS_END) + +def autosort_complete_rules(words, completion): + if len(words) == 0: + add_completions(completion, ['add', 'delete', 'insert', 'list', 'move', 'swap', 'update']) + if len(words) == 1 and words[0] in ('delete', 'insert', 'move', 'swap', 'update'): + add_completions(completion, map(str, range(len(config.rules)))) + if len(words) == 2 and words[0] in ('move', 'swap'): + add_completions(completion, map(str, range(len(config.rules)))) + if len(words) == 2 and words[0] in ('update'): + try: + add_completions(completion, [config.rules[int(words[1])]]) + except KeyError: pass + except ValueError: pass + else: + add_completions(completion, ['']) + return weechat.WEECHAT_RC_OK + +def autosort_complete_helpers(words, completion): + if len(words) == 0: + add_completions(completion, ['delete', 'list', 'rename', 'set', 'swap']) + elif len(words) == 1 and words[0] in ('delete', 'rename', 'set', 'swap'): + add_completions(completion, sorted(config.helpers.keys())) + elif len(words) == 2 and words[0] == 'swap': + add_completions(completion, sorted(config.helpers.keys())) + elif len(words) == 2 and words[0] == 'rename': + add_completions(completion, sorted(config.helpers.keys())) + elif len(words) == 2 and words[0] == 'set': + try: + add_completions(completion, [config.helpers[words[1]]]) + except KeyError: pass + return weechat.WEECHAT_RC_OK + +def on_autosort_complete(data, name, buffer, completion): + cmdline = weechat.buffer_get_string(buffer, "input") + cursor = weechat.buffer_get_integer(buffer, "input_pos") + prefix = cmdline[:cursor] + words = prefix.split()[1:] + + # If the current word isn't finished yet, + # ignore it for coming up with completion suggestions. + if prefix[-1] != ' ': words = words[:-1] + + if len(words) == 0: + add_completions(completion, ['debug', 'helpers', 'rules', 'sort']) + elif words[0] == 'rules': + return autosort_complete_rules(words[1:], completion) + elif words[0] == 'helpers': + return autosort_complete_helpers(words[1:], completion) + return weechat.WEECHAT_RC_OK + +command_description = r'''{*white}# General commands{reset} + +{*white}/autosort {brown}sort{reset} +Manually trigger the buffer sorting. + +{*white}/autosort {brown}debug{reset} +Show the evaluation results of the sort rules for each buffer. + + +{*white}# Sorting rule commands{reset} + +{*white}/autosort{brown} rules list{reset} +Print the list of sort rules. + +{*white}/autosort {brown}rules add {cyan}{reset} +Add a new rule at the end of the list. + +{*white}/autosort {brown}rules insert {cyan} {reset} +Insert a new rule at the given index in the list. + +{*white}/autosort {brown}rules update {cyan} {reset} +Update a rule in the list with a new expression. + +{*white}/autosort {brown}rules delete {cyan} +Delete a rule from the list. + +{*white}/autosort {brown}rules move {cyan} {reset} +Move a rule from one position in the list to another. + +{*white}/autosort {brown}rules swap {cyan} {reset} +Swap two rules in the list + + +{*white}# Helper variable commands{reset} + +{*white}/autosort {brown}helpers list +Print the list of helper variables. + +{*white}/autosort {brown}helpers set {cyan} +Add or update a helper variable with the given name. + +{*white}/autosort {brown}helpers delete {cyan} +Delete a helper variable. + +{*white}/autosort {brown}helpers rename {cyan} +Rename a helper variable. + +{*white}/autosort {brown}helpers swap {cyan} +Swap the expressions of two helper variables in the list. + + +{*white}# Info hooks{reset} +Autosort comes with a number of info hooks to add some extra functionality to regular weechat eval strings. +Info hooks can be used in eval strings in the form of {cyan}${{info:some_hook,arguments}}{reset}. + +Commas and backslashes in arguments to autosort info hooks (except for {cyan}${{info:autosort_escape}}{reset}) must be escaped with a backslash. + +{*white}${{info:{brown}autosort_replace{white},{cyan}pattern{white},{cyan}replacement{white},{cyan}source{white}}}{reset} +Replace all occurrences of {cyan}pattern{reset} with {cyan}replacement{reset} in the string {cyan}source{reset}. +Can be used to ignore certain strings when sorting by replacing them with an empty string. + +For example: {cyan}${{info:autosort_replace,cat,dog,the dog is meowing}}{reset} expands to "the cat is meowing". + +{*white}${{info:{brown}autosort_order{white},{cyan}value{white},{cyan}option0{white},{cyan}option1{white},{cyan}option2{white},{cyan}...{white}}} +Generate a zero-padded number that corresponds to the index of {cyan}value{reset} in the list of options. +If one of the options is the special value {brown}*{reset}, then any value not explicitly mentioned will be sorted at that position. +Otherwise, any value that does not match an option is assigned the highest number available. +Can be used to easily sort buffers based on a manual sequence. + +For example: {cyan}${{info:autosort_order,${{server}},freenode,oftc,efnet}}{reset} will sort freenode before oftc, followed by efnet and then any remaining servers. +Alternatively, {cyan}${{info:autosort_order,${{server}},freenode,oftc,*,efnet}}{reset} will sort any unlisted servers after freenode and oftc, but before efnet. + +{*white}${{info:{brown}autosort_escape{white},{cyan}text{white}}}{reset} +Escape commas and backslashes in {cyan}text{reset} by prepending them with a backslash. +This is mainly useful to pass arbitrary eval strings as arguments to other autosort info hooks. +Otherwise, an eval string that expands to something with a comma would be interpreted as multiple arguments. + +For example, it can be used to safely pass buffer names to {cyan}${{info:autosort_replace}}{reset} like so: +{cyan}${{info:autosort_replace,##,#,${{info:autosort_escape,${{buffer.name}}}}}}{reset}. + + +{*white}# Description +Autosort is a weechat script to automatically keep your buffers sorted. The sort +order can be customized by defining your own sort rules, but the default should +be sane enough for most people. It can also group IRC channel/private buffers +under their server buffer if you like. + +Autosort uses a stable sorting algorithm, meaning that you can manually move buffers +to change their relative order, if they sort equal with your rule set. + +{*white}# Sort rules{reset} +Autosort evaluates a list of eval expressions (see {*default}/help eval{reset}) and sorts the +buffers based on evaluated result. Earlier rules will be considered first. Only +if earlier rules produced identical results is the result of the next rule +considered for sorting purposes. + +You can debug your sort rules with the `{*default}/autosort debug{reset}` command, which will +print the evaluation results of each rule for each buffer. + +{*brown}NOTE:{reset} The sort rules for version 3 are not compatible with version 2 or vice +versa. You will have to manually port your old rules to version 3 if you have any. + +{*white}# Helper variables{reset} +You may define helper variables for the main sort rules to keep your rules +readable. They can be used in the main sort rules as variables. For example, +a helper variable named `{cyan}foo{reset}` can be accessed in a main rule with the +string `{cyan}${{foo}}{reset}`. + +{*white}# Automatic or manual sorting{reset} +By default, autosort will automatically sort your buffer list whenever a buffer +is opened, merged, unmerged or renamed. This should keep your buffers sorted in +almost all situations. However, you may wish to change the list of signals that +cause your buffer list to be sorted. Simply edit the `{cyan}autosort.sorting.signals{reset}` +option to add or remove any signal you like. + +If you remove all signals you can still sort your buffers manually with the +`{*default}/autosort sort{reset}` command. To prevent all automatic sorting, the option +`{cyan}autosort.sorting.sort_on_config_change{reset}` should also be disabled. + +{*white}# Recommended settings +For the best visual effect, consider setting the following options: + {*white}/set {cyan}irc.look.server_buffer{reset} {brown}independent{reset} + +This setting allows server buffers to be sorted independently, which is +needed to create a hierarchical tree view of the server and channel buffers. + +If you are using the {*default}buflist{reset} plugin you can (ab)use Unicode to draw a tree +structure with the following setting (modify to suit your need): + {*white}/set {cyan}buflist.format.indent {brown}"${{color:237}}${{if:${{buffer.next_buffer.local_variables.type}}=~^(channel|private)$?├─:└─}}"{reset} +''' + +command_completion = '%(plugin_autosort) %(plugin_autosort) %(plugin_autosort) %(plugin_autosort) %(plugin_autosort)' + +info_replace_description = ( + 'Replace all occurrences of `pattern` with `replacement` in the string `source`. ' + 'Can be used to ignore certain strings when sorting by replacing them with an empty string. ' + 'See /help autosort for examples.' +) +info_replace_arguments = 'pattern,replacement,source' + +info_order_description = ( + 'Generate a zero-padded number that corresponds to the index of `value` in the list of options. ' + 'If one of the options is the special value `*`, then any value not explicitly mentioned will be sorted at that position. ' + 'Otherwise, any value that does not match an option is assigned the highest number available. ' + 'Can be used to easily sort buffers based on a manual sequence. ' + 'See /help autosort for examples.' +) +info_order_arguments = 'value,first,second,third,...' + +info_escape_description = ( + 'Escape commas and backslashes in `text` by prepending them with a backslash. ' + 'This is mainly useful to pass arbitrary eval strings as arguments to other autosort info hooks. ' + 'Otherwise, an eval string that expands to something with a comma would be interpreted as multiple arguments.' + 'See /help autosort for examples.' +) +info_escape_arguments = 'text' + + +if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""): + config = Config('autosort') + + colors = { + 'default': weechat.color('default'), + 'reset': weechat.color('reset'), + 'black': weechat.color('black'), + 'red': weechat.color('red'), + 'green': weechat.color('green'), + 'brown': weechat.color('brown'), + 'yellow': weechat.color('yellow'), + 'blue': weechat.color('blue'), + 'magenta': weechat.color('magenta'), + 'cyan': weechat.color('cyan'), + 'white': weechat.color('white'), + '*default': weechat.color('*default'), + '*black': weechat.color('*black'), + '*red': weechat.color('*red'), + '*green': weechat.color('*green'), + '*brown': weechat.color('*brown'), + '*yellow': weechat.color('*yellow'), + '*blue': weechat.color('*blue'), + '*magenta': weechat.color('*magenta'), + '*cyan': weechat.color('*cyan'), + '*white': weechat.color('*white'), + } + + weechat.hook_config('autosort.*', 'on_config_changed', '') + weechat.hook_completion('plugin_autosort', '', 'on_autosort_complete', '') + weechat.hook_command('autosort', command_description.format(**colors), '', '', command_completion, 'on_autosort_command', '') + weechat.hook_info('autosort_escape', info_escape_description, info_escape_arguments, 'on_info_escape', '') + weechat.hook_info('autosort_replace', info_replace_description, info_replace_arguments, 'on_info_replace', '') + weechat.hook_info('autosort_order', info_order_description, info_order_arguments, 'on_info_order', '') + + apply_config() diff -r 93d27886c099 -r 62e329839625 weechat-old/python/colon_complete.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python/colon_complete.py Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,69 @@ +SCRIPT_NAME='coloncomplete' +SCRIPT_AUTHOR='Steve Losh ' +SCRIPT_VERSION='1.0' +SCRIPT_LICENSE='MIT/X11' +SCRIPT_DESC='Add a colon after nick completion when all the previous words in the input are also nicks.' + +EXTRA_NICKS = ['all', 'backend', 'clojerks', 'ops', 'support'] + +import_ok=True + +try: + import weechat +except ImportError: + print 'This script must be run under WeeChat' + print 'You can obtain a copy of WeeChat, for free, at http://www.weechat.org' + import_ok=False + +weechat_version=0 + +def get_nicks(buffer, prefix=''): + channel = weechat.buffer_get_string(buffer, 'localvar_channel') + server = weechat.buffer_get_string(buffer, 'localvar_server') + prefix = prefix.lower() + + matches = [] + + infolist = weechat.infolist_get('irc_nick', '', '%s,%s' % (server, channel)) + while weechat.infolist_next(infolist): + nick = weechat.infolist_string(infolist, 'name') + if nick != 'localhost' and nick.lower().startswith(prefix): + matches.append(nick) + weechat.infolist_free(infolist) + + for nick in EXTRA_NICKS: + if nick.lower().startswith(prefix): + matches.append(nick) + + return matches + +def completer(data, buffer, command): + cb = weechat.current_buffer() + if command == "/input complete_next": + line = weechat.buffer_get_string(cb, "input") + words = line.split(' ') + prefix = words[-1] + if prefix and words and all([s.endswith(':') for s in words[:-1] if s]): + nicks = get_nicks(cb, prefix) + if len(nicks) == 1: + for _ in range(len(prefix)): + weechat.command(buffer, "/input delete_previous_char") + weechat.command(buffer, "/input insert " + nicks[-1] + ":\\x20") + elif len(nicks) > 1: + l = min(len(nick) for nick in nicks) + for i in range(len(prefix), l): + if len(set(nick[i] for nick in nicks)) > 1: + break + else: + weechat.command(buffer, "/input insert " + nicks[0][i]) + + for nick in nicks: + weechat.prnt(cb, "==> " + nick) + return weechat.WEECHAT_RC_OK_EAT + + return weechat.WEECHAT_RC_OK + +if __name__ == "__main__" and import_ok: + if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""): + weechat_version = weechat.info_get("version_number", "") or 0 + weechat.hook_command_run('/input complete*', 'completer', '') diff -r 93d27886c099 -r 62e329839625 weechat-old/python/listbuffer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python/listbuffer.py Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,467 @@ +# -*- coding: utf-8 -*- +# +# ListBuffer, version 0.8.1 for WeeChat version 0.3 +# Latest development version: https://github.com/FiXato/listbuffer +# +# Show /list results in a common buffer and interact with them. +# +# This script allows you to easily join channels from the /list output. +# It will open a common buffer for the /list result, through which you +# browse with your cursor keys, and join with the meta-enter keys. +# Adjust sorting with meta->, meta-< and meta-/ keybindings. +# +## History: +### 2011-09-08: FiXato: +# +# * version 0.1: initial release. +# * added a common buffer for /list results +# * added highlighting for currently selected line +# * added /join support via enter key +# * added scroll_top and scroll_bottom support +# +# * version 0.2: /list format bugfix +# * added support for /list results without modes +# * some servers don't send 321 (/list start). Taken into account. +# +# * version 0.3: Sorting support +# * Added some basic sorting support. Scroll through sort options +# with meta-> and meta-< (users, channel, topic, modes) +# +### 2011-09-19: FiXato +# +# * version 0.4: +# * Case-insensitive buffer lookup fix. +# * Removed default enter keybind +# +### 2011-12-28: troydm: +# +# * version 0.5: It's an upside-down-world +# * Added inverted sorting support provided by Dmitry "troydm" Geurkov +# Use meta-/ to switch between inverted and regular sorting. +# +### 2012-02-10: FiXato: +# +# * version 0.6: Stop shoving that buffer in my face! +# * The listbuffer should no longer pop up by itself when you load the script. +# It should only pop up now when you actually do a /list query. +# +# * version 0.7: .. but please pop it up in my current window when I ask for it +# * Added setting plugins.var.python.listbuffer.autofocus +# This will autofocus the listbuffer in the current window if another window isn't +# already showing it, and of course only when the user issues /list +# +### 2012-07-10: FiXato: +# +# * version 0.7.1: Forgetful bugfix +# * Made sure lb_curline global variable is defined +# +### 2013-03-19: FiXato: +# +# * version 0.8: Sorted out the sorting +# * Added automatically updating options for sorting: +# * plugins.var.python.listbuffer.sort_inverted +# * plugins.var.python.listbuffer.sort_order +# * version 0.8.1: Pad it baby! +# * Channel modes are equally padded even when there are no channel modes. +# * Added padding options: +# * plugins.var.python.listbuffer.modes_min_width +# * plugins.var.python.listbuffer.channel_min_width +# * plugins.var.python.listbuffer.users_min_width +# +## Acknowledgements: +# * Dmitry "troydm" Geurkov, for providing the inverse-sorting patch to the project. +# * Sebastien "Flashcode" Helleu, for developing the kick-ass IRC client WeeChat +# and the iset.pl script which inspired me to this script. +# * Nils "nils_2" Görs, for his contributions to iset.pl which served as +# example code. +# * David "drubin" Rubin, for his urlgrab.py script, which also served +# as example code. +# * ArZa, whose listsort.pl script helped me getting started with +# grabbing the /list results. Parts of his code have been shamelessly +# copied and ported to Python. +# * Khaled Mardam-Bey, for making me yearn for similar /list support in +# WeeChat as mIRC already offered. :P +# * mave_, for pointing out that sort orders weren't remembered. +# +## TODO: +# - Auto-scroll selected line upon window scroll. +# - Add option to hide already joined channels. +# - Improve sorting methods +# - Add auto-join support +# - Detect if channel is already in auto-join +# - Allow automatically switching to the listbuffer +# - Add support for ALIS (/squery alis LIST * -mix 100 (IRCNet) +# - Make colours configurable +# - Limit number of channels to parse +# - Add filter support a la iset +# - Allow selecting multiple channels +# - Add optional command redirection. +# +## Copyright (c) 2011,2012,2013 Filip H.F. "FiXato" Slagter, +# +# http://profile.fixato.org +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +SCRIPT_NAME = "listbuffer" +SCRIPT_AUTHOR = "Filip H.F. 'FiXato' Slagter " +SCRIPT_VERSION = "0.8.1" +SCRIPT_LICENSE = "MIT" +SCRIPT_DESC = "A common buffer for /list output." +SCRIPT_COMMAND = "listbuffer" + +import_ok = True + +try: + import weechat +except ImportError: + print "This script must be run under WeeChat." + import_ok = False + +import re + +lb_settings = ( + ("autofocus", "on", "Focus the listbuffer in the current window if it isn't already displayed by a window."), + ("sort_order", "users", "Last used sort order for the channel list."), + ("sort_inverted", "on", "Invert the sort order for the channel list."), + ("modes_min_width", "8", "The minimum width used for modes in the channel list. If a channel has less modes than this amount, the column will be padded with spaces."), + ("channel_min_width", "25", "The minimum width used for the channel name in the channel list. If a channelname is shorter than this amount, the column will be padded with spaces."), + ("users_min_width", "8", "The minimum width used for the usercount in the channel list. If the usercount has less digits than this amount, the column will be padded with spaces."), +) +lb_buffer = None +lb_curline = 0 +lb_channels = [] +lb_network = None +lb_list_started = False +lb_current_sort = None +lb_sort_inverted = False +lb_sort_options = ( + 'channel', + 'users', + 'modes', + 'topic', +) + +# server numeric Nick Chan Users Modes Topic +lb_channel_list_expression = '(:\S+) (\d{3}) (\S+) (\S+) (\d+) :(\[(.*?)\] )?(.*)' + +# Create listbuffer. +def lb_create_buffer(): + global lb_buffer, lb_curline + + if not lb_buffer: + lb_buffer = weechat.buffer_new("listbuffer", "lb_input_cb", \ + "", "lb_close_cb", "") + lb_set_buffer_title() + # Sets notify to 0 as this buffer does not need to be in hotlist. + weechat.buffer_set(lb_buffer, "notify", "0") + weechat.buffer_set(lb_buffer, "nicklist", "0") + weechat.buffer_set(lb_buffer, "type", "free") + weechat.buffer_set(lb_buffer, "key_bind_ctrl-L", "/listbuffer **refresh") + weechat.buffer_set(lb_buffer, "key_bind_meta2-A", "/listbuffer **up") + weechat.buffer_set(lb_buffer, "key_bind_meta2-B", "/listbuffer **down") + weechat.buffer_set(lb_buffer, "key_bind_meta2-1~", "/listbuffer **scroll_top") + weechat.buffer_set(lb_buffer, "key_bind_meta2-4~", "/listbuffer **scroll_bottom") + weechat.buffer_set(lb_buffer, "key_bind_meta-ctrl-J", "/listbuffer **enter") + weechat.buffer_set(lb_buffer, "key_bind_meta-ctrl-M", "/listbuffer **enter") + weechat.buffer_set(lb_buffer, "key_bind_meta->", "/listbuffer **sort_next") + weechat.buffer_set(lb_buffer, "key_bind_meta-<", "/listbuffer **sort_previous") + weechat.buffer_set(lb_buffer, "key_bind_meta-/", "/listbuffer **sort_invert") + lb_curline = 0 + if weechat.config_get_plugin("autofocus") == "on": + if not weechat.window_search_with_buffer(lb_buffer): + weechat.command("", "/buffer " + weechat.buffer_get_string(lb_buffer,"name")) + +def lb_set_buffer_title(): + global lb_buffer, lb_current_sort + ascdesc = '(v)' if lb_sort_inverted else '(^)' + weechat.buffer_set(lb_buffer, "title", lb_line_format({ + 'channel': 'Channel name%s' % (ascdesc if lb_current_sort == 'channel' else ''), + 'users': 'Users%s' % (ascdesc if lb_current_sort == 'users' else ''), + 'modes': 'Modes%s' % (ascdesc if lb_current_sort == 'modes' else ''), + 'topic': 'Topic%s' % (ascdesc if lb_current_sort == 'topic' else ''), + 'nomodes': None, + })) + +def lb_list_start(data, signal, message): + lb_initialise_list + + return weechat.WEECHAT_RC_OK + +def lb_initialise_list(signal): + global lb_channels, lb_network, lb_list_started + + lb_create_buffer() + lb_channels = [] + lb_network = signal.split(',')[0] + lb_list_started = True + return + + +def lb_list_chan(data, signal, message): + global lb_channels, lb_buffer, lb_list_started + + # Work-around for IRCds which don't send 321 Numeric (/List start) + if not lb_list_started: + lb_initialise_list(signal) + + for chan_data in re.findall(lb_channel_list_expression,message): + lb_channels.append({ + 'server': chan_data[0][1:-1], + 'numeric': chan_data[1], + 'nick': chan_data[2], + 'channel': chan_data[3], + 'users': chan_data[4], + 'nomodes': chan_data[5] == '', + 'modes': chan_data[6], + 'topic': weechat.hook_modifier_exec("irc_color_decode", "1", chan_data[7]) + }) + return weechat.WEECHAT_RC_OK + +def lb_list_end(data, signal, message): + global lb_list_started + + # Work-around for IRCds which don't send 321 Numeric (/List start) + if not lb_list_started: + lb_initialise_list(signal) + + lb_list_started = False + if lb_current_sort: + lb_sort() + lb_refresh() + return weechat.WEECHAT_RC_OK + +def keyEvent (data, buffer, args): + global lb_options + lb_options[args]() + +def lb_input_cb(data, buffer, input_data): + global lb_options, lb_curline + lb_options[input_data]() + return weechat.WEECHAT_RC_OK + +def lb_refresh(): + global lb_channels, lb_buffer + weechat.buffer_clear(lb_buffer) + + y = 0 + for list_data in lb_channels: + lb_refresh_line(y) + y += 1 + return + +def lb_refresh_line(y): + global lb_buffer, lb_curline, lb_channels + if y >= 0 and y < len(lb_channels): + formatted_line = lb_line_format(lb_channels[y], y == lb_curline) + weechat.prnt_y(lb_buffer, y, formatted_line) + +def lb_refresh_curline(): + global lb_curline + lb_refresh_line(lb_curline-1) + lb_refresh_line(lb_curline) + lb_refresh_line(lb_curline+1) + return + +def lb_line_format(list_data,curr=False): + str = "" + if (curr): + str += weechat.color("yellow,red") + channel_text = list_data['channel'].ljust(int(weechat.config_get_plugin('channel_min_width'))) + users_text = "(%s)" % list_data['users'] + padded_users_text = users_text.rjust(int(weechat.config_get_plugin('users_min_width')) + 2) + str += "%s%s %s " % (weechat.color("bold"), channel_text, padded_users_text) + if not list_data['nomodes']: + modes = "[%s]" % list_data['modes'] + else: + modes = "[]" + str += "%s: " % modes.rjust(int(weechat.config_get_plugin('modes_min_width')) + 2) + str += "%s" % list_data['topic'] + return str + +def lb_line_up(): + global lb_curline + if lb_curline <= 0: + return + lb_curline -= 1 + lb_refresh_curline() + lb_check_outside_window() + return + +def lb_line_down(): + global lb_curline, lb_channels + if lb_curline+1 >= len(lb_channels): + return + lb_curline += 1 + lb_refresh_curline() + lb_check_outside_window() + return + +def lb_line_run(): + global lb_channels, lb_curline, lb_network + buff = weechat.info_get("irc_buffer", lb_network) + channel = lb_channels[lb_curline]['channel'] + command = "/join %s" % channel + weechat.command(buff, command) + return + +def lb_line_select(): + return + +def lb_scroll_top(): + global lb_curline + old_y = lb_curline + lb_curline = 0 + lb_refresh_curline() + lb_refresh_line(old_y) + weechat.command(lb_buffer, "/window scroll_top") + return + +def lb_scroll_bottom(): + global lb_curline, lb_channels + old_y = lb_curline + lb_curline = len(lb_channels)-1 + lb_refresh_curline() + lb_refresh_line(old_y) + weechat.command(lb_buffer, "/window scroll_bottom") + return + +def lb_check_outside_window(): + global lb_buffer, lb_curline + if (lb_buffer): + infolist = weechat.infolist_get("window", "", "current") + if (weechat.infolist_next(infolist)): + start_line_y = weechat.infolist_integer(infolist, "start_line_y") + chat_height = weechat.infolist_integer(infolist, "chat_height") + if(start_line_y > lb_curline): + weechat.command(lb_buffer, "/window scroll -%i" %(start_line_y - lb_curline)) + elif(start_line_y <= lb_curline - chat_height): + weechat.command(lb_buffer, "/window scroll +%i"%(lb_curline - start_line_y - chat_height + 1)) + weechat.infolist_free(infolist) + +def lb_sort_next(): + global lb_current_sort, lb_sort_options + if lb_current_sort: + new_index = lb_sort_options.index(lb_current_sort) + 1 + else: + new_index = 0 + + if len(lb_sort_options) <= new_index: + new_index = 0 + + lb_set_current_sort_order(lb_sort_options[new_index]) + lb_sort() + +def lb_set_current_sort_order(value): + global lb_current_sort + lb_current_sort = value + weechat.config_set_plugin('sort_order', lb_current_sort) + +def lb_set_invert_sort_order(value): + global lb_sort_inverted + lb_sort_inverted = value + weechat.config_set_plugin('sort_inverted', ('on' if lb_sort_inverted else 'off')) + +def lb_sort_previous(): + global lb_current_sort, lb_sort_options + if lb_current_sort: + new_index = lb_sort_options.index(lb_current_sort) - 1 + else: + new_index = 0 + + if new_index < 0: + new_index = len(lb_sort_options) - 1 + + lb_set_current_sort_order(lb_sort_options[new_index]) + lb_sort() + +def lb_sort(sort_key=None): + global lb_channels, lb_current_sort, lb_sort_inverted + if sort_key: + lb_set_current_sort_order(sort_key) + if lb_current_sort == 'users': + lb_channels = sorted(lb_channels, key=lambda chan_data: int(chan_data[lb_current_sort])) + else: + lb_channels = sorted(lb_channels, key=lambda chan_data: chan_data[lb_current_sort]) + if lb_sort_inverted: + lb_channels.reverse() + lb_set_buffer_title() + lb_refresh() + +def lb_sort_invert(): + global lb_current_sort, lb_sort_inverted + if lb_current_sort: + lb_set_invert_sort_order(not lb_sort_inverted) + lb_sort() + +def lb_close_cb(*kwargs): + """ A callback for buffer closing. """ + global lb_buffer + + lb_buffer = None + return weechat.WEECHAT_RC_OK + +lb_options = { + 'refresh' : lb_refresh, + 'up' : lb_line_up, + 'down' : lb_line_down, + 'enter' : lb_line_run, + 'space' : lb_line_select, + 'scroll_top' : lb_scroll_top, + 'scroll_bottom': lb_scroll_bottom, + 'sort_next' : lb_sort_next, + 'sort_previous': lb_sort_previous, + 'sort_invert': lb_sort_invert +} + +def lb_command_main(data, buffer, args): + if args[0:2] == "**": + keyEvent(data, buffer, args[2:]) + return weechat.WEECHAT_RC_OK + +def lb_set_default_settings(): + global lb_settings + # Set default settings + for option, default_value, description in lb_settings: + if not weechat.config_is_set_plugin(option): + weechat.config_set_plugin(option, default_value) + version = weechat.info_get("version_number", "") or 0 + if int(version) >= 0x00030500: + weechat.config_set_desc_plugin(option, description) + +def lb_reset_stored_sort_order(): + global lb_current_sort, lb_sort_inverted + lb_current_sort = weechat.config_get_plugin('sort_order') + lb_sort_inverted = (True if weechat.config_get_plugin('sort_inverted') == 'on' else False) + +if __name__ == "__main__" and import_ok: + if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, + SCRIPT_LICENSE, SCRIPT_DESC, "lb_close_cb", ""): + lb_set_default_settings() + lb_reset_stored_sort_order() + lb_buffer = weechat.buffer_search("python", "listbuffer") + + weechat.hook_signal("*,irc_in_321", "lb_list_start", "") + weechat.hook_signal("*,irc_in_322", "lb_list_chan", "") + weechat.hook_signal("*,irc_in_323", "lb_list_end", "") + weechat.hook_command(SCRIPT_COMMAND, + "List Buffer", + "", "", "", + "lb_command_main", "") diff -r 93d27886c099 -r 62e329839625 weechat-old/python/sanitize_jira.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/python/sanitize_jira.py Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,33 @@ +import re, weechat, subprocess + +SCRIPT_NAME = 'sanitize_jira' +SCRIPT_AUTHOR = 'Steve Losh ' +SCRIPT_VERSION = '0.0.1' +SCRIPT_LICENSE = 'MIT' +SCRIPT_DESC = 'clean up the garbage jirabot sends to channels into something readable' + +weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, '', '') + +weechat.hook_line('*', '', 'nick_Jira_Cloud', 'sanitize_jira', '') + +first_line_re = re.compile( + r'(?Phttps://[^/]+/browse/[^?]+)[?]atlOrigin=[^ ]+ [(](?P.+)[)]' +) + +detail_line_re = re.compile( + r'''Status: \x1a\x01[*](?P<status>[^*]+)[*]\x1b\x01.*Type: \x1a\x01[*](?P<type>[^*]+)[*]\x1b\x01.*Assignee: \x1a\x01[*](?P<assignee>[^*]+)[*]\x1b\x01.*Priority: \x1a\x01[*](?P<priority>[^*]+)[*]\x1b\x01''' +) + +def sanitize_jira(data, line): + if 'sign up for an Atlassian account to view this link' in line['message']: + return {'message': ' '} + + m = first_line_re.search(line['message']) + if m: + return {'message': '%s | %s' % (m.group('title'), m.group('link'))} + + m = detail_line_re.search(line['message']) + if m: + return {'message': '%s / %s / %s' % (m.group('type'), m.group('status'), m.group('assignee'))} + + return {} diff -r 93d27886c099 -r 62e329839625 weechat-old/relay.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/relay.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,59 @@ +# +# weechat -- relay.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[look] +auto_open_buffer = on +raw_messages = 256 + +[color] +client = cyan +status_active = lightblue +status_auth_failed = lightred +status_connecting = yellow +status_disconnected = lightred +status_waiting_auth = brown +text = default +text_bg = default +text_selected = white + +[network] +allow_empty_password = off +allowed_ips = "" +auth_timeout = 60 +bind_address = "" +clients_purge_delay = 0 +compression = 20 +ipv6 = on +max_clients = 5 +nonce_size = 16 +password = "" +password_hash_algo = "*" +password_hash_iterations = 100000 +ssl_cert_key = "%h/ssl/relay.pem" +ssl_priorities = "NORMAL:-VERS-SSL3.0" +totp_secret = "" +totp_window = 0 +websocket_allowed_origins = "" + +[irc] +backlog_max_minutes = 1440 +backlog_max_number = 256 +backlog_since_last_disconnect = on +backlog_since_last_message = off +backlog_tags = "irc_privmsg" +backlog_time_format = "[%H:%M] " + +[weechat] +commands = "" + +[port] + +[path] diff -r 93d27886c099 -r 62e329839625 weechat-old/rmodifier.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/rmodifier.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,11 @@ +# +# rmodifier.conf -- weechat v0.4.3 +# + +[look] +hide_char = "*" + +[modifier] +nickserv = "history_add,input_text_display;^(/(msg|quote) +nickserv +(identify|ghost \S+) +)(.*);1,4*" +oper = "history_add,input_text_display;^(/oper +\S+ +)(.*);1,2*" +set_pass = "history_add;^(/set +\S*password\S* +)(.*);1,2*" diff -r 93d27886c099 -r 62e329839625 weechat-old/ruby.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/ruby.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,14 @@ +# +# weechat -- ruby.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +check_license = off +eval_keep_context = on diff -r 93d27886c099 -r 62e329839625 weechat-old/script.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/script.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,57 @@ +# +# weechat -- script.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[look] +columns = "%s %n %V %v %u | %d | %t" +diff_color = on +diff_command = "auto" +display_source = on +quiet_actions = on +sort = "p,n" +translate_description = on +use_keys = on + +[color] +status_autoloaded = cyan +status_held = white +status_installed = lightcyan +status_obsolete = lightmagenta +status_popular = yellow +status_running = lightgreen +status_unknown = lightred +text = default +text_bg = default +text_bg_selected = red +text_date = default +text_date_selected = white +text_delimiters = darkgray +text_description = default +text_description_selected = white +text_extension = default +text_extension_selected = white +text_name = cyan +text_name_selected = lightcyan +text_selected = white +text_tags = brown +text_tags_selected = yellow +text_version = magenta +text_version_loaded = default +text_version_loaded_selected = white +text_version_selected = lightmagenta + +[scripts] +autoload = on +cache_expire = 60 +download_enabled = on +download_timeout = 30 +hold = "" +path = "%h/script" +url = "http://www.weechat.org/files/plugins.xml.gz" diff -r 93d27886c099 -r 62e329839625 weechat-old/spell.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/spell.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,33 @@ +# +# weechat -- spell.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[color] +misspelled = lightred +suggestion = default +suggestion_delimiter_dict = cyan +suggestion_delimiter_word = cyan + +[check] +commands = "away,command,cycle,kick,kickban,me,msg,notice,part,query,quit,topic" +default_dict = "" +during_search = off +enabled = off +real_time = off +suggestions = -1 +word_min_length = 2 + +[dict] + +[look] +suggestion_delimiter_dict = " / " +suggestion_delimiter_word = "," + +[option] diff -r 93d27886c099 -r 62e329839625 weechat-old/tcl.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/tcl.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,14 @@ +# +# weechat -- tcl.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use /set or similar command to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[look] +check_license = off +eval_keep_context = on diff -r 93d27886c099 -r 62e329839625 weechat-old/trigger.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/trigger.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,83 @@ +# +# weechat -- trigger.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[look] +enabled = on +monitor_strip_colors = off + +[color] +flag_command = lightgreen +flag_conditions = yellow +flag_post_action = lightblue +flag_regex = lightcyan +flag_return_code = lightmagenta +regex = white +replace = cyan +trigger = green +trigger_disabled = red + +[trigger] +beep.arguments = "" +beep.command = "/print -beep" +beep.conditions = "${tg_highlight} || ${tg_msg_pv}" +beep.enabled = on +beep.hook = print +beep.post_action = none +beep.regex = "" +beep.return_code = ok +cmd_pass.arguments = "5000|input_text_display;5000|history_add;5000|irc_command_auth" +cmd_pass.command = "" +cmd_pass.conditions = "" +cmd_pass.enabled = on +cmd_pass.hook = modifier +cmd_pass.post_action = none +cmd_pass.regex = "==^((/(msg|quote) +nickserv +(id|identify|register|ghost +[^ ]+|release +[^ ]+|regain +[^ ]+) +)|/oper +[^ ]+ +|/quote +pass +|/set +[^ ]*password[^ ]* +|/secure +(passphrase|decrypt|set +[^ ]+) +)(.*)==$1$.*+" +cmd_pass.return_code = ok +dumbass_buffer.arguments = "4000|input_text_for_buffer;4000|history_add" +dumbass_buffer.command = "" +dumbass_buffer.conditions = "" +dumbass_buffer.enabled = on +dumbass_buffer.hook = modifier +dumbass_buffer.post_action = none +dumbass_buffer.regex = "==^ +/?b (.+)==/b ${re:1}" +dumbass_buffer.return_code = ok +idiot_buffer.arguments = "4000|input_text_for_buffer;4000|history_add" +idiot_buffer.command = "" +idiot_buffer.conditions = "" +idiot_buffer.enabled = on +idiot_buffer.hook = modifier +idiot_buffer.post_action = none +idiot_buffer.regex = "==^b (.+)==/b ${re:1}" +idiot_buffer.return_code = ok +msg_auth.arguments = "5000|irc_message_auth" +msg_auth.command = "" +msg_auth.conditions = "" +msg_auth.enabled = on +msg_auth.hook = modifier +msg_auth.post_action = none +msg_auth.regex = "==^(.*(id|identify|register|ghost +[^ ]+|release +[^ ]+) +)(.*)==$1$.*+" +msg_auth.return_code = ok +server_pass.arguments = "5000|input_text_display;5000|history_add" +server_pass.command = "" +server_pass.conditions = "" +server_pass.enabled = on +server_pass.hook = modifier +server_pass.post_action = none +server_pass.regex = "==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==$1$.*4$5" +server_pass.return_code = ok +uncc.arguments = "weechat_print" +uncc.command = "" +uncc.conditions = "${tg_tag_nick}" +uncc.enabled = on +uncc.hook = modifier +uncc.post_action = none +uncc.regex = "== \[cc: [^ ]+\]====" +uncc.return_code = ok diff -r 93d27886c099 -r 62e329839625 weechat-old/typing.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/typing.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,19 @@ +# +# weechat -- typing.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[look] +delay_purge_paused = 30 +delay_purge_typing = 6 +delay_set_paused = 10 +enabled_nicks = off +enabled_self = off +input_min_chars = 4 +item_max_length = 0 diff -r 93d27886c099 -r 62e329839625 weechat-old/urlgrab.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/urlgrab.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,29 @@ +# +# weechat -- urlgrab.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[color] +color_bg_selected = green +color_buffer = red +color_buffer_selected = red +color_time = cyan +color_time_selected = cyan +color_url = blue +color_url_selected = blue + +[default] +copycmd = "xsel -i" +historysize = 20 +localcmd = "xdg-open %s" +method = "local" +output_main_buffer = off +remotecmd = "ssh -x localhost -i ~/.ssh/id_rsa -C "export DISPLAY=":0.0" && firefox %s"" +time_format = "%H:%M:%S" +url_log = "~/.weechat/urls.log" diff -r 93d27886c099 -r 62e329839625 weechat-old/weechat.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/weechat.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,693 @@ +# +# WeeChat -- weechat.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart +# + +[debug] + +[startup] +command_after_plugins = "" +command_before_plugins = "" +display_logo = on +display_version = on +sys_rlimit = "" + +[look] +align_end_of_lines = message +align_multiline_words = on +bar_more_down = "++" +bar_more_left = "<<" +bar_more_right = ">>" +bar_more_up = "--" +bare_display_exit_on_input = on +bare_display_time_format = "%H:%M" +buffer_auto_renumber = on +buffer_notify_default = all +buffer_position = end +buffer_search_case_sensitive = off +buffer_search_force_default = off +buffer_search_regex = off +buffer_search_where = prefix_message +buffer_time_format = "%H:%M" +buffer_time_same = "" +color_basic_force_bold = off +color_inactive_buffer = off +color_inactive_message = on +color_inactive_prefix = on +color_inactive_prefix_buffer = on +color_inactive_time = off +color_inactive_window = off +color_nick_offline = off +color_pairs_auto_reset = 5 +color_real_white = off +command_chars = "" +command_incomplete = off +confirm_quit = off +confirm_upgrade = off +day_change = on +day_change_message_1date = "-- %a, %d %b %Y --" +day_change_message_2dates = "-- %%a, %%d %%b %%Y (%a, %d %b %Y) --" +eat_newline_glitch = off +emphasized_attributes = "" +highlight = "sjl,slosh,slj,horrifying,steve.losh,@steve.losh,stevelosh" +highlight_regex = "(steve losh|rob ford|(jesus )?fucking christ|(horse|mouse|clown)fuckers?|((mother)?fuck([ie]ng?|er)?|(god?)?damn(ed)?|dammit|(bull|horse)?shite?){3,})" +highlight_tags = "" +hotlist_add_conditions = "${away} || ${buffer.num_displayed} == 0" +hotlist_buffer_separator = ", " +hotlist_count_max = 2 +hotlist_count_min_msg = 2 +hotlist_names_count = 3 +hotlist_names_length = 0 +hotlist_names_level = 12 +hotlist_names_merged_buffers = off +hotlist_prefix = "H: " +hotlist_remove = merged +hotlist_short_names = on +hotlist_sort = group_time_asc +hotlist_suffix = "" +hotlist_unique_numbers = on +hotlist_update_on_buffer_switch = on +input_cursor_scroll = 20 +input_share = none +input_share_overwrite = off +input_undo_max = 32 +item_away_message = on +item_buffer_filter = "*" +item_buffer_zoom = "!" +item_mouse_status = "M" +item_time_format = "%H:%M" +jump_current_to_previous_buffer = on +jump_previous_buffer_when_closing = on +jump_smart_back_to_buffer = on +key_bind_safe = on +key_grab_delay = 800 +mouse = off +mouse_timer_delay = 100 +nick_color_force = "" +nick_color_hash = djb2 +nick_color_hash_salt = "" +nick_color_stop_chars = "_|[" +nick_prefix = "" +nick_suffix = "" +paste_auto_add_newline = on +paste_bracketed = off +paste_bracketed_timer_delay = 10 +paste_max_lines = 3 +prefix_action = " *" +prefix_align = right +prefix_align_max = 15 +prefix_align_min = 0 +prefix_align_more = "+" +prefix_align_more_after = on +prefix_buffer_align = right +prefix_buffer_align_max = 0 +prefix_buffer_align_more = "+" +prefix_buffer_align_more_after = on +prefix_error = "=!=" +prefix_join = "✔" +prefix_network = "--" +prefix_quit = "✘" +prefix_same_nick = "" +prefix_same_nick_middle = "" +prefix_suffix = "|" +quote_nick_prefix = "<" +quote_nick_suffix = ">" +quote_time_format = "%H:%M:%S" +read_marker = line +read_marker_always_show = on +read_marker_string = "─" +read_marker_update_on_buffer_switch = on +save_config_on_exit = off +save_config_with_fsync = off +save_layout_on_exit = all +scroll_amount = 3 +scroll_bottom_after_switch = off +scroll_page_percent = 100 +search_text_not_found_alert = on +separator_horizontal = "-" +separator_vertical = "" +tab_width = 1 +time_format = "%a, %d %b %Y %T" +window_auto_zoom = off +window_separator_horizontal = on +window_separator_vertical = on +window_title = "" +word_chars_highlight = "!\u00A0,-,_,|,@,.,alnum" +word_chars_input = "!\u00A0,-,_,|,alnum" + +[palette] + +[color] +bar_more = magenta +chat = default +chat_bg = default +chat_buffer = white +chat_channel = white +chat_day_change = cyan +chat_delimiters = green +chat_highlight = 207 +chat_highlight_bg = default +chat_host = cyan +chat_inactive_buffer = darkgray +chat_inactive_window = darkgray +chat_nick = lightcyan +chat_nick_colors = "027,048,068,028,081,082,099,112,129,136,169,178,208,226,113,196,161,23,59,222" +chat_nick_offline = darkgray +chat_nick_offline_highlight = default +chat_nick_offline_highlight_bg = darkgray +chat_nick_other = cyan +chat_nick_prefix = green +chat_nick_self = white +chat_nick_suffix = green +chat_prefix_action = white +chat_prefix_buffer = brown +chat_prefix_buffer_inactive_buffer = darkgray +chat_prefix_error = yellow +chat_prefix_join = lightgreen +chat_prefix_more = lightmagenta +chat_prefix_network = magenta +chat_prefix_quit = lightred +chat_prefix_suffix = green +chat_read_marker = green +chat_read_marker_bg = default +chat_server = brown +chat_tags = red +chat_text_found = yellow +chat_text_found_bg = lightmagenta +chat_time = 238 +chat_time_delimiters = 236 +chat_value = cyan +chat_value_null = blue +emphasized = yellow +emphasized_bg = magenta +input_actions = lightgreen +input_text_not_found = red +item_away = yellow +nicklist_away = cyan +nicklist_group = green +separator = green +status_count_highlight = magenta +status_count_msg = brown +status_count_other = 16 +status_count_private = green +status_data_highlight = lightmagenta +status_data_msg = yellow +status_data_other = 16 +status_data_private = lightgreen +status_filter = green +status_more = 16 +status_mouse = green +status_name = *16 +status_name_ssl = *16 +status_nicklist_count = default +status_number = 16 +status_time = *16 + +[completion] +base_word_until_cursor = on +command_inline = on +default_template = "%(nicks)|%(irc_channels)" +nick_add_space = on +nick_case_sensitive = off +nick_completer = ":" +nick_first_only = off +nick_ignore_chars = "[]`_-^" +partial_completion_alert = on +partial_completion_command = off +partial_completion_command_arg = off +partial_completion_count = on +partial_completion_other = off +partial_completion_templates = "config_options" + +[history] +display_default = 5 +max_buffer_lines_minutes = 0 +max_buffer_lines_number = 4096 +max_commands = 100 +max_visited_buffers = 50 + +[proxy] + +[network] +connection_timeout = 60 +gnutls_ca_system = on +gnutls_ca_user = "" +gnutls_handshake_timeout = 30 +proxy_curl = "" + +[plugin] +autoload = "*" +debug = off +extension = ".so" +path = "%h/plugins" +save_config_on_unload = on + +[signal] +sighup = "${if:${info:weechat_headless}?/reload:/quit -yes}" +sigquit = "/quit -yes" +sigterm = "/quit -yes" +sigusr1 = "" +sigusr2 = "" + +[bar] +buffers.color_bg = default +buffers.color_bg_inactive = default +buffers.color_delim = default +buffers.color_fg = default +buffers.conditions = "" +buffers.filling_left_right = vertical +buffers.filling_top_bottom = horizontal +buffers.hidden = on +buffers.items = "buffers" +buffers.position = left +buffers.priority = 0 +buffers.separator = on +buffers.size = 0 +buffers.size_max = 0 +buffers.type = root +buflist.color_bg = default +buflist.color_bg_inactive = default +buflist.color_delim = default +buflist.color_fg = default +buflist.conditions = "" +buflist.filling_left_right = vertical +buflist.filling_top_bottom = columns_vertical +buflist.hidden = off +buflist.items = "buflist" +buflist.position = left +buflist.priority = 0 +buflist.separator = on +buflist.size = 0 +buflist.size_max = 25 +buflist.type = root +fset.color_bg = default +fset.color_bg_inactive = default +fset.color_delim = cyan +fset.color_fg = default +fset.conditions = "${buffer.full_name} == fset.fset" +fset.filling_left_right = vertical +fset.filling_top_bottom = horizontal +fset.hidden = off +fset.items = "fset" +fset.position = top +fset.priority = 0 +fset.separator = on +fset.size = 3 +fset.size_max = 3 +fset.type = window +input.color_bg = default +input.color_bg_inactive = default +input.color_delim = green +input.color_fg = default +input.conditions = "" +input.filling_left_right = vertical +input.filling_top_bottom = horizontal +input.hidden = off +input.items = "[input_prompt]+(away),[input_search],[input_paste],input_text" +input.position = bottom +input.priority = 1000 +input.separator = off +input.size = 1 +input.size_max = 0 +input.type = window +nicklist.color_bg = default +nicklist.color_bg_inactive = default +nicklist.color_delim = cyan +nicklist.color_fg = default +nicklist.conditions = "nicklist" +nicklist.filling_left_right = vertical +nicklist.filling_top_bottom = columns_vertical +nicklist.hidden = on +nicklist.items = "buffer_nicklist" +nicklist.position = right +nicklist.priority = 200 +nicklist.separator = on +nicklist.size = 0 +nicklist.size_max = 0 +nicklist.type = window +status.color_bg = green +status.color_bg_inactive = default +status.color_delim = 0 +status.color_fg = 0 +status.conditions = "" +status.filling_left_right = vertical +status.filling_top_bottom = horizontal +status.hidden = off +status.items = "[time],buffer_number+:+buffer_name,buffer_title" +status.position = bottom +status.priority = 500 +status.separator = off +status.size = 1 +status.size_max = 0 +status.type = window +title.color_bg = green +title.color_bg_inactive = default +title.color_delim = cyan +title.color_fg = 16 +title.conditions = "" +title.filling_left_right = vertical +title.filling_top_bottom = horizontal +title.hidden = on +title.items = "buffer_title" +title.position = top +title.priority = 500 +title.separator = off +title.size = 1 +title.size_max = 0 +title.type = window + +[layout] + +[notify] +python.slack.10xgenomics.&cloud-alerts-pagerduty = highlight +python.slack.10xgenomics.&cloud-sumo-prod-support-alerts = highlight +python.slack.10xgenomics.&lacework-10xdev = highlight +python.slack.10xgenomics.&lacework-10xprod = highlight +python.slack.10xgenomics.&testing1234 = highlight + +[filter] +irc_smart = on;*;irc_smart_filter;* +nicks = on;*;irc_366;* + +[key] +ctrl-? = "/input delete_previous_char" +ctrl-A = "/input move_beginning_of_line" +ctrl-B = "/brows" +ctrl-Cb = "/input insert \x02" +ctrl-Cc = "/input insert \x03" +ctrl-Ci = "/input insert \x1D" +ctrl-Co = "/input insert \x0F" +ctrl-Cr = "/input insert \x12" +ctrl-Cu = "/input insert \x15" +ctrl-D = "/buffer close" +ctrl-E = "/input move_end_of_line" +ctrl-F = "/input move_next_char" +ctrl-H = "/input delete_previous_char" +ctrl-I = "/input complete_next" +ctrl-J = "/input jump_smart" +ctrl-K = "/input delete_end_of_line" +ctrl-L = "/window refresh" +ctrl-M = "/input return" +ctrl-N = "/buffer +1" +ctrl-O = "/editor" +ctrl-P = "/buffer -1" +ctrl-R = "/input search_text" +ctrl-Sctrl-U = "/input set_unread" +ctrl-T = "/input transpose_chars" +ctrl-U = "/url 1" +ctrl-W = "/input delete_previous_word" +ctrl-X = "/input switch_active_buffer" +ctrl-Y = "/input clipboard_paste" +meta-meta-OP = "/bar scroll buflist * b" +meta-meta-OQ = "/bar scroll buflist * e" +meta-meta2-11~ = "/bar scroll buflist * b" +meta-meta2-12~ = "/bar scroll buflist * e" +meta-meta2-1~ = "/window scroll_top" +meta-meta2-23~ = "/bar scroll nicklist * yb" +meta-meta2-24~ = "/bar scroll nicklist * ye" +meta-meta2-4~ = "/window scroll_bottom" +meta-meta2-5~ = "/window scroll_up" +meta-meta2-6~ = "/window scroll_down" +meta-meta2-7~ = "/window scroll_top" +meta-meta2-8~ = "/window scroll_bottom" +meta-meta2-A = "/buffer move -1" +meta-meta2-B = "/buffer move +1" +meta-meta2-C = "/buffer +1" +meta-meta2-D = "/buffer -1" +meta-0 = "/buffer *10" +meta-1 = "/buffer *1" +meta-2 = "/buffer *2" +meta-3 = "/buffer *3" +meta-4 = "/buffer *4" +meta-5 = "/buffer *5" +meta-6 = "/buffer *6" +meta-7 = "/buffer *7" +meta-8 = "/buffer *8" +meta-9 = "/buffer *9" +meta-< = "/input jump_previously_visited_buffer" +meta-= = "/filter toggle" +meta-> = "/input jump_next_visited_buffer" +meta-B = "/buflist toggle" +meta-OA = "/input history_global_previous" +meta-OB = "/input history_global_next" +meta-OC = "/input move_next_word" +meta-OD = "/input move_previous_word" +meta-OF = "/input move_end_of_line" +meta-OH = "/input move_beginning_of_line" +meta-OP = "/bar scroll buflist * -100%" +meta-OQ = "/bar scroll buflist * +100%" +meta-Oa = "/input history_global_previous" +meta-Ob = "/input history_global_next" +meta-Oc = "/input move_next_word" +meta-Od = "/input move_previous_word" +meta2-11^ = "/bar scroll buflist * -100%" +meta2-11~ = "/bar scroll buflist * -100%" +meta2-12^ = "/bar scroll buflist * +100%" +meta2-12~ = "/bar scroll buflist * +100%" +meta2-15~ = "/bar scroll nicklist * y-100%" +meta2-17~ = "/bar scroll nicklist * y+100%" +meta2-18~ = "/window -1" +meta2-19~ = "/window +1" +meta2-1;3A = "/buffer -1" +meta2-1;3B = "/buffer +1" +meta2-1;3C = "/buffer +1" +meta2-1;3D = "/buffer -1" +meta2-1;3P = "/bar scroll buflist * b" +meta2-1;3Q = "/bar scroll buflist * e" +meta2-1;5A = "/input history_global_previous" +meta2-1;5B = "/input history_global_next" +meta2-1;5P = "/bar scroll buflist * -100%" +meta2-1;5Q = "/bar scroll buflist * +100%" +meta2-1;9A = "/buffer move -1" +meta2-1;9B = "/buffer move +1" +meta2-1~ = "/input move_beginning_of_line" +meta2-20~ = "/bar scroll title * x-50%" +meta2-21~ = "/bar scroll title * x+50%" +meta2-23~ = "/bar scroll nicklist * y-100%" +meta2-24~ = "/bar scroll nicklist * y+100%" +meta2-3~ = "/input delete_next_char" +meta2-4~ = "/input move_end_of_line" +meta2-5;3~ = "/window scroll_up" +meta2-5~ = "/window page_up" +meta2-6;3~ = "/window scroll_down" +meta2-6~ = "/window page_down" +meta2-7~ = "/input move_beginning_of_line" +meta2-8~ = "/input move_end_of_line" +meta2-A = "/input history_previous" +meta2-B = "/input history_next" +meta2-C = "/input move_next_char" +meta2-D = "/input move_previous_char" +meta2-F = "/input move_end_of_line" +meta2-G = "/window page_down" +meta2-H = "/input move_beginning_of_line" +meta2-I = "/window page_up" +meta2-Z = "/input complete_previous" +meta-_ = "/input redo" +meta-a = "/input jump_smart" +meta-b = "/input move_previous_word" +meta-d = "/input delete_next_word" +meta-f = "/input move_next_word" +meta-h = "/input hotlist_clear" +meta-jmeta-l = "/input jump_last_buffer" +meta-jmeta-r = "/server raw" +meta-jmeta-s = "/server jump" +meta-j01 = "/buffer 1" +meta-j02 = "/buffer 2" +meta-j03 = "/buffer 3" +meta-j04 = "/buffer 4" +meta-j05 = "/buffer 5" +meta-j06 = "/buffer 6" +meta-j07 = "/buffer 7" +meta-j08 = "/buffer 8" +meta-j09 = "/buffer 9" +meta-j10 = "/buffer 10" +meta-j11 = "/buffer 11" +meta-j12 = "/buffer 12" +meta-j13 = "/buffer 13" +meta-j14 = "/buffer 14" +meta-j15 = "/buffer 15" +meta-j16 = "/buffer 16" +meta-j17 = "/buffer 17" +meta-j18 = "/buffer 18" +meta-j19 = "/buffer 19" +meta-j20 = "/buffer 20" +meta-j21 = "/buffer 21" +meta-j22 = "/buffer 22" +meta-j23 = "/buffer 23" +meta-j24 = "/buffer 24" +meta-j25 = "/buffer 25" +meta-j26 = "/buffer 26" +meta-j27 = "/buffer 27" +meta-j28 = "/buffer 28" +meta-j29 = "/buffer 29" +meta-j30 = "/buffer 30" +meta-j31 = "/buffer 31" +meta-j32 = "/buffer 32" +meta-j33 = "/buffer 33" +meta-j34 = "/buffer 34" +meta-j35 = "/buffer 35" +meta-j36 = "/buffer 36" +meta-j37 = "/buffer 37" +meta-j38 = "/buffer 38" +meta-j39 = "/buffer 39" +meta-j40 = "/buffer 40" +meta-j41 = "/buffer 41" +meta-j42 = "/buffer 42" +meta-j43 = "/buffer 43" +meta-j44 = "/buffer 44" +meta-j45 = "/buffer 45" +meta-j46 = "/buffer 46" +meta-j47 = "/buffer 47" +meta-j48 = "/buffer 48" +meta-j49 = "/buffer 49" +meta-j50 = "/buffer 50" +meta-j51 = "/buffer 51" +meta-j52 = "/buffer 52" +meta-j53 = "/buffer 53" +meta-j54 = "/buffer 54" +meta-j55 = "/buffer 55" +meta-j56 = "/buffer 56" +meta-j57 = "/buffer 57" +meta-j58 = "/buffer 58" +meta-j59 = "/buffer 59" +meta-j60 = "/buffer 60" +meta-j61 = "/buffer 61" +meta-j62 = "/buffer 62" +meta-j63 = "/buffer 63" +meta-j64 = "/buffer 64" +meta-j65 = "/buffer 65" +meta-j66 = "/buffer 66" +meta-j67 = "/buffer 67" +meta-j68 = "/buffer 68" +meta-j69 = "/buffer 69" +meta-j70 = "/buffer 70" +meta-j71 = "/buffer 71" +meta-j72 = "/buffer 72" +meta-j73 = "/buffer 73" +meta-j74 = "/buffer 74" +meta-j75 = "/buffer 75" +meta-j76 = "/buffer 76" +meta-j77 = "/buffer 77" +meta-j78 = "/buffer 78" +meta-j79 = "/buffer 79" +meta-j80 = "/buffer 80" +meta-j81 = "/buffer 81" +meta-j82 = "/buffer 82" +meta-j83 = "/buffer 83" +meta-j84 = "/buffer 84" +meta-j85 = "/buffer 85" +meta-j86 = "/buffer 86" +meta-j87 = "/buffer 87" +meta-j88 = "/buffer 88" +meta-j89 = "/buffer 89" +meta-j90 = "/buffer 90" +meta-j91 = "/buffer 91" +meta-j92 = "/buffer 92" +meta-j93 = "/buffer 93" +meta-j94 = "/buffer 94" +meta-j95 = "/buffer 95" +meta-j96 = "/buffer 96" +meta-j97 = "/buffer 97" +meta-j98 = "/buffer 98" +meta-j99 = "/buffer 99" +meta-k = "/input grab_key_command" +meta-n = "/window scroll_next_highlight" +meta-p = "/window scroll_previous_highlight" +meta-r = "/input delete_line" +meta-u = "/input scroll_unread" +meta-wmeta-meta2-A = "/window up" +meta-wmeta-meta2-B = "/window down" +meta-wmeta-meta2-C = "/window right" +meta-wmeta-meta2-D = "/window left" +meta-wmeta2-1;3A = "/window up" +meta-wmeta2-1;3B = "/window down" +meta-wmeta2-1;3C = "/window right" +meta-wmeta2-1;3D = "/window left" +meta-wmeta-b = "/window balance" +meta-wmeta-s = "/window swap" +meta-x = "/bar toggle nicklist" +meta-z = "/window zoom" +ctrl-_ = "/input undo" + +[key_search] +ctrl-J = "/input search_stop" +ctrl-M = "/input search_stop" +ctrl-R = "/input search_switch_case" +meta2-A = "/input search_previous" +meta2-B = "/input search_next" + +[key_cursor] +ctrl-J = "/cursor stop" +ctrl-M = "/cursor stop" +meta-meta2-A = "/cursor move area_up" +meta-meta2-B = "/cursor move area_down" +meta-meta2-C = "/cursor move area_right" +meta-meta2-D = "/cursor move area_left" +meta2-1;3A = "/cursor move area_up" +meta2-1;3B = "/cursor move area_down" +meta2-1;3C = "/cursor move area_right" +meta2-1;3D = "/cursor move area_left" +meta2-A = "/cursor move up" +meta2-B = "/cursor move down" +meta2-C = "/cursor move right" +meta2-D = "/cursor move left" +@chat(python.*):D = "hsignal:slack_cursor_delete" +@chat(python.*):L = "hsignal:slack_cursor_linkarchive" +@chat(python.*):M = "hsignal:slack_cursor_message" +@chat(python.*):R = "hsignal:slack_cursor_reply" +@chat(python.*):T = "hsignal:slack_cursor_thread" +@item(buffer_nicklist):K = "/window ${_window_number};/kickban ${nick}" +@item(buffer_nicklist):b = "/window ${_window_number};/ban ${nick}" +@item(buffer_nicklist):k = "/window ${_window_number};/kick ${nick}" +@item(buffer_nicklist):q = "/window ${_window_number};/query ${nick};/cursor stop" +@item(buffer_nicklist):w = "/window ${_window_number};/whois ${nick}" +@chat:Q = "hsignal:chat_quote_time_prefix_message;/cursor stop" +@chat:m = "hsignal:chat_quote_message;/cursor stop" +@chat:q = "hsignal:chat_quote_prefix_message;/cursor stop" + +[key_mouse] +@bar(buflist):ctrl-wheeldown = "hsignal:buflist_mouse" +@bar(buflist):ctrl-wheelup = "hsignal:buflist_mouse" +@bar(input):button2 = "/input grab_mouse_area" +@bar(nicklist):button1-gesture-down = "/bar scroll nicklist ${_window_number} +100%" +@bar(nicklist):button1-gesture-down-long = "/bar scroll nicklist ${_window_number} e" +@bar(nicklist):button1-gesture-up = "/bar scroll nicklist ${_window_number} -100%" +@bar(nicklist):button1-gesture-up-long = "/bar scroll nicklist ${_window_number} b" +@chat(fset.fset):button1 = "/window ${_window_number};/fset -go ${_chat_line_y}" +@chat(fset.fset):button2* = "hsignal:fset_mouse" +@chat(fset.fset):wheeldown = "/fset -down 5" +@chat(fset.fset):wheelup = "/fset -up 5" +@chat(python.*):button2 = "hsignal:slack_mouse" +@chat(script.scripts):button1 = "/window ${_window_number};/script go ${_chat_line_y}" +@chat(script.scripts):button2 = "/window ${_window_number};/script go ${_chat_line_y};/script installremove -q ${script_name_with_extension}" +@chat(script.scripts):wheeldown = "/script down 5" +@chat(script.scripts):wheelup = "/script up 5" +@item(buffer_nicklist):button1 = "/window ${_window_number};/query ${nick}" +@item(buffer_nicklist):button1-gesture-left = "/window ${_window_number};/kick ${nick}" +@item(buffer_nicklist):button1-gesture-left-long = "/window ${_window_number};/kickban ${nick}" +@item(buffer_nicklist):button2 = "/window ${_window_number};/whois ${nick}" +@item(buffer_nicklist):button2-gesture-left = "/window ${_window_number};/ban ${nick}" +@item(buffers):button1* = "hsignal:buffers_mouse" +@item(buffers):button2* = "hsignal:buffers_mouse" +@item(buflist):button1* = "hsignal:buflist_mouse" +@item(buflist):button2* = "hsignal:buflist_mouse" +@item(buflist2):button1* = "hsignal:buflist_mouse" +@item(buflist2):button2* = "hsignal:buflist_mouse" +@item(buflist3):button1* = "hsignal:buflist_mouse" +@item(buflist3):button2* = "hsignal:buflist_mouse" +@bar:wheeldown = "/bar scroll ${_bar_name} ${_window_number} +20%" +@bar:wheelup = "/bar scroll ${_bar_name} ${_window_number} -20%" +@chat:button1 = "/window ${_window_number}" +@chat:button1-gesture-left = "/window ${_window_number};/buffer -1" +@chat:button1-gesture-left-long = "/window ${_window_number};/buffer 1" +@chat:button1-gesture-right = "/window ${_window_number};/buffer +1" +@chat:button1-gesture-right-long = "/window ${_window_number};/input jump_last_buffer" +@chat:wheeldown = "/window scroll_down -window ${_window_number}" +@chat:wheelup = "/window scroll_up -window ${_window_number}" +@*:button3 = "/cursor go ${_x},${_y}" diff -r 93d27886c099 -r 62e329839625 weechat-old/xfer.conf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/weechat-old/xfer.conf Wed Aug 27 16:19:24 2025 -0400 @@ -0,0 +1,49 @@ +# +# weechat -- xfer.conf +# +# WARNING: It is NOT recommended to edit this file by hand, +# especially if WeeChat is running. +# +# Use commands like /set or /fset to change settings in WeeChat. +# +# For more info, see: https://weechat.org/doc/quickstart/ +# + +[look] +auto_open_buffer = on +progress_bar_size = 20 +pv_tags = "notify_private" + +[color] +status_aborted = lightred +status_active = lightblue +status_connecting = yellow +status_done = lightgreen +status_failed = lightred +status_waiting = lightcyan +text = default +text_bg = default +text_selected = white + +[network] +blocksize = 65536 +fast_send = on +own_ip = "" +port_range = "" +send_ack = on +speed_limit_recv = 0 +speed_limit_send = 0 +timeout = 300 + +[file] +auto_accept_chats = off +auto_accept_files = off +auto_accept_nicks = "" +auto_check_crc32 = off +auto_rename = on +auto_resume = on +convert_spaces = on +download_path = "%h/xfer" +download_temporary_suffix = ".part" +upload_path = "~" +use_nick_in_filename = on diff -r 93d27886c099 -r 62e329839625 weechat/.agignore --- a/weechat/.agignore Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -logs/ -urls.log diff -r 93d27886c099 -r 62e329839625 weechat/GandiStandardSSLCA.crt Binary file weechat/GandiStandardSSLCA.crt has changed diff -r 93d27886c099 -r 62e329839625 weechat/alias.conf --- a/weechat/alias.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -# -# weechat -- alias.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[cmd] -AAWAY = "allserv /away" -AME = "allchan /me" -AMSG = "allchan /msg *" -ANICK = "allserv /nick" -b = "/buffer" -BYE = "quit" -C = "buffer clear" -CHAT = "dcc chat" -CL = "buffer clear" -CLOSE = "buffer close" -EXIT = "quit" -IG = "ignore" -J = "join" -K = "kick" -KB = "kickban" -LEAVE = "part" -M = "msg" -MUB = "unban *" -N = "names" -Q = "query" -REDRAW = "window refresh" -SAY = "msg *" -SIGNOFF = "quit" -T = "topic" -UB = "unban" -V = "command core version" -W = "who" -WC = "window merge" -WI = "whois" -WII = "whois $1 $1" -WW = "whowas" - -[completion] diff -r 93d27886c099 -r 62e329839625 weechat/aspell.conf --- a/weechat/aspell.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -# -# weechat -- aspell.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use /set or similar command to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart -# - -[color] -misspelled = lightred -suggestion = default -suggestion_delimiter_dict = cyan -suggestion_delimiter_word = cyan - -[check] -commands = "ame,amsg,away,command,cycle,kick,kickban,me,msg,notice,part,query,quit,topic" -default_dict = "en" -during_search = off -enabled = off -real_time = off -suggestions = -1 -word_min_length = 2 - -[dict] - -[look] -suggestion_delimiter_dict = " / " -suggestion_delimiter_word = "," - -[option] diff -r 93d27886c099 -r 62e329839625 weechat/autosort.conf --- a/weechat/autosort.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -# -# weechat -- autosort.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[sorting] -case_sensitive = off -debug_log = off -replacements = "[]" -rules = "[["core", 0], ["irc", 2], ["*", 1], ["irc.irc_raw", 0], ["irc.server", 1]]" -signal_delay = 5 -signals = "buffer_opened buffer_merged buffer_unmerged buffer_renamed" -sort_limit = 100 -sort_on_config_change = on - -[v3] -helpers = "{"core_first": "${if:${buffer.full_name}!=core.weechat}", "irc_raw_first": "${if:${buffer.full_name}!=irc.irc_raw}", "irc_raw_last": "${if:${buffer.full_name}==irc.irc_raw}", "hashless_name": "${info:autosort_replace,#,,${info:autosort_escape,${buffer.name}}}", "script_or_plugin": "${if:${script_name}?${script_name}:${plugin}}"}" -rules = "["${core_first}", "${info:autosort_order,${info:autosort_escape,${script_or_plugin}},core,*,irc,bitlbee,matrix,slack}", "${script_or_plugin}", "${irc_raw_first}", "${server}", "${info:autosort_order,${type},server,*,channel,private}", "${hashless_name}", "${buffer.full_name}"]" diff -r 93d27886c099 -r 62e329839625 weechat/buffers.conf --- a/weechat/buffers.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -# -# weechat -- buffers.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use /set or similar command to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart -# - -[color] -current_bg = green -current_fg = black -default_bg = default -default_fg = default -hotlist_highlight_bg = default -hotlist_highlight_fg = *magenta -hotlist_low_bg = default -hotlist_low_fg = white -hotlist_message_bg = default -hotlist_message_fg = green -hotlist_private_bg = default -hotlist_private_fg = *magenta -none_channel_bg = default -none_channel_fg = 240 -number = green -number_char = green -prefix_bufname = default -queries_default_bg = default -queries_default_fg = default -queries_highlight_bg = default -queries_highlight_fg = default -queries_message_bg = default -queries_message_fg = default -suffix_bufname = default -whitelist_default_bg = default -whitelist_default_fg = default -whitelist_highlight_bg = default -whitelist_highlight_fg = default -whitelist_low_bg = default -whitelist_low_fg = default -whitelist_message_bg = default -whitelist_message_fg = default -whitelist_private_bg = default -whitelist_private_fg = default - -[look] -core_to_front = off -detach = 0 -detach_buffer_immediately = "" -detach_display_window_number = off -detach_displayed_buffers = on -detach_free_content = off -detach_query = off -hide_merged_buffers = none -hotlist_counter = off -immune_detach_buffers = "" -indenting = on -indenting_number = on -jump_prev_next_visited_buffer = off -mark_inactive = off -mouse_move_buffer = on -name_crop_suffix = "+" -name_size_max = 0 -number_char = " " -prefix = off -prefix_bufname = "" -prefix_empty = on -prefix_for_query = "" -short_names = on -show_lag = off -show_number = on -sort = number -suffix_bufname = "" -toogle_bar = on -whitelist_buffers = "" diff -r 93d27886c099 -r 62e329839625 weechat/buflist.conf --- a/weechat/buflist.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -# -# weechat -- buflist.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[look] -add_newline = on -auto_scroll = 50 -display_conditions = "${buffer.hidden}==0" -enabled = on -mouse_jump_visited_buffer = off -mouse_move_buffer = on -mouse_wheel = on -nick_prefix = off -nick_prefix_empty = on -signals_refresh = "" -sort = "number,-active" -use_items = 1 - -[format] -buffer = "${format_number}${indent}${format_nick_prefix}${color_hotlist}${format_name}" -buffer_current = "${color:,blue}${format_buffer}" -hotlist = " ${color:green}(${hotlist}${color:green})" -hotlist_highlight = "${color:magenta}" -hotlist_low = "${color:white}" -hotlist_message = "${color:green}" -hotlist_none = "${color:default}" -hotlist_private = "${color:magenta}" -hotlist_separator = "${color:default}," -indent = " " -lag = " ${color:green}[${color:brown}${lag}${color:green}]" -name = "${name}" -nick_prefix = "${color_nick_prefix}${nick_prefix}" -number = "${color:green}${number}${if:${number_displayed}?.: }" -tls_version = " ${color:default}(${if:${tls_version}==TLS1.3?${color:green}:${if:${tls_version}==TLS1.2?${color:yellow}:${color:red}}}${translate:${tls_version}}${color:default})" diff -r 93d27886c099 -r 62e329839625 weechat/charset.conf --- a/weechat/charset.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -# -# weechat -- charset.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[default] -decode = "iso-8859-1" -encode = "" - -[decode] - -[encode] diff -r 93d27886c099 -r 62e329839625 weechat/exec.conf --- a/weechat/exec.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -# -# weechat -- exec.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[command] -default_options = "" -purge_delay = 0 -shell = "${env:SHELL}" - -[color] -flag_finished = lightred -flag_running = lightgreen diff -r 93d27886c099 -r 62e329839625 weechat/fifo.conf --- a/weechat/fifo.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -# -# weechat -- fifo.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[file] -enabled = on -path = "%h/weechat_fifo" diff -r 93d27886c099 -r 62e329839625 weechat/fset.conf --- a/weechat/fset.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -# -# weechat -- fset.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[look] -auto_refresh = "*" -auto_unmark = off -condition_catch_set = "${count} >= 1" -export_help_default = on -format_number = 1 -marked_string = "*" -scroll_horizontal = 10 -show_plugins_desc = off -sort = "~name" -unmarked_string = " " -use_color_value = off -use_keys = on -use_mute = off - -[format] -export_help = "# ${description2}" -export_option = "/set ${name} ${quoted_value}" -export_option_null = "/unset ${name}" -option1 = "" -option2 = "${marked} ${name} ${type} ${value2}${newline} ${empty_name} ${_default_value}${color:darkgray} -- ${min}..${max}${newline} ${empty_name} ${description}" - -[color] -default_value = default -default_value_selected = white -description = default -description_selected = white -file = default -file_changed = brown -file_changed_selected = yellow -file_selected = white -help_default_value = white -help_description = default -help_name = white -help_quotes = darkgray -help_values = default -index = cyan -index_selected = lightcyan -line_marked_bg1 = default -line_marked_bg2 = default -line_selected_bg1 = blue -line_selected_bg2 = red -marked = brown -marked_selected = yellow -max = default -max_selected = white -min = default -min_selected = white -name = default -name_changed = brown -name_changed_selected = yellow -name_selected = white -option = default -option_changed = brown -option_changed_selected = yellow -option_selected = white -parent_name = default -parent_name_selected = white -parent_value = cyan -parent_value_selected = lightcyan -quotes = darkgray -quotes_changed = default -quotes_changed_selected = white -quotes_selected = default -section = default -section_changed = brown -section_changed_selected = yellow -section_selected = white -string_values = default -string_values_selected = white -title_count_options = cyan -title_current_option = lightcyan -title_filter = yellow -title_marked_options = lightgreen -title_sort = white -type = green -type_selected = lightgreen -unmarked = default -unmarked_selected = white -value = cyan -value_changed = brown -value_changed_selected = yellow -value_selected = lightcyan -value_undef = magenta -value_undef_selected = lightmagenta diff -r 93d27886c099 -r 62e329839625 weechat/icon.png Binary file weechat/icon.png has changed diff -r 93d27886c099 -r 62e329839625 weechat/logger.conf --- a/weechat/logger.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -# -# weechat -- logger.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[look] -backlog = 20 -backlog_conditions = "" - -[color] -backlog_end = darkgray -backlog_line = darkgray - -[file] -auto_log = on -color_lines = off -flush_delay = 120 -fsync = off -info_lines = off -mask = "$plugin.$name.weechatlog" -name_lower_case = on -nick_prefix = " <" -nick_suffix = "> " -path = "%h/logs/" -replacement_char = "_" -time_format = "%Y-%m-%d %H:%M:%S" - -[level] - -[mask] diff -r 93d27886c099 -r 62e329839625 weechat/lua.conf --- a/weechat/lua.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -# -# weechat -- lua.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use /set or similar command to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart -# - -[look] -check_license = off -eval_keep_context = on diff -r 93d27886c099 -r 62e329839625 weechat/perl.conf --- a/weechat/perl.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -# -# weechat -- perl.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart -# - -[look] -check_license = off -eval_keep_context = on diff -r 93d27886c099 -r 62e329839625 weechat/perl/autoload/colorize_lines.pl --- a/weechat/perl/autoload/colorize_lines.pl Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,251 +0,0 @@ -# -# Copyright (c) 2010-2013 by Nils Görs <weechatter@arcor.de> -# Copyleft (ɔ) 2013 by oakkitten -# -# colors the channel text with nick color and also highlight the whole line -# colorize_nicks.py script will be supported -# -# 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 <http://www.gnu.org/licenses/>. -# -# with version 3.0 some options were renamed or have new possible values: -# old: new: -# avail_buffer buffer -# blacklist_channels blacklist_buffers -# highlight new values - -# obsolete options: -# buffer_autoset -# hotlist_max_level_nicks_add -# highlight_regex -# highlight_words -# shuffle -# chat see option highlight - -# history: -# 3.0: large part of script rewritten -# fix: works nicely with irc colors -# improved: highlight_regex and highlight_words work in a natural way -# removed: command /colorize_lines -# removed: option shuffle -# 2.2: fix: regex with [tab] in message (patch by sqrrl) -# 2.1: fix: changing highlight color did not apply messages already displayed (reported by rafi_) -# 2.0: fix: debugging weechat::print() removed (thanks demure) -# 1.9: fix: display bug with nick_mode -# 1.8 add: option "use_irc_colors" (requested by Zertap) -# fix: empty char for nick_mode was used, even when "irc.look.nick_mode_empty" was OFF (reported by FlashCode) -# 1.7: fix: broken lines in dcc chat (reported by equatorping) -# 1.6: improved: wildcard "*" can be used for server and/or nick. (requested by ldvx) -# : add: new value, "only", for option "own_lines" (read help!) -# 1.5: sync: option weechat.look.nickmode changed in 0.3.9 to "irc.look.nick_mode" -# 1.4: fix: whole ctcp message was display in prefix (reported by : Mkaysi) -# 1.3: fix: now using weechat::buffer_get_string() instead of regex to prevent problems with dots inside server-/channelnames (reported by surfhai) -# 1.2: add: hook_modifier("colorize_lines") to use colorize_lines with another script. -# : fix: regex was too greedy and also hit tag "prefix_nick_ccc" -# 1.1: fix: problems with temporary server (reported by nand`) -# : improved: using weechat_string_has_highlight() -# 1.0: fix: irc.look.nick_prefix wasn't supported -# 0.9: added: option "own_nick" (idea by travkin) -# : new value (always) for option highlight -# : clean up code -# 0.8.1: fix: regex() -# 0.8: added: option "avail_buffer" and "nicks" (please read help-page) (suggested by ldvx) -# : fix: blacklist_buffers wasn't load at start -# : fix: nick_modes wasn't displayed since v0.7 -# : rewrote init() routine -# : thanks to stfn for hint with unescaped variables in regex. -# 0.7: fix: bug when irc.look.nick_suffix was set (reported and beta-testing by: hw2) (>= weechat 0.3.4) -# blacklist_buffers option supports servername -# clean up code -# 0.6: code optimazations. -# rename of script (rainbow_text.pl -> colorize_lines.pl) (suggested by xt and flashcode) -# 0.5: support of hotlist_max_level_nicks_add and weechat.color.chat_nick_colors (>= weechat 0.3.4) -# 0.4: support of weechat.look.highlight_regex option (>= weechat 0.3.4) -# : support of weechat.look.highlight option -# : highlighted line did not work with "." inside servername -# ; internal "autoset" function fixed -# 0.3: support of colorize_nicks.py implemented. -# : /me text displayed wrong nick colour (colour from suffix was used) -# : highlight messages will be checked case insensitiv -# 0.2: supports highlight_words_add from buffer_autoset.py script (suggested: Emralegna) -# : correct look_nickmode colour will be used (bug reported by: Emralegna) -# : /me text will be coloured, too -# 0.1: initial release -# -# Development is currently hosted at -# https://github.com/weechatter/weechat-scripts - -# use Data::Dumper -# $Data::Dumper::Useqq=1; - -use strict; -my $prgname = "colorize_lines"; -my $version = "3.0"; -my $description = "colors text in chat area with according nick color, including highlights"; - -my %config = ("buffers" => "all", # all, channel, query - "blacklist_buffers" => "", # "a,b,c" - "lines" => "on", - "highlight" => "on", # on, off, nicks - "nicks" => "", # "d,e,f", "/file" - "own_lines" => "on", # on, off, only -); - -my %help_desc = ("buffers" => "buffer type affected by the script (all/channel/query, default: all)", - "blacklist_buffers" => "comma-separated list of channels to be ignored (e.g. freenode.#weechat,*.#python)", - "lines" => "apply nickname color to the non-highlighted lines (off/on/nicks). the latter will limit highlighting to nicknames in option 'nicks'", - "highlight" => "apply highlight color to the highlighted lines (off/on/nicks). the latter will limit highlighting to nicknames in option 'nicks'", - "nicks" => "comma-separater list of nicks (e.g. freenode.cat,*.dog) OR file name starting with '/' (e.g. /file.txt). in the latter case, nicknames will get loaded from that file inside weechat folder (e.g. from ~/.weechat/file.txt). nicknames in file are newline-separated (e.g. freenode.dog\\n*.cat)", - "own_lines" => "apply nickname color to own lines (off/on/only). the latter turns off all other kinds of coloring altogether", -); - -#################################################################################################### config - -# program starts here -sub colorize_cb { - my ( $data, $modifier, $modifier_data, $string ) = @_; - - # quit if it's not a privmsg or ctcp - # or we are not supposed to - if ((index($modifier_data,"irc_privmsg") == -1) || - (index($modifier_data,"irc_ctcp") >= 0)) { - return $string; - } - - # find buffer pointer - $modifier_data =~ m/([^;]*);([^;]*);/; - my $buffer = weechat::buffer_search($1, $2); - return $string if ($buffer eq ""); - - # find buffer name, server name - # return if buffer is in a blacklist - my $buffername = weechat::buffer_get_string($buffer, "name"); - return $string if weechat::string_has_highlight($buffername, $config{blacklist_buffers}); - my $servername = weechat::buffer_get_string($buffer, "localvar_server"); - - # find stuff between \t - $string =~ m/^([^\t]*)\t(.*)/; - my $left = $1; - my $right = $2; - - # find nick of the sender - # find out if we are doing an action - my $nick = ($modifier_data =~ m/(^|,)nick_([^,]*)/) ? $2 : weechat::string_remove_color($left, ""); - my $action = ($modifier_data =~ m/\birc_action\b/) ? 1 : 0; - - ######################################## get color - - my $color = ""; - my $my_nick = weechat::buffer_get_string($buffer, "localvar_nick"); - if ($my_nick eq $nick) { - # it's our own line - # process only if own_lines is "on" or "only" (i.e. not "off") - return $string if ($config{own_lines} eq "off"); - $color = weechat::color("chat_nick_self"); - } else { - # it's someone else's line - # don't process is own_lines are "only" - # in order to get correct matching, remove colors from the string - return $string if ($config{own_lines} eq "only"); - my $right_nocolor = weechat::string_remove_color($right, ""); - if (weechat::string_has_highlight($right_nocolor, weechat::buffer_string_replace_local_var($buffer, weechat::buffer_get_string($buffer, "highlight_words"))) || - weechat::string_has_highlight($right_nocolor, weechat::config_string(weechat::config_get("weechat.look.highlight"))) || - weechat::string_has_highlight_regex($right_nocolor, weechat::config_string(weechat::config_get("weechat.look.highlight_regex"))) || - weechat::string_has_highlight_regex($right_nocolor, weechat::buffer_get_string($buffer, "highlight_regex")) - ) { - # we have a hilight! get a hilight color - # and replace the first occurance of coloring, that'd be nick color - # process only if highlight is "on" OR "nicks" & nick's in nicks - return $string if ($config{highlight} eq "off" || - ($config{highlight} eq "nicks" && !weechat::string_has_highlight("$servername.$nick", $config{nicks}))); - $color = weechat::color('chat_highlight'); - $right =~ s/\31[^\31 ]+?\Q$nick/$color$nick/ if ($action); - } else { - # that's not a highlight - # process only if lines is "on" OR "nicks" & nick's in nicks - return $string if ($config{lines} eq "off" || - ($config{lines} eq "nicks" && !weechat::string_has_highlight("$servername.$nick", $config{nicks}))); - $color = weechat::info_get('irc_nick_color', $nick); - } - } - - ######################################## inject colors and go! - - my $out = ""; - if ($action) { - # remove the first color reset - after * nick - # make other resets reset to our color - $right =~ s/\34//; - $right =~ s/\34/\34$color/g; - $out = $left . "\t" . $right . "\34" - } else { - # make other resets reset to our color - $right =~ s/\34/\34$color/g; - $out = $left . "\t" . $color . $right . "\34" - } - #weechat::print("", ""); weechat::print("", "\$str " . Dumper($string)); weechat::print("", "\$out " . Dumper($out)); - return $out; -} - -#################################################################################################### config - -# read nicknames if $conf{nisks} starts with / -# after this, $conf{nisks} is of form a,b,c,d -# if it doesnt start with /, assume it's already a,b,c,d -sub nicklist_read { - return if (substr($config{nicks}, 0, 1) ne "/"); - my $file = weechat::info_get("weechat_dir", "") . $config{nicks}; - return unless -e $file; - my $nili = ""; - open (WL, "<", $file) || DEBUG("$file: $!"); - while (<WL>) { - chomp; # kill LF - $nili .= $_ . ","; - } - close WL; - chop $nili; # remove last "," - $config{nicks} = $nili; -} - -# called when a config option ha been changed -# $name = plugins.var.perl.$prgname.nicks etc -sub toggle_config_by_set { - my ($pointer, $name, $value) = @_; - $name = substr($name,length("plugins.var.perl.$prgname."),length($name)); - $config{$name} = lc($value); - nicklist_read() if ($name eq "nicks"); -} - -# read configuration from weechat OR -# set default options and -# set dectription if weechat >= 0.3.5 -# after done, read nicklist from file if needed -sub init_config { - my $weechat_version = weechat::info_get('version_number', '') || 0; - foreach my $option (keys %config){ - if (!weechat::config_is_set_plugin($option)) { - weechat::config_set_plugin($option, $config{$option}); - weechat::config_set_desc_plugin($option, $help_desc{$option}) if ($weechat_version >= 0x00030500); # v0.3.5 - } else { - $config{$option} = lc(weechat::config_get_plugin($option)); - } - } - nicklist_read(); -} - -#################################################################################################### start - -weechat::register($prgname, "Nils Görs <weechatter\@arcor.de>", $version, "GPL3", $description, "", ""); -weechat::hook_modifier("500|weechat_print","colorize_cb", ""); -init_config(); -weechat::hook_config("plugins.var.perl.$prgname.*", "toggle_config_by_set", ""); diff -r 93d27886c099 -r 62e329839625 weechat/python.conf --- a/weechat/python.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -# -# weechat -- python.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[look] -check_license = off -eval_keep_context = on diff -r 93d27886c099 -r 62e329839625 weechat/python/autoload/autosort.py --- a/weechat/python/autoload/autosort.py Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../autosort.py \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 weechat/python/autoload/brows.py --- a/weechat/python/autoload/brows.py Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -import subprocess -import os - -SCRIPT_NAME = 'brows' -SCRIPT_AUTHOR = 'Steve Losh <steve@stevelosh.com>' -SCRIPT_VERSION = '1.0' -SCRIPT_LICENSE = 'MIT/X11' -SCRIPT_DESC = 'Launch brows to view URLs' -SCRIPT_COMMAND = 'brows' - -import_ok = True - -BROWS = os.environ.get('BROWS', 'brows') - -try: - import weechat -except ImportError: - print('This is a weechat script, what are you doing, run it in weechat, jesus') - import_ok = False - -weechat_version = 0 - -def hd(fn, name, obj, attr): - return fn(weechat.hdata_get(name), obj, attr) - -def hdp(name, obj, attr): - return hd(weechat.hdata_pointer, name, obj, attr) - -def hds(name, obj, attr): - return hd(weechat.hdata_string, name, obj, attr) - -def get_lines(buffer, numlines): - lines = hdp("buffer", buffer, "own_lines") - if not lines: - # null pointer wat do - return None - - last_lines = [] - - line = hdp("lines", lines, "last_line") - for _ in range(numlines): - if not line: - # shit we're at the top of the buffer - break - - data = hdp("line", line, "data") - msg = hds("line_data", data, "message") - msg = weechat.string_remove_color(msg, "") - - last_lines.append(msg.strip()) - - line = hdp("line", line, "prev_line") - - return last_lines - -def brows(data, buffer, args, numlines=100): - lines = get_lines(buffer, numlines) - - proc = subprocess.Popen([BROWS], stdin=subprocess.PIPE) - proc.communicate(input='\n'.join(lines)) - weechat.command("", "/window refresh") - - return weechat.WEECHAT_RC_OK - - -if __name__ == '__main__' and import_ok: - if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, - SCRIPT_LICENSE, SCRIPT_DESC, '', ''): - weechat_version = weechat.info_get('version_number', '') or 0 - weechat.hook_command( - SCRIPT_COMMAND, - 'Launch brows to view URLs', - '', - '', - '', - 'brows', - '') diff -r 93d27886c099 -r 62e329839625 weechat/python/autoload/editor.py --- a/weechat/python/autoload/editor.py Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -import subprocess -import os -import tempfile - -SCRIPT_NAME = 'editor' -SCRIPT_AUTHOR = 'Steve Losh <steve@stevelosh.com>' -SCRIPT_VERSION = '1.0' -SCRIPT_LICENSE = 'MIT/X11' -SCRIPT_DESC = 'Launch an external editor to compose a message' -SCRIPT_COMMAND = 'editor' - -import_ok = True - -EDITOR = os.environ.get('EDITOR','vim') - -try: - import weechat -except ImportError: - print('This is a weechat script, what are you doing, run it in weechat, jesus') - import_ok = False - -weechat_version = 0 - - -def get_data(suffix, initial_data): - with tempfile.NamedTemporaryFile(suffix=".%s" % suffix, mode="w+") as tf: - tf.write(initial_data) - tf.flush() - - if subprocess.call([EDITOR, tf.name]) != 0: - return None - - # Reopen, because most editors do atomic write-tmp+rename saves which - # fucks with Python here. - tf.file.close() - with open(tf.name) as tf2: - return tf2.read() - -def editor(data, buffer, args): - suffix = args or "tmp" - - line = weechat.buffer_get_string(buffer, "input") - - data = get_data(suffix, line) - if data: - weechat.command(buffer, "/input delete_line") - weechat.command(buffer, data.strip()) - - weechat.command("", "/window refresh") - - return weechat.WEECHAT_RC_OK - - -if __name__ == '__main__' and import_ok: - if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, - SCRIPT_LICENSE, SCRIPT_DESC, '', ''): - weechat_version = weechat.info_get('version_number', '') or 0 - weechat.hook_command( - SCRIPT_COMMAND, - 'Open $EDITOR to compose a message', - '[file-extension]', - 'If an argument is given, it will be used as the extension for the temporary file.', - '', - 'editor', - '') diff -r 93d27886c099 -r 62e329839625 weechat/python/autoload/notify.py --- a/weechat/python/autoload/notify.py Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -import weechat, subprocess - -SCRIPT_NAME = 'notify' -SCRIPT_AUTHOR = 'Steve Losh <steve@stevelosh.com>' -SCRIPT_VERSION = '0.0.1' -SCRIPT_LICENSE = 'MIT' -SCRIPT_DESC = 'notify-send for weechat' - -weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, '', '') - -weechat.hook_print('', 'irc_privmsg', '', 1, 'notify', '') - -def _notify(text): - subprocess.call(['notify-send', text]) - -def notify(data, buffer, date, tags, displayed, highlight, prefix, message): - # ignore if it's yourself - own_nick = weechat.buffer_get_string(buffer, 'localvar_nick') - - if prefix == own_nick or prefix == ('@%s' % own_nick): - return weechat.WEECHAT_RC_OK - - if int(highlight): - channel = weechat.buffer_get_string(buffer, 'localvar_channel') - _notify('%s %s\n%s' % (prefix, channel, message)) - elif 'notify_private' in tags: - _notify('%s [PM]\n%s' % (prefix, message)) - - return weechat.WEECHAT_RC_OK diff -r 93d27886c099 -r 62e329839625 weechat/python/autoload/quotes.py --- a/weechat/python/autoload/quotes.py Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -import subprocess, os - -SCRIPT_NAME = 'quotes' -SCRIPT_AUTHOR = 'Steve Losh <steve@stevelosh.com>' -SCRIPT_VERSION = '1.0' -SCRIPT_LICENSE = 'MIT/X11' -SCRIPT_DESC = 'Grab quotes and shove them into a text file.' -SCRIPT_COMMAND = 'quo' -SCRIPT_COMMAND_LONG = 'quoo' -SCRIPT_COMMAND_COPY = 'cop' - -HOME = os.getenv("HOME") -QUOTE_FILE = '%s/Dropbox/quotes.txt' % HOME -COPY_FILE = '%s/.ircopy.irc' % HOME - -import_ok = True - -try: - import weechat -except ImportError: - print('This is a weechat script, what are you doing, run it in weechat, jesus') - import_ok = False - -weechat_version = 0 - -def hd(fn, name, obj, attr): - return fn(weechat.hdata_get(name), obj, attr) - -def hdp(name, obj, attr): - return hd(weechat.hdata_pointer, name, obj, attr) - -def hds(name, obj, attr): - return hd(weechat.hdata_string, name, obj, attr) - -def get_lines(buffer, numlines): - lines = hdp("buffer", buffer, "own_lines") - if not lines: - # null pointer wat do - return None - - last_lines = [] - - line = hdp("lines", lines, "last_line") - for _ in range(numlines): - if not line: - # shit we're at the top of the buffer - break - - data = hdp("line", line, "data") - msg = hds("line_data", data, "message") - pre = hds("line_data", data, "prefix") - - msg = weechat.string_remove_color(msg, "") - pre = weechat.string_remove_color(pre, "") - - last_lines.append("<%s> %s" % (pre.strip(), msg.strip())) - - line = hdp("line", line, "prev_line") - - last_lines.reverse() - return last_lines - -def quote_grab(data, buffer, args, numlines=15): - lines = get_lines(buffer, numlines) - - with open(QUOTE_FILE, 'a') as f: - f.write("\n---\n") - f.write('\n'.join(lines)) - - subprocess.call(["nvim", QUOTE_FILE, - # start at the bottom of the file - "+", - # move up N lines, where N is how many we appended - "-c", "normal! %dk" % len(lines)]) - weechat.command("", "/window refresh") - - return weechat.WEECHAT_RC_OK - -def quote_grab_long(data, buffer, args): - return quote_grab(data, buffer, args, 75) - -def quote_grab_copy(data, buffer, args): - lines = get_lines(buffer, 1000) - - with open(COPY_FILE, 'w') as f: - f.write('\n'.join(lines)) - - subprocess.call(["nvim", COPY_FILE, - # start at the bottom of the file - "+"]) - weechat.command("", "/window refresh") - - return weechat.WEECHAT_RC_OK - -if __name__ == '__main__' and import_ok: - if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, - SCRIPT_LICENSE, SCRIPT_DESC, '', ''): - weechat_version = weechat.info_get('version_number', '') or 0 - weechat.hook_command( - SCRIPT_COMMAND, - 'Appends the last 15 lines of the current buffer to your quotes ' - 'file and opens it in Vim so you can trim it.', - '', - '', - '', - 'quote_grab', - '') - weechat.hook_command( - SCRIPT_COMMAND_LONG, - 'Appends the last 75 lines of the current buffer to your quotes ' - 'file and opens it in Vim so you can trim it.', - '', - '', - '', - 'quote_grab_long', - '') - weechat.hook_command( - SCRIPT_COMMAND_COPY, - 'Open the last 1000 lines of the file in Vim so you can copy.', - '', - '', - '', - 'quote_grab_copy', - '') diff -r 93d27886c099 -r 62e329839625 weechat/python/autoload/urlgrab.py --- a/weechat/python/autoload/urlgrab.py Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,699 +0,0 @@ -# -*- coding: utf-8 -*- -# -# UrlGrab, for weechat version >= 0.3.0 -# -# Listens to all channels for URLs, collects them in a list, and launches -# them in your favourite web server on the local host or a remote server. -# Copies url to X11 clipboard via xsel -# (http://www.vergenet.net/~conrad/software/xsel) -# -# Usage: -# -# The /url command provides access to all UrlGrab functions. Run -# '/help url' for complete command usage. -# -# In general, use '/url list' to list the entire url list for the current -# channel, and '/url <n>' to launch the nth url in the list. For -# example, to launch the first (and most-recently added) url in the list, -# you would run '/url 1' -# -# From the server window, you must specify a specific channel for the -# list and launch commands, for example: -# /url list weechat -# /url 3 weechat -# -# Configuration: -# -# The '/url set' command lets you get and set the following options: -# -# historysize -# The maximum number of URLs saved per channel. Default is 10 -# -# method -# Must be one of 'local' or 'remote' - Defines how URLs are launched by -# the script. If 'local', the script will run 'localcmd' on the host. -# If 'remote', the script will run 'remotessh remotehost remotecmd' on -# the local host which should normally use ssh to connect to another -# host and run the browser command there. -# -# localcmd -# The command to run on the local host to launch URLs in 'local' mode. -# The string '%s' will be replaced with the URL. The default is -# 'firefox %s'. -# -# remotessh -# The command (and arguments) used to connect to the remote host for -# 'remote' mode. The default is 'ssh -x' which will connect as the -# current username via ssh and disable X11 forwarding. -# -# remotehost -# The remote host to which we will connect in 'remote' mode. For ssh, -# this can just be a hostname or 'user@host' to specify a username -# other than your current login name. The default is 'localhost'. -# -# remotecmd -# The command to execute on the remote host for 'remote' mode. The -# default is 'bash -c "DISPLAY=:0.0 firefox '%s'"' Which runs bash, sets -# up the environment to display on the remote host's main X display, -# and runs firefox. As with 'localcmd', the string '%s' will be -# replaced with the URL. -# -# cmdoutput -# The file where the command output (if any) is saved. Overwritten -# each time you launch a new URL. Default is ~/.weechat/urllaunch.log -# -# default -# The command that will be run if no arguemnts to /url are given. -# Default is show -# -# Requirements: -# -# - Designed to run with weechat version 0.3 or better. -# http://www.weechat.org/ -# -# Acknowlegements: -# -# - Based on an earlier version called 'urlcollector.py' by 'kolter' of -# irc.freenode.net/#weechat Honestly, I just cleaned up the code a bit and -# made the settings a little more useful (to me). -# -# - With changes by Leonid Evdokimov (weechat at darkk dot net another dot ru): -# http://darkk.net.ru/weechat/urlgrab.py -# v1.1: added better handling of dead zombie-childs -# added parsing of private messages -# added default command setting -# added parsing of scrollback buffers on load -# v1.2: `historysize` was ignored -# -# - With changes by ExclusivE (exclusive_tm at mail dot ru): -# v1.3: X11 clipboard support -# -# - V1.4 Just ported it over to weechat 0.2.7 drubin AT smartcube dot co dot za -# - V1.5 1) I created a logging feature for urls, Time, Date, buffer, and url. -# 2) Added selectable urls support, similar to the iset plugin (Thanks FlashCode) -# 3) Colors/formats are configuarable. -# 4) browser now uses hook_process (Please test with remote clients) -# 5) Added /url open http://url.com functionality -# 6) Changed urls detection to use regexpressions so should be much better -# Thanks to xt of #weechat bassed on on urlbar.py -# - V1.6 FlashCode <flashcode@flashtux.org>: Increase timeout for hook_process -# (from 1 second to 1 minute) -# - V1.7 FlashCode <flashcode@flashtux.org>: Update WeeChat site -# - V1.8 drubin <drubin [at] smartcube . co.za>: -# - Changed remote cmd to be single option -# - Added scrolling on up and down arrow keys for /url show -# - Changed remotecmd to include options with public/private keys password auth doesn't work -# - V1.9 Specimen <spinifer [at] gmail . com>: -# - Changed the default command when /url is run with no arguments to 'show' -# - Removed '/url help' command, because /help <command> is the standard way -# - V2.0 Xilov: replace "/url help" by "/help url" -# - V2.1 nand: Changed default: firefox %s to firefox '%s' (localcmd) -# - V2.2 Sébastien Helleu <flashcode@flashtux.org>: fix reload of config file -# - V2.3 nand: Allowed trailing )s for unmatched (s in URLs -# - V2.4 nand: Escaped URLs via URL-encoding instead of shell escaping, fixes ' -# - V2.5 nand: Fixed some URLs that got incorrectly mangled by escaping -# - V2.6 nesthib: Fixed escaping of "=" -# Added missing quotes in default parameter (firefox '%s') -# Removed the mix of tabs and spaces in the file indentation -# - V2.7 dobbymoodge <john.w.lamb [at] gmail . com> -# ( https://github.com/dobbymoodge/ ): -# - Added 'copycmd' setting, users can set command to pipe into -# for '/url copy' -# - V2.8 Simmo Saan <simmo.saan@gmail.com>: -# - Changed print hook to ignore filtered lines -# - V2.9 Dominik Heidler <dominik@heidler.eu>: -# - Updated script for python3 support (now python2 and 3 are both supported) -# - V3.0 Sébastien Helleu <flashcode@flashtux.org>: -# - Fix python 3 compatibility (replace "has_key" by "in") -# -# Copyright (C) 2005 David Rubin <drubin AT smartcube dot co dot za> -# -# 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 2 -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. -# - -from __future__ import print_function -import sys -import os -try: - import weechat - import_ok = True -except: - print("This script must be run under WeeChat.") - print("Get WeeChat now at: http://www.weechat.org/") - import_ok = False -import subprocess -import time -try: - from urllib import quote -except ImportError: - from urllib.parse import quote -import re -try: - from UserDict import UserDict -except ImportError: - from collections import UserDict - - -octet = r'(?:2(?:[0-4]\d|5[0-5])|1\d\d|\d{1,2})' -ipAddr = r'%s(?:\.%s){3}' % (octet, octet) -# Base domain regex off RFC 1034 and 1738 -label = r'[0-9a-z][-0-9a-z]*[0-9a-z]?' -domain = r'%s(?:\.%s)*\.[a-z][-0-9a-z]*[a-z]?' % (label, label) -urlRe = re.compile(r'(\w+://(?:%s|%s)(?::\d+)?(?:/[^\]>\s]*)?)' % (domain, ipAddr), re.I) - - -SCRIPT_NAME = "urlgrab" -SCRIPT_AUTHOR = "David Rubin <drubin [At] smartcube [dot] co [dot] za>" -SCRIPT_VERSION = "3.0" -SCRIPT_LICENSE = "GPL" -SCRIPT_DESC = "Url functionality Loggin, opening of browser, selectable links" -CONFIG_FILE_NAME= "urlgrab" -SCRIPT_COMMAND = "url" - - -def stripParens(url): - return dropChar(')', url.count(')') - url.count('('), url[::-1])[::-1] - -def dropChar(c, n, xs): - if n == 0 or xs == []: - return xs - elif xs[0] == c: - return dropChar(c, n-1, xs[1:]) - else: - return xs - -def urlGrabPrint(message): - bufferd=weechat.current_buffer() - if urlGrabSettings['output_main_buffer'] == 1 : - weechat.prnt("","[%s] %s" % ( SCRIPT_NAME, message ) ) - else : - weechat.prnt(bufferd,"[%s] %s" % ( SCRIPT_NAME, message ) ) - -def hashBufferName(bufferp): - if not weechat.buffer_get_string(bufferp, "short_name"): - bufferd = weechat.buffer_get_string(bufferp, "name") - else: - bufferd = weechat.buffer_get_string(bufferp, "short_name") - return bufferd - -def ug_config_reload_cb(data, config_file): - """ Reload configuration file. """ - return weechat.config_reload(config_file) - -class UrlGrabSettings(UserDict): - def __init__(self): - UserDict.__init__(self) - self.data = {} - self.config_file = weechat.config_new(CONFIG_FILE_NAME, - "ug_config_reload_cb", "") - if not self.config_file: - return - - section_color = weechat.config_new_section( - self.config_file, "color", 0, 0, "", "", "", "", "", "", - "", "", "", "") - section_default = weechat.config_new_section( - self.config_file, "default", 0, 0, "", "", "", "", "", "", - "", "", "", "") - - self.data['color_buffer']=weechat.config_new_option( - self.config_file, section_color, - "color_buffer", "color", "Color to display buffer name", "", 0, 0, - "red", "red", 0, "", "", "", "", "", "") - - self.data['color_url']=weechat.config_new_option( - self.config_file, section_color, - "color_url", "color", "Color to display urls", "", 0, 0, - "blue", "blue", 0, "", "", "", "", "", "") - - self.data['color_time']=weechat.config_new_option( - self.config_file, section_color, - "color_time", "color", "Color to display time", "", 0, 0, - "cyan", "cyan", 0, "", "", "", "", "", "") - - self.data['color_buffer_selected']=weechat.config_new_option( - self.config_file, section_color, - "color_buffer_selected", "color", - "Color to display buffer selected name", "", 0, 0, "red", "red", - 0, "", "", "", "", "", "") - - self.data['color_url_selected']=weechat.config_new_option( - self.config_file, section_color, - "color_url_selected", "color", "Color to display url selected", - "", 0, 0, "blue", "blue", 0, "", "", "", "", "", "") - - self.data['color_time_selected']=weechat.config_new_option( - self.config_file, section_color, - "color_time_selected", "color", "Color to display tim selected", - "", 0, 0, "cyan", "cyan", 0, "", "", "", "", "", "") - - self.data['color_bg_selected']=weechat.config_new_option( - self.config_file, section_color, - "color_bg_selected", "color", "Background for selected row", "", 0, 0, - "green", "green", 0, "", "", "", "", "", "") - - self.data['historysize']=weechat.config_new_option( - self.config_file, section_default, - "historysize", "integer", "Max number of urls to store per buffer", - "", 0, 999, "10", "10", 0, "", "", "", "", "", "") - - self.data['method']=weechat.config_new_option( - self.config_file, section_default, - "method", "string", """Where to launch URLs - If 'local', runs %localcmd%. - If 'remote' runs the following command: - '%remodecmd%'""", "", 0, 0, - "local", "local", 0, "", "", "", "", "", "") - - self.data['copycmd']=weechat.config_new_option( - self.config_file, section_default, - "copycmd", "string", - "Command to pipe into for 'url copy'. " - "E.g. to copy into the CLIPBOARD buffer " - "instead of PRIMARY, you can use 'xsel -b " - "-i' here.", "", 0, 0, - "xsel -i", "xsel -i", 0, "", "", "", "", "", "") - - self.data['localcmd']=weechat.config_new_option( - self.config_file, section_default, - "localcmd", "string", """Local command to execute""", "", 0, 0, - "firefox '%s'", "firefox '%s'", 0, "", "", "", "", "", "") - - remotecmd="ssh -x localhost -i ~/.ssh/id_rsa -C \"export DISPLAY=\":0.0\" && firefox '%s'\"" - self.data['remotecmd']=weechat.config_new_option( - self.config_file, section_default, - "remotecmd", "string", remotecmd, "", 0, 0, - remotecmd, remotecmd, 0, "", "", "", "", "", "") - - self.data['url_log']=weechat.config_new_option( - self.config_file, section_default, - "url_log", "string", """log location""", "", 0, 0, - "~/.weechat/urls.log", "~/.weechat/urls.log", 0, "", "", "", "", "", "") - - self.data['time_format']=weechat.config_new_option( - self.config_file, section_default, - "time_format", "string", """TIme format""", "", 0, 0, - "%H:%M:%S", "%H:%M:%S", 0, "", "", "", "", "", "") - - self.data['output_main_buffer']=weechat.config_new_option( - self.config_file, section_default, - "output_main_buffer", "boolean", - """Print text to main buffer or current one""", "", 0, 0, "1", "1", - 0, "", "", "", "", "", "") - weechat.config_read(self.config_file) - - def __getitem__(self, key): - if key == "historysize": - return weechat.config_integer(self.data[key]) - elif key == 'output_main_buffer': - return weechat.config_boolean(self.data[key]) - #elif key.startswith('color'): - # return weechat.config_color(self.data[key]) - else: - return weechat.config_string(self.data[key]) - - def prnt(self, name, verbose = True): - weechat.prnt( ""," %s = %s" % (name.ljust(11), self.data[name]) ) - - def prntall(self): - for key in self.names(): - self.prnt(key, verbose = False) - - def createCmd(self, url): - str ="" - if self['method'] == 'remote': - str = self['remotecmd'] % url - else: - str = self['localcmd'] % url - return str - -class UrlGrabber: - def __init__(self, historysize): - # init - self.urls = {} - self.globalUrls = [] - self.historysize = 5 - # control - self.setHistorysize(historysize) - - def setHistorysize(self, count): - if count > 1: - self.historysize = count - - def getHistorysize(self): - return self.historysize - - def addUrl(self, bufferp,url ): - global urlGrabSettings - self.globalUrls.insert(0,{"buffer":bufferp, - "url":url, "time":time.strftime(urlGrabSettings["time_format"])}) - #Log urls only if we have set a log path. - if urlGrabSettings['url_log']: - try : - index = self.globalUrls[0] - logfile = os.path.expanduser(urlGrabSettings['url_log']) - dout = open(logfile, "a") - dout.write("%s %s %s\n" % (index['time'], - index['buffer'], index['url'])) - dout.close() - except : - print("failed to log url check that %s is valid path" % urlGrabSettings['url_log']) - pass - - # check for buffer - if not bufferp in self.urls: - self.urls[bufferp] = [] - # add url - if url in self.urls[bufferp]: - self.urls[bufferp].remove(url) - self.urls[bufferp].insert(0, url) - # removing old urls - while len(self.urls[bufferp]) > self.historysize: - self.urls[bufferp].pop() - - def hasIndex( self, bufferp, index ): - return bufferp in self.urls and \ - len(self.url[bufferp]) >= index - - def hasBuffer( self, bufferp ): - return bufferp in self.urls - - - def getUrl(self, bufferp, index): - url = "" - if bufferp in self.urls: - if len(self.urls[bufferp]) >= index: - url = self.urls[bufferp][index-1] - return url - - - def prnt(self, buff): - found = True - if buff in self.urls: - if len(self.urls[buff]) > 0: - i = 1 - for url in self.urls[buff]: - urlGrabPrint("--> " + str(i) + " : " + url) - i += 1 - else: - found = False - elif buff == "*": - for b in self.urls.keys(): - self.prnt(b) - else: - found = False - - if not found: - urlGrabPrint(buff + ": no entries") - -def urlGrabCheckMsgline(bufferp, message, isdisplayed): - global urlGrab, max_buffer_length - if not message or isdisplayed == 0: - return - # Ignore output from 'tinyurl.py' and our selfs - if ( message.startswith( "[AKA] http://tinyurl.com" ) or - message.startswith("[urlgrab]") ): - return - # Check for URLs - for url in urlRe.findall(message): - urlGrab.addUrl(bufferp,stripParens(url)) - if max_buffer_length < len(bufferp): - max_buffer_length = len(bufferp) - if urlgrab_buffer: - refresh() - - -def urlGrabCheck(data, bufferp, uber_empty, tagsn, isdisplayed, ishilight, prefix, message): - urlGrabCheckMsgline(hashBufferName(bufferp), message, isdisplayed) - return weechat.WEECHAT_RC_OK - -def urlGrabCopy(bufferd, index): - global urlGrab - if bufferd == "": - urlGrabPrint( "No current channel, you must activate one" ) - elif not urlGrab.hasBuffer(bufferd): - urlGrabPrint("No URL found - Invalid channel") - else: - if index <= 0: - urlGrabPrint("No URL found - Invalid index") - return - url = urlGrab.getUrl(bufferd,index) - if url == "": - urlGrabPrint("No URL found - Invalid index") - else: - try: - pipe = os.popen(urlGrabSettings['copycmd'],"w") - pipe.write(url) - pipe.close() - urlGrabPrint("Url: %s gone to clipboard." % url) - except: - urlGrabPrint("Url: %s failed to copy to clipboard." % url) - -def urlGrabOpenUrl(url): - global urlGrab, urlGrabSettings - argl = urlGrabSettings.createCmd( quote(url, '/:#%?&+=') ) - weechat.hook_process(argl,60000, "ug_open_cb", "") - -def ug_open_cb(data, command, code, out, err): - # weechat.prnt("", out) - # weechat.prnt("", err) - return weechat.WEECHAT_RC_OK - - -def urlGrabOpen(bufferd, index): - global urlGrab, urlGrabSettings - if bufferd == "": - urlGrabPrint( "No current channel, you must specify one" ) - elif not urlGrab.hasBuffer(bufferd) : - urlGrabPrint("No URL found - Invalid channel") - else: - if index <= 0: - urlGrabPrint("No URL found - Invalid index") - return - url = urlGrab.getUrl(bufferd,index) - if url == "": - urlGrabPrint("No URL found - Invalid index") - else: - urlGrabPrint("loading %s %sly" % (url, urlGrabSettings["method"])) - urlGrabOpenUrl (url) - -def urlGrabList( args ): - global urlGrab - if len(args) == 0: - buf = hashBufferName(weechat.current_buffer()) - else: - buf = args[0] - if buf == "" or buf == "all": - buf = "*" - urlGrab.prnt(buf) - - -def urlGrabMain(data, bufferp, args): - if args[0:2] == "**": - keyEvent(data, bufferp, args[2:]) - return weechat.WEECHAT_RC_OK - - bufferd = hashBufferName(bufferp) - largs = args.split(" ") - #strip spaces - while '' in largs: - largs.remove('') - while ' ' in largs: - largs.remove(' ') - if len(largs) == 0 or largs[0] == "show": - if not urlgrab_buffer: - init() - refresh() - weechat.buffer_set(urlgrab_buffer, "display", "1") - elif largs[0] == 'open' and len(largs) == 2: - urlGrabOpenUrl(largs[1]) - elif largs[0] == 'list': - urlGrabList( largs[1:] ) - elif largs[0] == 'copy': - if len(largs) > 1: - no = int(largs[1]) - urlGrabCopy(bufferd, no) - else: - urlGrabCopy(bufferd,1) - else: - try: - no = int(largs[0]) - if len(largs) > 1: - urlGrabOpen(largs[1], no) - else: - urlGrabOpen(bufferd, no) - except ValueError: - #not a valid number so try opening it as a url.. - for url in urlRe.findall(largs[0]): - urlGrabOpenUrl(stripParens(url)) - urlGrabPrint( "Unknown command '%s'. Try '/help url' for usage" % largs[0]) - return weechat.WEECHAT_RC_OK - -def buffer_input(*kwargs): - return weechat.WEECHAT_RC_OK - -def buffer_close(*kwargs): - global urlgrab_buffer - urlgrab_buffer = None - return weechat.WEECHAT_RC_OK - -def keyEvent (data, bufferp, args): - global urlGrab , urlGrabSettings, urlgrab_buffer, current_line - if args == "refresh": - refresh() - elif args == "up": - if current_line > 0: - current_line = current_line -1 - refresh_line (current_line + 1) - refresh_line (current_line) - ugCheckLineOutsideWindow() - elif args == "down": - if current_line < len(urlGrab.globalUrls) - 1: - current_line = current_line +1 - refresh_line (current_line - 1) - refresh_line (current_line) - ugCheckLineOutsideWindow() - elif args == "scroll_top": - temp_current = current_line - current_line = 0 - refresh_line (temp_current) - refresh_line (current_line) - weechat.command(urlgrab_buffer, "/window scroll_top") - pass - elif args == "scroll_bottom": - temp_current = current_line - current_line = len(urlGrab.globalUrls) - refresh_line (temp_current) - refresh_line (current_line) - weechat.command(urlgrab_buffer, "/window scroll_bottom") - elif args == "enter": - if urlGrab.globalUrls[current_line]: - urlGrabOpenUrl (urlGrab.globalUrls[current_line]['url']) - -def refresh_line (y): - global urlGrab , urlGrabSettings, urlgrab_buffer, current_line, max_buffer_length - #Print format Time(space)buffer(max4 spaces, but lined up)url - format = "%%s%%s %%s%%-%ds%%s%%s" % (max_buffer_length+4) - - #non selected colors - color_buffer = urlGrabSettings["color_buffer"] - color_url = urlGrabSettings["color_url"] - color_time =urlGrabSettings["color_time"] - #selected colors - color_buffer_selected = urlGrabSettings["color_buffer_selected"] - color_url_selected = urlGrabSettings["color_url_selected"] - color_time_selected = urlGrabSettings["color_time_selected"] - - color_bg_selected = urlGrabSettings["color_bg_selected"] - - color1 = color_time - color2 = color_buffer - color3 = color_url - - #If this line is selected we change the colors. - if y == current_line: - color1 = "%s,%s" % (color_time_selected, color_bg_selected) - color2 = "%s,%s" % (color_buffer_selected, color_bg_selected) - color3 = "%s,%s" % (color_url_selected, color_bg_selected) - - color1 = weechat.color(color1) - color2 = weechat.color(color2) - color3 = weechat.color(color3) - text = format % (color1, - urlGrab.globalUrls[y]['time'], - color2, - urlGrab.globalUrls[y]['buffer'], - color3, - urlGrab.globalUrls[y]['url'] ) - weechat.prnt_y(urlgrab_buffer,y,text) - -def ugCheckLineOutsideWindow(): - global urlGrab , urlGrabSettings, urlgrab_buffer, current_line, max_buffer_length - if (urlgrab_buffer): - infolist = weechat.infolist_get("window", "", "current") - if (weechat.infolist_next(infolist)): - start_line_y = weechat.infolist_integer(infolist, "start_line_y") - chat_height = weechat.infolist_integer(infolist, "chat_height") - if(start_line_y > current_line): - weechat.command(urlgrab_buffer, "/window scroll -%i" %(start_line_y - current_line)) - elif(start_line_y <= current_line - chat_height): - weechat.command(urlgrab_buffer, "/window scroll +%i"%(current_line - start_line_y - chat_height + 1)) - weechat.infolist_free(infolist) - - -def refresh(): - global urlGrab - y=0 - for x in urlGrab.globalUrls: - refresh_line (y) - y += 1 - - -def init(): - global urlGrab , urlGrabSettings, urlgrab_buffer - if not urlgrab_buffer: - urlgrab_buffer = weechat.buffer_new("urlgrab", "buffer_input", "", "buffer_close", "") - if urlgrab_buffer: - weechat.buffer_set(urlgrab_buffer, "type", "free") - weechat.buffer_set(urlgrab_buffer, "key_bind_ctrl-R", "/url **refresh") - weechat.buffer_set(urlgrab_buffer, "key_bind_meta2-A", "/url **up") - weechat.buffer_set(urlgrab_buffer, "key_bind_meta2-B", "/url **down") - weechat.buffer_set(urlgrab_buffer, "key_bind_meta-ctrl-J", "/url **enter") - weechat.buffer_set(urlgrab_buffer, "key_bind_meta-ctrl-M", "/url **enter") - weechat.buffer_set(urlgrab_buffer, "key_bind_meta-meta2-1./~", "/url **scroll_top") - weechat.buffer_set(urlgrab_buffer, "key_bind_meta-meta2-4~", "/url **scroll_bottom") - weechat.buffer_set(urlgrab_buffer, "title","Lists the urls in the applications") - weechat.buffer_set(urlgrab_buffer, "display", "1") - -def completion_urls_cb(data, completion_item, bufferp, completion): - """ Complete with URLS, for command '/url'. """ - global urlGrab - bufferd = hashBufferName( bufferp) - for url in urlGrab.globalUrls : - if url['buffer'] == bufferd: - weechat.hook_completion_list_add(completion, url['url'], 0, weechat.WEECHAT_LIST_POS_SORT) - return weechat.WEECHAT_RC_OK - -def ug_unload_script(): - """ Function called when script is unloaded. """ - global urlGrabSettings - weechat.config_write(urlGrabSettings.config_file) - return weechat.WEECHAT_RC_OK - -#Main stuff -if ( import_ok and - weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, - SCRIPT_LICENSE,SCRIPT_DESC, "ug_unload_script", "") ): - urlgrab_buffer = None - current_line = 0 - max_buffer_length = 0 - urlGrabSettings = UrlGrabSettings() - urlGrab = UrlGrabber( urlGrabSettings['historysize']) - weechat.hook_print("", "", "", 1, "urlGrabCheck", "") - weechat.hook_command(SCRIPT_COMMAND, - "Url Grabber", - "[open <url> | <url> | show | copy [n] | [n] | list]", - "open or <url>: opens the url\n" - "show: Opens the select buffer to allow for url selection\n" - "copy: Copies the nth url to the system clipboard\n" - "list: Lists the urls in the current buffer\n", - "open %(urlgrab_urls) || %(urlgrab_urls) || " - "copy || show || list", - "urlGrabMain", "") - weechat.hook_completion("urlgrab_urls", "list of URLs", - "completion_urls_cb", "") -else: - print("failed to load weechat") diff -r 93d27886c099 -r 62e329839625 weechat/python/autoload/wee_slack.py --- a/weechat/python/autoload/wee_slack.py Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -/home/sjl/src/wee-slack/wee_slack.py \ No newline at end of file diff -r 93d27886c099 -r 62e329839625 weechat/python/autosort.py --- a/weechat/python/autosort.py Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1075 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013-2017 Maarten de Vries <maarten@de-vri.es> -# -# 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 <http://www.gnu.org/licenses/>. -# - -# -# Autosort automatically keeps your buffers sorted and grouped by server. -# You can define your own sorting rules. See /help autosort for more details. -# -# https://github.com/de-vri-es/weechat-autosort -# - -# -# Changelog: -# 3.9: -# * Remove `buffers.pl` from recommended settings. -# 3,8: -# * Fix relative sorting on script name in default rules. -# * Document a useful property of stable sort algorithms. -# 3.7: -# * Make default rules work with bitlbee, matrix and slack. -# 3.6: -# * Add more documentation on provided info hooks. -# 3.5: -# * Add ${info:autosort_escape,...} to escape arguments for other info hooks. -# 3.4: -# * Fix rate-limit of sorting to prevent high CPU load and lock-ups. -# * Fix bug in parsing empty arguments for info hooks. -# * Add debug_log option to aid with debugging. -# * Correct a few typos. -# 3.3: -# * Fix the /autosort debug command for unicode. -# * Update the default rules to work better with Slack. -# 3.2: -# * Fix python3 compatiblity. -# 3.1: -# * Use colors to format the help text. -# 3.0: -# * Switch to evaluated expressions for sorting. -# * Add `/autosort debug` command. -# * Add ${info:autosort_replace,from,to,text} to replace substrings in sort rules. -# * Add ${info:autosort_order,value,first,second,third} to ease writing sort rules. -# * Make tab completion context aware. -# 2.8: -# * Fix compatibility with python 3 regarding unicode handling. -# 2.7: -# * Fix sorting of buffers with spaces in their name. -# 2.6: -# * Ignore case in rules when doing case insensitive sorting. -# 2.5: -# * Fix handling unicode buffer names. -# * Add hint to set irc.look.server_buffer to independent and buffers.look.indenting to on. -# 2.4: -# * Make script python3 compatible. -# 2.3: -# * Fix sorting items without score last (regressed in 2.2). -# 2.2: -# * Add configuration option for signals that trigger a sort. -# * Add command to manually trigger a sort (/autosort sort). -# * Add replacement patterns to apply before sorting. -# 2.1: -# * Fix some minor style issues. -# 2.0: -# * Allow for custom sort rules. -# - - -import json -import math -import re -import sys -import time -import weechat - -SCRIPT_NAME = 'autosort' -SCRIPT_AUTHOR = 'Maarten de Vries <maarten@de-vri.es>' -SCRIPT_VERSION = '3.9' -SCRIPT_LICENSE = 'GPL3' -SCRIPT_DESC = 'Flexible automatic (or manual) buffer sorting based on eval expressions.' - - -config = None -hooks = [] -signal_delay_timer = None -sort_limit_timer = None -sort_queued = False - - -# Make sure that unicode, bytes and str are always available in python2 and 3. -# For python 2, str == bytes -# For python 3, str == unicode -if sys.version_info[0] >= 3: - unicode = str - -def ensure_str(input): - ''' - Make sure the given type if the correct string type for the current python version. - That means bytes for python2 and unicode for python3. - ''' - if not isinstance(input, str): - if isinstance(input, bytes): - return input.encode('utf-8') - if isinstance(input, unicode): - return input.decode('utf-8') - return input - - -if hasattr(time, 'perf_counter'): - perf_counter = time.perf_counter -else: - perf_counter = time.clock - -def casefold(string): - if hasattr(string, 'casefold'): return string.casefold() - # Fall back to lowercasing for python2. - return string.lower() - -def list_swap(values, a, b): - values[a], values[b] = values[b], values[a] - -def list_move(values, old_index, new_index): - values.insert(new_index, values.pop(old_index)) - -def list_find(collection, value): - for i, elem in enumerate(collection): - if elem == value: return i - return None - -class HumanReadableError(Exception): - pass - -def parse_int(arg, arg_name = 'argument'): - ''' Parse an integer and provide a more human readable error. ''' - arg = arg.strip() - try: - return int(arg) - except ValueError: - raise HumanReadableError('Invalid {0}: expected integer, got "{1}".'.format(arg_name, arg)) - -def decode_rules(blob): - parsed = json.loads(blob) - if not isinstance(parsed, list): - log('Malformed rules, expected a JSON encoded list of strings, but got a {0}. No rules have been loaded. Please fix the setting manually.'.format(type(parsed))) - return [] - - for i, entry in enumerate(parsed): - if not isinstance(entry, (str, unicode)): - log('Rule #{0} is not a string but a {1}. No rules have been loaded. Please fix the setting manually.'.format(i, type(entry))) - return [] - - return parsed - -def decode_helpers(blob): - parsed = json.loads(blob) - if not isinstance(parsed, dict): - log('Malformed helpers, expected a JSON encoded dictionary but got a {0}. No helpers have been loaded. Please fix the setting manually.'.format(type(parsed))) - return {} - - for key, value in parsed.items(): - if not isinstance(value, (str, unicode)): - log('Helper "{0}" is not a string but a {1}. No helpers have been loaded. Please fix setting manually.'.format(key, type(value))) - return {} - return parsed - -class Config: - ''' The autosort configuration. ''' - - default_rules = json.dumps([ - '${core_first}', - '${info:autosort_order,${info:autosort_escape,${script_or_plugin}},core,*,irc,bitlbee,matrix,slack}', - '${script_or_plugin}', - '${irc_raw_first}', - '${server}', - '${info:autosort_order,${type},server,*,channel,private}', - '${hashless_name}', - '${buffer.full_name}', - ]) - - default_helpers = json.dumps({ - 'core_first': '${if:${buffer.full_name}!=core.weechat}', - 'irc_raw_first': '${if:${buffer.full_name}!=irc.irc_raw}', - 'irc_raw_last': '${if:${buffer.full_name}==irc.irc_raw}', - 'hashless_name': '${info:autosort_replace,#,,${info:autosort_escape,${buffer.name}}}', - 'script_or_plugin': '${if:${script_name}?${script_name}:${plugin}}', - }) - - default_signal_delay = 5 - default_sort_limit = 100 - - default_signals = 'buffer_opened buffer_merged buffer_unmerged buffer_renamed' - - def __init__(self, filename): - ''' Initialize the configuration. ''' - - self.filename = filename - self.config_file = weechat.config_new(self.filename, '', '') - self.sorting_section = None - self.v3_section = None - - self.case_sensitive = False - self.rules = [] - self.helpers = {} - self.signals = [] - self.signal_delay = Config.default_signal_delay, - self.sort_limit = Config.default_sort_limit, - self.sort_on_config = True - self.debug_log = False - - self.__case_sensitive = None - self.__rules = None - self.__helpers = None - self.__signals = None - self.__signal_delay = None - self.__sort_limit = None - self.__sort_on_config = None - self.__debug_log = None - - if not self.config_file: - log('Failed to initialize configuration file "{0}".'.format(self.filename)) - return - - self.sorting_section = weechat.config_new_section(self.config_file, 'sorting', False, False, '', '', '', '', '', '', '', '', '', '') - self.v3_section = weechat.config_new_section(self.config_file, 'v3', False, False, '', '', '', '', '', '', '', '', '', '') - - if not self.sorting_section: - log('Failed to initialize section "sorting" of configuration file.') - weechat.config_free(self.config_file) - return - - self.__case_sensitive = weechat.config_new_option( - self.config_file, self.sorting_section, - 'case_sensitive', 'boolean', - 'If this option is on, sorting is case sensitive.', - '', 0, 0, 'off', 'off', 0, - '', '', '', '', '', '' - ) - - weechat.config_new_option( - self.config_file, self.sorting_section, - 'rules', 'string', - 'Sort rules used by autosort v2.x and below. Not used by autosort anymore.', - '', 0, 0, '', '', 0, - '', '', '', '', '', '' - ) - - weechat.config_new_option( - self.config_file, self.sorting_section, - 'replacements', 'string', - 'Replacement patterns used by autosort v2.x and below. Not used by autosort anymore.', - '', 0, 0, '', '', 0, - '', '', '', '', '', '' - ) - - self.__rules = weechat.config_new_option( - self.config_file, self.v3_section, - 'rules', 'string', - 'An ordered list of sorting rules encoded as JSON. See /help autosort for commands to manipulate these rules.', - '', 0, 0, Config.default_rules, Config.default_rules, 0, - '', '', '', '', '', '' - ) - - self.__helpers = weechat.config_new_option( - self.config_file, self.v3_section, - 'helpers', 'string', - 'A dictionary helper variables to use in the sorting rules, encoded as JSON. See /help autosort for commands to manipulate these helpers.', - '', 0, 0, Config.default_helpers, Config.default_helpers, 0, - '', '', '', '', '', '' - ) - - self.__signals = weechat.config_new_option( - self.config_file, self.sorting_section, - 'signals', 'string', - 'A space separated list of signals that will cause autosort to resort your buffer list.', - '', 0, 0, Config.default_signals, Config.default_signals, 0, - '', '', '', '', '', '' - ) - - self.__signal_delay = weechat.config_new_option( - self.config_file, self.sorting_section, - 'signal_delay', 'integer', - 'Delay in milliseconds to wait after a signal before sorting the buffer list. This prevents triggering many times if multiple signals arrive in a short time. It can also be needed to wait for buffer localvars to be available.', - '', 0, 1000, str(Config.default_signal_delay), str(Config.default_signal_delay), 0, - '', '', '', '', '', '' - ) - - self.__sort_limit = weechat.config_new_option( - self.config_file, self.sorting_section, - 'sort_limit', 'integer', - 'Minimum delay in milliseconds to wait after sorting before signals can trigger a sort again. This is effectively a rate limit on sorting. Keeping signal_delay low while setting this higher can reduce excessive sorting without a long initial delay.', - '', 0, 1000, str(Config.default_sort_limit), str(Config.default_sort_limit), 0, - '', '', '', '', '', '' - ) - - self.__sort_on_config = weechat.config_new_option( - self.config_file, self.sorting_section, - 'sort_on_config_change', 'boolean', - 'Decides if the buffer list should be sorted when autosort configuration changes.', - '', 0, 0, 'on', 'on', 0, - '', '', '', '', '', '' - ) - - self.__debug_log = weechat.config_new_option( - self.config_file, self.sorting_section, - 'debug_log', 'boolean', - 'If enabled, print more debug messages. Not recommended for normal usage.', - '', 0, 0, 'off', 'off', 0, - '', '', '', '', '', '' - ) - - if weechat.config_read(self.config_file) != weechat.WEECHAT_RC_OK: - log('Failed to load configuration file.') - - if weechat.config_write(self.config_file) != weechat.WEECHAT_RC_OK: - log('Failed to write configuration file.') - - self.reload() - - def reload(self): - ''' Load configuration variables. ''' - - self.case_sensitive = weechat.config_boolean(self.__case_sensitive) - - rules_blob = weechat.config_string(self.__rules) - helpers_blob = weechat.config_string(self.__helpers) - signals_blob = weechat.config_string(self.__signals) - - self.rules = decode_rules(rules_blob) - self.helpers = decode_helpers(helpers_blob) - self.signals = signals_blob.split() - self.signal_delay = weechat.config_integer(self.__signal_delay) - self.sort_limit = weechat.config_integer(self.__sort_limit) - self.sort_on_config = weechat.config_boolean(self.__sort_on_config) - self.debug_log = weechat.config_boolean(self.__debug_log) - - def save_rules(self, run_callback = True): - ''' Save the current rules to the configuration. ''' - weechat.config_option_set(self.__rules, json.dumps(self.rules), run_callback) - - def save_helpers(self, run_callback = True): - ''' Save the current helpers to the configuration. ''' - weechat.config_option_set(self.__helpers, json.dumps(self.helpers), run_callback) - - -def pad(sequence, length, padding = None): - ''' Pad a list until is has a certain length. ''' - return sequence + [padding] * max(0, (length - len(sequence))) - -def log(message, buffer = 'NULL'): - weechat.prnt(buffer, 'autosort: {0}'.format(message)) - -def debug(message, buffer = 'NULL'): - if config.debug_log: - weechat.prnt(buffer, 'autosort: debug: {0}'.format(message)) - -def get_buffers(): - ''' Get a list of all the buffers in weechat. ''' - hdata = weechat.hdata_get('buffer') - buffer = weechat.hdata_get_list(hdata, "gui_buffers"); - - result = [] - while buffer: - number = weechat.hdata_integer(hdata, buffer, 'number') - result.append((number, buffer)) - buffer = weechat.hdata_pointer(hdata, buffer, 'next_buffer') - return hdata, result - -class MergedBuffers(list): - """ A list of merged buffers, possibly of size 1. """ - def __init__(self, number): - super(MergedBuffers, self).__init__() - self.number = number - -def merge_buffer_list(buffers): - ''' - Group merged buffers together. - The output is a list of MergedBuffers. - ''' - if not buffers: return [] - result = {} - for number, buffer in buffers: - if number not in result: result[number] = MergedBuffers(number) - result[number].append(buffer) - return result.values() - -def sort_buffers(hdata, buffers, rules, helpers, case_sensitive): - for merged in buffers: - for buffer in merged: - name = weechat.hdata_string(hdata, buffer, 'name') - - return sorted(buffers, key=merged_sort_key(rules, helpers, case_sensitive)) - -def buffer_sort_key(rules, helpers, case_sensitive): - ''' Create a sort key function for a list of lists of merged buffers. ''' - def key(buffer): - extra_vars = {} - for helper_name, helper in sorted(helpers.items()): - expanded = weechat.string_eval_expression(helper, {"buffer": buffer}, {}, {}) - extra_vars[helper_name] = expanded if case_sensitive else casefold(expanded) - result = [] - for rule in rules: - expanded = weechat.string_eval_expression(rule, {"buffer": buffer}, extra_vars, {}) - result.append(expanded if case_sensitive else casefold(expanded)) - return result - - return key - -def merged_sort_key(rules, helpers, case_sensitive): - buffer_key = buffer_sort_key(rules, helpers, case_sensitive) - def key(merged): - best = None - for buffer in merged: - this = buffer_key(buffer) - if best is None or this < best: best = this - return best - return key - -def apply_buffer_order(buffers): - ''' Sort the buffers in weechat according to the given order. ''' - for i, buffer in enumerate(buffers): - weechat.buffer_set(buffer[0], "number", str(i + 1)) - -def split_args(args, expected, optional = 0): - ''' Split an argument string in the desired number of arguments. ''' - split = args.split(' ', expected - 1) - if (len(split) < expected): - raise HumanReadableError('Expected at least {0} arguments, got {1}.'.format(expected, len(split))) - return split[:-1] + pad(split[-1].split(' ', optional), optional + 1, '') - -def do_sort(verbose = False): - start = perf_counter() - - hdata, buffers = get_buffers() - buffers = merge_buffer_list(buffers) - buffers = sort_buffers(hdata, buffers, config.rules, config.helpers, config.case_sensitive) - apply_buffer_order(buffers) - - elapsed = perf_counter() - start - if verbose: - log("Finished sorting buffers in {0:.4f} seconds.".format(elapsed)) - else: - debug("Finished sorting buffers in {0:.4f} seconds.".format(elapsed)) - -def command_sort(buffer, command, args): - ''' Sort the buffers and print a confirmation. ''' - do_sort(True) - return weechat.WEECHAT_RC_OK - -def command_debug(buffer, command, args): - hdata, buffers = get_buffers() - buffers = merge_buffer_list(buffers) - - # Show evaluation results. - log('Individual evaluation results:') - start = perf_counter() - key = buffer_sort_key(config.rules, config.helpers, config.case_sensitive) - results = [] - for merged in buffers: - for buffer in merged: - fullname = weechat.hdata_string(hdata, buffer, 'full_name') - results.append((fullname, key(buffer))) - elapsed = perf_counter() - start - - for fullname, result in results: - fullname = ensure_str(fullname) - result = [ensure_str(x) for x in result] - log('{0}: {1}'.format(fullname, result)) - log('Computing evaluation results took {0:.4f} seconds.'.format(elapsed)) - - return weechat.WEECHAT_RC_OK - -def command_rule_list(buffer, command, args): - ''' Show the list of sorting rules. ''' - output = 'Sorting rules:\n' - for i, rule in enumerate(config.rules): - output += ' {0}: {1}\n'.format(i, rule) - if not len(config.rules): - output += ' No sorting rules configured.\n' - log(output ) - - return weechat.WEECHAT_RC_OK - - -def command_rule_add(buffer, command, args): - ''' Add a rule to the rule list. ''' - config.rules.append(args) - config.save_rules() - command_rule_list(buffer, command, '') - - return weechat.WEECHAT_RC_OK - - -def command_rule_insert(buffer, command, args): - ''' Insert a rule at the desired position in the rule list. ''' - index, rule = split_args(args, 2) - index = parse_int(index, 'index') - - config.rules.insert(index, rule) - config.save_rules() - command_rule_list(buffer, command, '') - return weechat.WEECHAT_RC_OK - - -def command_rule_update(buffer, command, args): - ''' Update a rule in the rule list. ''' - index, rule = split_args(args, 2) - index = parse_int(index, 'index') - - config.rules[index] = rule - config.save_rules() - command_rule_list(buffer, command, '') - return weechat.WEECHAT_RC_OK - - -def command_rule_delete(buffer, command, args): - ''' Delete a rule from the rule list. ''' - index = args.strip() - index = parse_int(index, 'index') - - config.rules.pop(index) - config.save_rules() - command_rule_list(buffer, command, '') - return weechat.WEECHAT_RC_OK - - -def command_rule_move(buffer, command, args): - ''' Move a rule to a new position. ''' - index_a, index_b = split_args(args, 2) - index_a = parse_int(index_a, 'index') - index_b = parse_int(index_b, 'index') - - list_move(config.rules, index_a, index_b) - config.save_rules() - command_rule_list(buffer, command, '') - return weechat.WEECHAT_RC_OK - - -def command_rule_swap(buffer, command, args): - ''' Swap two rules. ''' - index_a, index_b = split_args(args, 2) - index_a = parse_int(index_a, 'index') - index_b = parse_int(index_b, 'index') - - list_swap(config.rules, index_a, index_b) - config.save_rules() - command_rule_list(buffer, command, '') - return weechat.WEECHAT_RC_OK - - -def command_helper_list(buffer, command, args): - ''' Show the list of helpers. ''' - output = 'Helper variables:\n' - - width = max(map(lambda x: len(x) if len(x) <= 30 else 0, config.helpers.keys())) - - for name, expression in sorted(config.helpers.items()): - output += ' {0:>{width}}: {1}\n'.format(name, expression, width=width) - if not len(config.helpers): - output += ' No helper variables configured.' - log(output) - - return weechat.WEECHAT_RC_OK - - -def command_helper_set(buffer, command, args): - ''' Add/update a helper to the helper list. ''' - name, expression = split_args(args, 2) - - config.helpers[name] = expression - config.save_helpers() - command_helper_list(buffer, command, '') - - return weechat.WEECHAT_RC_OK - -def command_helper_delete(buffer, command, args): - ''' Delete a helper from the helper list. ''' - name = args.strip() - - del config.helpers[name] - config.save_helpers() - command_helper_list(buffer, command, '') - return weechat.WEECHAT_RC_OK - - -def command_helper_rename(buffer, command, args): - ''' Rename a helper to a new position. ''' - old_name, new_name = split_args(args, 2) - - try: - config.helpers[new_name] = config.helpers[old_name] - del config.helpers[old_name] - except KeyError: - raise HumanReadableError('No such helper: {0}'.format(old_name)) - config.save_helpers() - command_helper_list(buffer, command, '') - return weechat.WEECHAT_RC_OK - - -def command_helper_swap(buffer, command, args): - ''' Swap two helpers. ''' - a, b = split_args(args, 2) - try: - config.helpers[b], config.helpers[a] = config.helpers[a], config.helpers[b] - except KeyError as e: - raise HumanReadableError('No such helper: {0}'.format(e.args[0])) - - config.helpers.swap(index_a, index_b) - config.save_helpers() - command_helper_list(buffer, command, '') - return weechat.WEECHAT_RC_OK - -def call_command(buffer, command, args, subcommands): - ''' Call a subcommand from a dictionary. ''' - subcommand, tail = pad(args.split(' ', 1), 2, '') - subcommand = subcommand.strip() - if (subcommand == ''): - child = subcommands.get(' ') - else: - command = command + [subcommand] - child = subcommands.get(subcommand) - - if isinstance(child, dict): - return call_command(buffer, command, tail, child) - elif callable(child): - return child(buffer, command, tail) - - log('{0}: command not found'.format(' '.join(command))) - return weechat.WEECHAT_RC_ERROR - -def on_signal(data, signal, signal_data): - global signal_delay_timer - global sort_queued - - # If the sort limit timeout is started, we're in the hold-off time after sorting, just queue a sort. - if sort_limit_timer is not None: - if sort_queued: - debug('Signal {0} ignored, sort limit timeout is active and sort is already queued.'.format(signal)) - else: - debug('Signal {0} received but sort limit timeout is active, sort is now queued.'.format(signal)) - sort_queued = True - return weechat.WEECHAT_RC_OK - - # If the signal delay timeout is started, a signal was recently received, so ignore this signal. - if signal_delay_timer is not None: - debug('Signal {0} ignored, signal delay timeout active.'.format(signal)) - return weechat.WEECHAT_RC_OK - - # Otherwise, start the signal delay timeout. - debug('Signal {0} received, starting signal delay timeout of {1} ms.'.format(signal, config.signal_delay)) - weechat.hook_timer(config.signal_delay, 0, 1, "on_signal_delay_timeout", "") - return weechat.WEECHAT_RC_OK - -def on_signal_delay_timeout(pointer, remaining_calls): - """ Called when the signal_delay_timer triggers. """ - global signal_delay_timer - global sort_limit_timer - global sort_queued - - signal_delay_timer = None - - # If the sort limit timeout was started, we're still in the no-sort period, so just queue a sort. - if sort_limit_timer is not None: - debug('Signal delay timeout expired, but sort limit timeout is active, sort is now queued.') - sort_queued = True - return weechat.WEECHAT_RC_OK - - # Time to sort! - debug('Signal delay timeout expired, starting sort.') - do_sort() - - # Start the sort limit timeout if not disabled. - if config.sort_limit > 0: - debug('Starting sort limit timeout of {0} ms.'.format(config.sort_limit)) - sort_limit_timer = weechat.hook_timer(config.sort_limit, 0, 1, "on_sort_limit_timeout", "") - - return weechat.WEECHAT_RC_OK - -def on_sort_limit_timeout(pointer, remainin_calls): - """ Called when de sort_limit_timer triggers. """ - global sort_limit_timer - global sort_queued - - # If no signal was received during the timeout, we're done. - if not sort_queued: - debug('Sort limit timeout expired without receiving a signal.') - sort_limit_timer = None - return weechat.WEECHAT_RC_OK - - # Otherwise it's time to sort. - debug('Signal received during sort limit timeout, starting queued sort.') - do_sort() - sort_queued = False - - # Start the sort limit timeout again if not disabled. - if config.sort_limit > 0: - debug('Starting sort limit timeout of {0} ms.'.format(config.sort_limit)) - sort_limit_timer = weechat.hook_timer(config.sort_limit, 0, 1, "on_sort_limit_timeout", "") - - return weechat.WEECHAT_RC_OK - - -def apply_config(): - # Unhook all signals and hook the new ones. - for hook in hooks: - weechat.unhook(hook) - for signal in config.signals: - hooks.append(weechat.hook_signal(signal, 'on_signal', '')) - - if config.sort_on_config: - debug('Sorting because configuration changed.') - do_sort() - -def on_config_changed(*args, **kwargs): - ''' Called whenever the configuration changes. ''' - config.reload() - apply_config() - - return weechat.WEECHAT_RC_OK - -def parse_arg(args): - if not args: return '', None - - result = '' - escaped = False - for i, c in enumerate(args): - if not escaped: - if c == '\\': - escaped = True - continue - elif c == ',': - return result, args[i+1:] - result += c - escaped = False - return result, None - -def parse_args(args, max = None): - result = [] - i = 0 - while max is None or i < max: - i += 1 - arg, args = parse_arg(args) - if arg is None: break - result.append(arg) - if args is None: break - return result, args - -def on_info_escape(pointer, name, arguments): - result = '' - for c in arguments: - if c == '\\': - result += '\\\\' - elif c == ',': - result += '\\,' - else: - result +=c - return result - -def on_info_replace(pointer, name, arguments): - arguments, rest = parse_args(arguments, 3) - if rest or len(arguments) < 3: - log('usage: ${{info:{0},old,new,text}}'.format(name)) - return '' - old, new, text = arguments - - return text.replace(old, new) - -def on_info_order(pointer, name, arguments): - arguments, rest = parse_args(arguments) - if len(arguments) < 1: - log('usage: ${{info:{0},value,first,second,third,...}}'.format(name)) - return '' - - value = arguments[0] - keys = arguments[1:] - if not keys: return '0' - - # Find the value in the keys (or '*' if we can't find it) - result = list_find(keys, value) - if result is None: result = list_find(keys, '*') - if result is None: result = len(keys) - - # Pad result with leading zero to make sure string sorting works. - width = int(math.log10(len(keys))) + 1 - return '{0:0{1}}'.format(result, width) - - -def on_autosort_command(data, buffer, args): - ''' Called when the autosort command is invoked. ''' - try: - return call_command(buffer, ['/autosort'], args, { - ' ': command_sort, - 'sort': command_sort, - 'debug': command_debug, - - 'rules': { - ' ': command_rule_list, - 'list': command_rule_list, - 'add': command_rule_add, - 'insert': command_rule_insert, - 'update': command_rule_update, - 'delete': command_rule_delete, - 'move': command_rule_move, - 'swap': command_rule_swap, - }, - 'helpers': { - ' ': command_helper_list, - 'list': command_helper_list, - 'set': command_helper_set, - 'delete': command_helper_delete, - 'rename': command_helper_rename, - 'swap': command_helper_swap, - }, - }) - except HumanReadableError as e: - log(e) - return weechat.WEECHAT_RC_ERROR - -def add_completions(completion, words): - for word in words: - weechat.hook_completion_list_add(completion, word, 0, weechat.WEECHAT_LIST_POS_END) - -def autosort_complete_rules(words, completion): - if len(words) == 0: - add_completions(completion, ['add', 'delete', 'insert', 'list', 'move', 'swap', 'update']) - if len(words) == 1 and words[0] in ('delete', 'insert', 'move', 'swap', 'update'): - add_completions(completion, map(str, range(len(config.rules)))) - if len(words) == 2 and words[0] in ('move', 'swap'): - add_completions(completion, map(str, range(len(config.rules)))) - if len(words) == 2 and words[0] in ('update'): - try: - add_completions(completion, [config.rules[int(words[1])]]) - except KeyError: pass - except ValueError: pass - else: - add_completions(completion, ['']) - return weechat.WEECHAT_RC_OK - -def autosort_complete_helpers(words, completion): - if len(words) == 0: - add_completions(completion, ['delete', 'list', 'rename', 'set', 'swap']) - elif len(words) == 1 and words[0] in ('delete', 'rename', 'set', 'swap'): - add_completions(completion, sorted(config.helpers.keys())) - elif len(words) == 2 and words[0] == 'swap': - add_completions(completion, sorted(config.helpers.keys())) - elif len(words) == 2 and words[0] == 'rename': - add_completions(completion, sorted(config.helpers.keys())) - elif len(words) == 2 and words[0] == 'set': - try: - add_completions(completion, [config.helpers[words[1]]]) - except KeyError: pass - return weechat.WEECHAT_RC_OK - -def on_autosort_complete(data, name, buffer, completion): - cmdline = weechat.buffer_get_string(buffer, "input") - cursor = weechat.buffer_get_integer(buffer, "input_pos") - prefix = cmdline[:cursor] - words = prefix.split()[1:] - - # If the current word isn't finished yet, - # ignore it for coming up with completion suggestions. - if prefix[-1] != ' ': words = words[:-1] - - if len(words) == 0: - add_completions(completion, ['debug', 'helpers', 'rules', 'sort']) - elif words[0] == 'rules': - return autosort_complete_rules(words[1:], completion) - elif words[0] == 'helpers': - return autosort_complete_helpers(words[1:], completion) - return weechat.WEECHAT_RC_OK - -command_description = r'''{*white}# General commands{reset} - -{*white}/autosort {brown}sort{reset} -Manually trigger the buffer sorting. - -{*white}/autosort {brown}debug{reset} -Show the evaluation results of the sort rules for each buffer. - - -{*white}# Sorting rule commands{reset} - -{*white}/autosort{brown} rules list{reset} -Print the list of sort rules. - -{*white}/autosort {brown}rules add {cyan}<expression>{reset} -Add a new rule at the end of the list. - -{*white}/autosort {brown}rules insert {cyan}<index> <expression>{reset} -Insert a new rule at the given index in the list. - -{*white}/autosort {brown}rules update {cyan}<index> <expression>{reset} -Update a rule in the list with a new expression. - -{*white}/autosort {brown}rules delete {cyan}<index> -Delete a rule from the list. - -{*white}/autosort {brown}rules move {cyan}<index_from> <index_to>{reset} -Move a rule from one position in the list to another. - -{*white}/autosort {brown}rules swap {cyan}<index_a> <index_b>{reset} -Swap two rules in the list - - -{*white}# Helper variable commands{reset} - -{*white}/autosort {brown}helpers list -Print the list of helper variables. - -{*white}/autosort {brown}helpers set {cyan}<name> <expression> -Add or update a helper variable with the given name. - -{*white}/autosort {brown}helpers delete {cyan}<name> -Delete a helper variable. - -{*white}/autosort {brown}helpers rename {cyan}<old_name> <new_name> -Rename a helper variable. - -{*white}/autosort {brown}helpers swap {cyan}<name_a> <name_b> -Swap the expressions of two helper variables in the list. - - -{*white}# Info hooks{reset} -Autosort comes with a number of info hooks to add some extra functionality to regular weechat eval strings. -Info hooks can be used in eval strings in the form of {cyan}${{info:some_hook,arguments}}{reset}. - -Commas and backslashes in arguments to autosort info hooks (except for {cyan}${{info:autosort_escape}}{reset}) must be escaped with a backslash. - -{*white}${{info:{brown}autosort_replace{white},{cyan}pattern{white},{cyan}replacement{white},{cyan}source{white}}}{reset} -Replace all occurrences of {cyan}pattern{reset} with {cyan}replacement{reset} in the string {cyan}source{reset}. -Can be used to ignore certain strings when sorting by replacing them with an empty string. - -For example: {cyan}${{info:autosort_replace,cat,dog,the dog is meowing}}{reset} expands to "the cat is meowing". - -{*white}${{info:{brown}autosort_order{white},{cyan}value{white},{cyan}option0{white},{cyan}option1{white},{cyan}option2{white},{cyan}...{white}}} -Generate a zero-padded number that corresponds to the index of {cyan}value{reset} in the list of options. -If one of the options is the special value {brown}*{reset}, then any value not explicitly mentioned will be sorted at that position. -Otherwise, any value that does not match an option is assigned the highest number available. -Can be used to easily sort buffers based on a manual sequence. - -For example: {cyan}${{info:autosort_order,${{server}},freenode,oftc,efnet}}{reset} will sort freenode before oftc, followed by efnet and then any remaining servers. -Alternatively, {cyan}${{info:autosort_order,${{server}},freenode,oftc,*,efnet}}{reset} will sort any unlisted servers after freenode and oftc, but before efnet. - -{*white}${{info:{brown}autosort_escape{white},{cyan}text{white}}}{reset} -Escape commas and backslashes in {cyan}text{reset} by prepending them with a backslash. -This is mainly useful to pass arbitrary eval strings as arguments to other autosort info hooks. -Otherwise, an eval string that expands to something with a comma would be interpreted as multiple arguments. - -For example, it can be used to safely pass buffer names to {cyan}${{info:autosort_replace}}{reset} like so: -{cyan}${{info:autosort_replace,##,#,${{info:autosort_escape,${{buffer.name}}}}}}{reset}. - - -{*white}# Description -Autosort is a weechat script to automatically keep your buffers sorted. The sort -order can be customized by defining your own sort rules, but the default should -be sane enough for most people. It can also group IRC channel/private buffers -under their server buffer if you like. - -Autosort uses a stable sorting algorithm, meaning that you can manually move buffers -to change their relative order, if they sort equal with your rule set. - -{*white}# Sort rules{reset} -Autosort evaluates a list of eval expressions (see {*default}/help eval{reset}) and sorts the -buffers based on evaluated result. Earlier rules will be considered first. Only -if earlier rules produced identical results is the result of the next rule -considered for sorting purposes. - -You can debug your sort rules with the `{*default}/autosort debug{reset}` command, which will -print the evaluation results of each rule for each buffer. - -{*brown}NOTE:{reset} The sort rules for version 3 are not compatible with version 2 or vice -versa. You will have to manually port your old rules to version 3 if you have any. - -{*white}# Helper variables{reset} -You may define helper variables for the main sort rules to keep your rules -readable. They can be used in the main sort rules as variables. For example, -a helper variable named `{cyan}foo{reset}` can be accessed in a main rule with the -string `{cyan}${{foo}}{reset}`. - -{*white}# Automatic or manual sorting{reset} -By default, autosort will automatically sort your buffer list whenever a buffer -is opened, merged, unmerged or renamed. This should keep your buffers sorted in -almost all situations. However, you may wish to change the list of signals that -cause your buffer list to be sorted. Simply edit the `{cyan}autosort.sorting.signals{reset}` -option to add or remove any signal you like. - -If you remove all signals you can still sort your buffers manually with the -`{*default}/autosort sort{reset}` command. To prevent all automatic sorting, the option -`{cyan}autosort.sorting.sort_on_config_change{reset}` should also be disabled. - -{*white}# Recommended settings -For the best visual effect, consider setting the following options: - {*white}/set {cyan}irc.look.server_buffer{reset} {brown}independent{reset} - -This setting allows server buffers to be sorted independently, which is -needed to create a hierarchical tree view of the server and channel buffers. - -If you are using the {*default}buflist{reset} plugin you can (ab)use Unicode to draw a tree -structure with the following setting (modify to suit your need): - {*white}/set {cyan}buflist.format.indent {brown}"${{color:237}}${{if:${{buffer.next_buffer.local_variables.type}}=~^(channel|private)$?├─:└─}}"{reset} -''' - -command_completion = '%(plugin_autosort) %(plugin_autosort) %(plugin_autosort) %(plugin_autosort) %(plugin_autosort)' - -info_replace_description = ( - 'Replace all occurrences of `pattern` with `replacement` in the string `source`. ' - 'Can be used to ignore certain strings when sorting by replacing them with an empty string. ' - 'See /help autosort for examples.' -) -info_replace_arguments = 'pattern,replacement,source' - -info_order_description = ( - 'Generate a zero-padded number that corresponds to the index of `value` in the list of options. ' - 'If one of the options is the special value `*`, then any value not explicitly mentioned will be sorted at that position. ' - 'Otherwise, any value that does not match an option is assigned the highest number available. ' - 'Can be used to easily sort buffers based on a manual sequence. ' - 'See /help autosort for examples.' -) -info_order_arguments = 'value,first,second,third,...' - -info_escape_description = ( - 'Escape commas and backslashes in `text` by prepending them with a backslash. ' - 'This is mainly useful to pass arbitrary eval strings as arguments to other autosort info hooks. ' - 'Otherwise, an eval string that expands to something with a comma would be interpreted as multiple arguments.' - 'See /help autosort for examples.' -) -info_escape_arguments = 'text' - - -if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""): - config = Config('autosort') - - colors = { - 'default': weechat.color('default'), - 'reset': weechat.color('reset'), - 'black': weechat.color('black'), - 'red': weechat.color('red'), - 'green': weechat.color('green'), - 'brown': weechat.color('brown'), - 'yellow': weechat.color('yellow'), - 'blue': weechat.color('blue'), - 'magenta': weechat.color('magenta'), - 'cyan': weechat.color('cyan'), - 'white': weechat.color('white'), - '*default': weechat.color('*default'), - '*black': weechat.color('*black'), - '*red': weechat.color('*red'), - '*green': weechat.color('*green'), - '*brown': weechat.color('*brown'), - '*yellow': weechat.color('*yellow'), - '*blue': weechat.color('*blue'), - '*magenta': weechat.color('*magenta'), - '*cyan': weechat.color('*cyan'), - '*white': weechat.color('*white'), - } - - weechat.hook_config('autosort.*', 'on_config_changed', '') - weechat.hook_completion('plugin_autosort', '', 'on_autosort_complete', '') - weechat.hook_command('autosort', command_description.format(**colors), '', '', command_completion, 'on_autosort_command', '') - weechat.hook_info('autosort_escape', info_escape_description, info_escape_arguments, 'on_info_escape', '') - weechat.hook_info('autosort_replace', info_replace_description, info_replace_arguments, 'on_info_replace', '') - weechat.hook_info('autosort_order', info_order_description, info_order_arguments, 'on_info_order', '') - - apply_config() diff -r 93d27886c099 -r 62e329839625 weechat/python/colon_complete.py --- a/weechat/python/colon_complete.py Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -SCRIPT_NAME='coloncomplete' -SCRIPT_AUTHOR='Steve Losh <steve@stevelosh.com>' -SCRIPT_VERSION='1.0' -SCRIPT_LICENSE='MIT/X11' -SCRIPT_DESC='Add a colon after nick completion when all the previous words in the input are also nicks.' - -EXTRA_NICKS = ['all', 'backend', 'clojerks', 'ops', 'support'] - -import_ok=True - -try: - import weechat -except ImportError: - print 'This script must be run under WeeChat' - print 'You can obtain a copy of WeeChat, for free, at http://www.weechat.org' - import_ok=False - -weechat_version=0 - -def get_nicks(buffer, prefix=''): - channel = weechat.buffer_get_string(buffer, 'localvar_channel') - server = weechat.buffer_get_string(buffer, 'localvar_server') - prefix = prefix.lower() - - matches = [] - - infolist = weechat.infolist_get('irc_nick', '', '%s,%s' % (server, channel)) - while weechat.infolist_next(infolist): - nick = weechat.infolist_string(infolist, 'name') - if nick != 'localhost' and nick.lower().startswith(prefix): - matches.append(nick) - weechat.infolist_free(infolist) - - for nick in EXTRA_NICKS: - if nick.lower().startswith(prefix): - matches.append(nick) - - return matches - -def completer(data, buffer, command): - cb = weechat.current_buffer() - if command == "/input complete_next": - line = weechat.buffer_get_string(cb, "input") - words = line.split(' ') - prefix = words[-1] - if prefix and words and all([s.endswith(':') for s in words[:-1] if s]): - nicks = get_nicks(cb, prefix) - if len(nicks) == 1: - for _ in range(len(prefix)): - weechat.command(buffer, "/input delete_previous_char") - weechat.command(buffer, "/input insert " + nicks[-1] + ":\\x20") - elif len(nicks) > 1: - l = min(len(nick) for nick in nicks) - for i in range(len(prefix), l): - if len(set(nick[i] for nick in nicks)) > 1: - break - else: - weechat.command(buffer, "/input insert " + nicks[0][i]) - - for nick in nicks: - weechat.prnt(cb, "==> " + nick) - return weechat.WEECHAT_RC_OK_EAT - - return weechat.WEECHAT_RC_OK - -if __name__ == "__main__" and import_ok: - if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""): - weechat_version = weechat.info_get("version_number", "") or 0 - weechat.hook_command_run('/input complete*', 'completer', '') diff -r 93d27886c099 -r 62e329839625 weechat/python/listbuffer.py --- a/weechat/python/listbuffer.py Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,467 +0,0 @@ -# -*- coding: utf-8 -*- -# -# ListBuffer, version 0.8.1 for WeeChat version 0.3 -# Latest development version: https://github.com/FiXato/listbuffer -# -# Show /list results in a common buffer and interact with them. -# -# This script allows you to easily join channels from the /list output. -# It will open a common buffer for the /list result, through which you -# browse with your cursor keys, and join with the meta-enter keys. -# Adjust sorting with meta->, meta-< and meta-/ keybindings. -# -## History: -### 2011-09-08: FiXato: -# -# * version 0.1: initial release. -# * added a common buffer for /list results -# * added highlighting for currently selected line -# * added /join support via enter key -# * added scroll_top and scroll_bottom support -# -# * version 0.2: /list format bugfix -# * added support for /list results without modes -# * some servers don't send 321 (/list start). Taken into account. -# -# * version 0.3: Sorting support -# * Added some basic sorting support. Scroll through sort options -# with meta-> and meta-< (users, channel, topic, modes) -# -### 2011-09-19: FiXato -# -# * version 0.4: -# * Case-insensitive buffer lookup fix. -# * Removed default enter keybind -# -### 2011-12-28: troydm: -# -# * version 0.5: It's an upside-down-world -# * Added inverted sorting support provided by Dmitry "troydm" Geurkov -# Use meta-/ to switch between inverted and regular sorting. -# -### 2012-02-10: FiXato: -# -# * version 0.6: Stop shoving that buffer in my face! -# * The listbuffer should no longer pop up by itself when you load the script. -# It should only pop up now when you actually do a /list query. -# -# * version 0.7: .. but please pop it up in my current window when I ask for it -# * Added setting plugins.var.python.listbuffer.autofocus -# This will autofocus the listbuffer in the current window if another window isn't -# already showing it, and of course only when the user issues /list -# -### 2012-07-10: FiXato: -# -# * version 0.7.1: Forgetful bugfix -# * Made sure lb_curline global variable is defined -# -### 2013-03-19: FiXato: -# -# * version 0.8: Sorted out the sorting -# * Added automatically updating options for sorting: -# * plugins.var.python.listbuffer.sort_inverted -# * plugins.var.python.listbuffer.sort_order -# * version 0.8.1: Pad it baby! -# * Channel modes are equally padded even when there are no channel modes. -# * Added padding options: -# * plugins.var.python.listbuffer.modes_min_width -# * plugins.var.python.listbuffer.channel_min_width -# * plugins.var.python.listbuffer.users_min_width -# -## Acknowledgements: -# * Dmitry "troydm" Geurkov, for providing the inverse-sorting patch to the project. -# * Sebastien "Flashcode" Helleu, for developing the kick-ass IRC client WeeChat -# and the iset.pl script which inspired me to this script. -# * Nils "nils_2" Görs, for his contributions to iset.pl which served as -# example code. -# * David "drubin" Rubin, for his urlgrab.py script, which also served -# as example code. -# * ArZa, whose listsort.pl script helped me getting started with -# grabbing the /list results. Parts of his code have been shamelessly -# copied and ported to Python. -# * Khaled Mardam-Bey, for making me yearn for similar /list support in -# WeeChat as mIRC already offered. :P -# * mave_, for pointing out that sort orders weren't remembered. -# -## TODO: -# - Auto-scroll selected line upon window scroll. -# - Add option to hide already joined channels. -# - Improve sorting methods -# - Add auto-join support -# - Detect if channel is already in auto-join -# - Allow automatically switching to the listbuffer -# - Add support for ALIS (/squery alis LIST * -mix 100 (IRCNet) -# - Make colours configurable -# - Limit number of channels to parse -# - Add filter support a la iset -# - Allow selecting multiple channels -# - Add optional command redirection. -# -## Copyright (c) 2011,2012,2013 Filip H.F. "FiXato" Slagter, -# <FiXato [at] Gmail [dot] com> -# http://profile.fixato.org -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -SCRIPT_NAME = "listbuffer" -SCRIPT_AUTHOR = "Filip H.F. 'FiXato' Slagter <fixato [at] gmail [dot] com>" -SCRIPT_VERSION = "0.8.1" -SCRIPT_LICENSE = "MIT" -SCRIPT_DESC = "A common buffer for /list output." -SCRIPT_COMMAND = "listbuffer" - -import_ok = True - -try: - import weechat -except ImportError: - print "This script must be run under WeeChat." - import_ok = False - -import re - -lb_settings = ( - ("autofocus", "on", "Focus the listbuffer in the current window if it isn't already displayed by a window."), - ("sort_order", "users", "Last used sort order for the channel list."), - ("sort_inverted", "on", "Invert the sort order for the channel list."), - ("modes_min_width", "8", "The minimum width used for modes in the channel list. If a channel has less modes than this amount, the column will be padded with spaces."), - ("channel_min_width", "25", "The minimum width used for the channel name in the channel list. If a channelname is shorter than this amount, the column will be padded with spaces."), - ("users_min_width", "8", "The minimum width used for the usercount in the channel list. If the usercount has less digits than this amount, the column will be padded with spaces."), -) -lb_buffer = None -lb_curline = 0 -lb_channels = [] -lb_network = None -lb_list_started = False -lb_current_sort = None -lb_sort_inverted = False -lb_sort_options = ( - 'channel', - 'users', - 'modes', - 'topic', -) - -# server numeric Nick Chan Users Modes Topic -lb_channel_list_expression = '(:\S+) (\d{3}) (\S+) (\S+) (\d+) :(\[(.*?)\] )?(.*)' - -# Create listbuffer. -def lb_create_buffer(): - global lb_buffer, lb_curline - - if not lb_buffer: - lb_buffer = weechat.buffer_new("listbuffer", "lb_input_cb", \ - "", "lb_close_cb", "") - lb_set_buffer_title() - # Sets notify to 0 as this buffer does not need to be in hotlist. - weechat.buffer_set(lb_buffer, "notify", "0") - weechat.buffer_set(lb_buffer, "nicklist", "0") - weechat.buffer_set(lb_buffer, "type", "free") - weechat.buffer_set(lb_buffer, "key_bind_ctrl-L", "/listbuffer **refresh") - weechat.buffer_set(lb_buffer, "key_bind_meta2-A", "/listbuffer **up") - weechat.buffer_set(lb_buffer, "key_bind_meta2-B", "/listbuffer **down") - weechat.buffer_set(lb_buffer, "key_bind_meta2-1~", "/listbuffer **scroll_top") - weechat.buffer_set(lb_buffer, "key_bind_meta2-4~", "/listbuffer **scroll_bottom") - weechat.buffer_set(lb_buffer, "key_bind_meta-ctrl-J", "/listbuffer **enter") - weechat.buffer_set(lb_buffer, "key_bind_meta-ctrl-M", "/listbuffer **enter") - weechat.buffer_set(lb_buffer, "key_bind_meta->", "/listbuffer **sort_next") - weechat.buffer_set(lb_buffer, "key_bind_meta-<", "/listbuffer **sort_previous") - weechat.buffer_set(lb_buffer, "key_bind_meta-/", "/listbuffer **sort_invert") - lb_curline = 0 - if weechat.config_get_plugin("autofocus") == "on": - if not weechat.window_search_with_buffer(lb_buffer): - weechat.command("", "/buffer " + weechat.buffer_get_string(lb_buffer,"name")) - -def lb_set_buffer_title(): - global lb_buffer, lb_current_sort - ascdesc = '(v)' if lb_sort_inverted else '(^)' - weechat.buffer_set(lb_buffer, "title", lb_line_format({ - 'channel': 'Channel name%s' % (ascdesc if lb_current_sort == 'channel' else ''), - 'users': 'Users%s' % (ascdesc if lb_current_sort == 'users' else ''), - 'modes': 'Modes%s' % (ascdesc if lb_current_sort == 'modes' else ''), - 'topic': 'Topic%s' % (ascdesc if lb_current_sort == 'topic' else ''), - 'nomodes': None, - })) - -def lb_list_start(data, signal, message): - lb_initialise_list - - return weechat.WEECHAT_RC_OK - -def lb_initialise_list(signal): - global lb_channels, lb_network, lb_list_started - - lb_create_buffer() - lb_channels = [] - lb_network = signal.split(',')[0] - lb_list_started = True - return - - -def lb_list_chan(data, signal, message): - global lb_channels, lb_buffer, lb_list_started - - # Work-around for IRCds which don't send 321 Numeric (/List start) - if not lb_list_started: - lb_initialise_list(signal) - - for chan_data in re.findall(lb_channel_list_expression,message): - lb_channels.append({ - 'server': chan_data[0][1:-1], - 'numeric': chan_data[1], - 'nick': chan_data[2], - 'channel': chan_data[3], - 'users': chan_data[4], - 'nomodes': chan_data[5] == '', - 'modes': chan_data[6], - 'topic': weechat.hook_modifier_exec("irc_color_decode", "1", chan_data[7]) - }) - return weechat.WEECHAT_RC_OK - -def lb_list_end(data, signal, message): - global lb_list_started - - # Work-around for IRCds which don't send 321 Numeric (/List start) - if not lb_list_started: - lb_initialise_list(signal) - - lb_list_started = False - if lb_current_sort: - lb_sort() - lb_refresh() - return weechat.WEECHAT_RC_OK - -def keyEvent (data, buffer, args): - global lb_options - lb_options[args]() - -def lb_input_cb(data, buffer, input_data): - global lb_options, lb_curline - lb_options[input_data]() - return weechat.WEECHAT_RC_OK - -def lb_refresh(): - global lb_channels, lb_buffer - weechat.buffer_clear(lb_buffer) - - y = 0 - for list_data in lb_channels: - lb_refresh_line(y) - y += 1 - return - -def lb_refresh_line(y): - global lb_buffer, lb_curline, lb_channels - if y >= 0 and y < len(lb_channels): - formatted_line = lb_line_format(lb_channels[y], y == lb_curline) - weechat.prnt_y(lb_buffer, y, formatted_line) - -def lb_refresh_curline(): - global lb_curline - lb_refresh_line(lb_curline-1) - lb_refresh_line(lb_curline) - lb_refresh_line(lb_curline+1) - return - -def lb_line_format(list_data,curr=False): - str = "" - if (curr): - str += weechat.color("yellow,red") - channel_text = list_data['channel'].ljust(int(weechat.config_get_plugin('channel_min_width'))) - users_text = "(%s)" % list_data['users'] - padded_users_text = users_text.rjust(int(weechat.config_get_plugin('users_min_width')) + 2) - str += "%s%s %s " % (weechat.color("bold"), channel_text, padded_users_text) - if not list_data['nomodes']: - modes = "[%s]" % list_data['modes'] - else: - modes = "[]" - str += "%s: " % modes.rjust(int(weechat.config_get_plugin('modes_min_width')) + 2) - str += "%s" % list_data['topic'] - return str - -def lb_line_up(): - global lb_curline - if lb_curline <= 0: - return - lb_curline -= 1 - lb_refresh_curline() - lb_check_outside_window() - return - -def lb_line_down(): - global lb_curline, lb_channels - if lb_curline+1 >= len(lb_channels): - return - lb_curline += 1 - lb_refresh_curline() - lb_check_outside_window() - return - -def lb_line_run(): - global lb_channels, lb_curline, lb_network - buff = weechat.info_get("irc_buffer", lb_network) - channel = lb_channels[lb_curline]['channel'] - command = "/join %s" % channel - weechat.command(buff, command) - return - -def lb_line_select(): - return - -def lb_scroll_top(): - global lb_curline - old_y = lb_curline - lb_curline = 0 - lb_refresh_curline() - lb_refresh_line(old_y) - weechat.command(lb_buffer, "/window scroll_top") - return - -def lb_scroll_bottom(): - global lb_curline, lb_channels - old_y = lb_curline - lb_curline = len(lb_channels)-1 - lb_refresh_curline() - lb_refresh_line(old_y) - weechat.command(lb_buffer, "/window scroll_bottom") - return - -def lb_check_outside_window(): - global lb_buffer, lb_curline - if (lb_buffer): - infolist = weechat.infolist_get("window", "", "current") - if (weechat.infolist_next(infolist)): - start_line_y = weechat.infolist_integer(infolist, "start_line_y") - chat_height = weechat.infolist_integer(infolist, "chat_height") - if(start_line_y > lb_curline): - weechat.command(lb_buffer, "/window scroll -%i" %(start_line_y - lb_curline)) - elif(start_line_y <= lb_curline - chat_height): - weechat.command(lb_buffer, "/window scroll +%i"%(lb_curline - start_line_y - chat_height + 1)) - weechat.infolist_free(infolist) - -def lb_sort_next(): - global lb_current_sort, lb_sort_options - if lb_current_sort: - new_index = lb_sort_options.index(lb_current_sort) + 1 - else: - new_index = 0 - - if len(lb_sort_options) <= new_index: - new_index = 0 - - lb_set_current_sort_order(lb_sort_options[new_index]) - lb_sort() - -def lb_set_current_sort_order(value): - global lb_current_sort - lb_current_sort = value - weechat.config_set_plugin('sort_order', lb_current_sort) - -def lb_set_invert_sort_order(value): - global lb_sort_inverted - lb_sort_inverted = value - weechat.config_set_plugin('sort_inverted', ('on' if lb_sort_inverted else 'off')) - -def lb_sort_previous(): - global lb_current_sort, lb_sort_options - if lb_current_sort: - new_index = lb_sort_options.index(lb_current_sort) - 1 - else: - new_index = 0 - - if new_index < 0: - new_index = len(lb_sort_options) - 1 - - lb_set_current_sort_order(lb_sort_options[new_index]) - lb_sort() - -def lb_sort(sort_key=None): - global lb_channels, lb_current_sort, lb_sort_inverted - if sort_key: - lb_set_current_sort_order(sort_key) - if lb_current_sort == 'users': - lb_channels = sorted(lb_channels, key=lambda chan_data: int(chan_data[lb_current_sort])) - else: - lb_channels = sorted(lb_channels, key=lambda chan_data: chan_data[lb_current_sort]) - if lb_sort_inverted: - lb_channels.reverse() - lb_set_buffer_title() - lb_refresh() - -def lb_sort_invert(): - global lb_current_sort, lb_sort_inverted - if lb_current_sort: - lb_set_invert_sort_order(not lb_sort_inverted) - lb_sort() - -def lb_close_cb(*kwargs): - """ A callback for buffer closing. """ - global lb_buffer - - lb_buffer = None - return weechat.WEECHAT_RC_OK - -lb_options = { - 'refresh' : lb_refresh, - 'up' : lb_line_up, - 'down' : lb_line_down, - 'enter' : lb_line_run, - 'space' : lb_line_select, - 'scroll_top' : lb_scroll_top, - 'scroll_bottom': lb_scroll_bottom, - 'sort_next' : lb_sort_next, - 'sort_previous': lb_sort_previous, - 'sort_invert': lb_sort_invert -} - -def lb_command_main(data, buffer, args): - if args[0:2] == "**": - keyEvent(data, buffer, args[2:]) - return weechat.WEECHAT_RC_OK - -def lb_set_default_settings(): - global lb_settings - # Set default settings - for option, default_value, description in lb_settings: - if not weechat.config_is_set_plugin(option): - weechat.config_set_plugin(option, default_value) - version = weechat.info_get("version_number", "") or 0 - if int(version) >= 0x00030500: - weechat.config_set_desc_plugin(option, description) - -def lb_reset_stored_sort_order(): - global lb_current_sort, lb_sort_inverted - lb_current_sort = weechat.config_get_plugin('sort_order') - lb_sort_inverted = (True if weechat.config_get_plugin('sort_inverted') == 'on' else False) - -if __name__ == "__main__" and import_ok: - if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, - SCRIPT_LICENSE, SCRIPT_DESC, "lb_close_cb", ""): - lb_set_default_settings() - lb_reset_stored_sort_order() - lb_buffer = weechat.buffer_search("python", "listbuffer") - - weechat.hook_signal("*,irc_in_321", "lb_list_start", "") - weechat.hook_signal("*,irc_in_322", "lb_list_chan", "") - weechat.hook_signal("*,irc_in_323", "lb_list_end", "") - weechat.hook_command(SCRIPT_COMMAND, - "List Buffer", - "", "", "", - "lb_command_main", "") diff -r 93d27886c099 -r 62e329839625 weechat/python/sanitize_jira.py --- a/weechat/python/sanitize_jira.py Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -import re, weechat, subprocess - -SCRIPT_NAME = 'sanitize_jira' -SCRIPT_AUTHOR = 'Steve Losh <steve@stevelosh.com>' -SCRIPT_VERSION = '0.0.1' -SCRIPT_LICENSE = 'MIT' -SCRIPT_DESC = 'clean up the garbage jirabot sends to channels into something readable' - -weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, '', '') - -weechat.hook_line('*', '', 'nick_Jira_Cloud', 'sanitize_jira', '') - -first_line_re = re.compile( - r'(?P<link>https://[^/]+/browse/[^?]+)[?]atlOrigin=[^ ]+ [(](?P<title>.+)[)]' -) - -detail_line_re = re.compile( - r'''Status: \x1a\x01[*](?P<status>[^*]+)[*]\x1b\x01.*Type: \x1a\x01[*](?P<type>[^*]+)[*]\x1b\x01.*Assignee: \x1a\x01[*](?P<assignee>[^*]+)[*]\x1b\x01.*Priority: \x1a\x01[*](?P<priority>[^*]+)[*]\x1b\x01''' -) - -def sanitize_jira(data, line): - if 'sign up for an Atlassian account to view this link' in line['message']: - return {'message': ' '} - - m = first_line_re.search(line['message']) - if m: - return {'message': '%s | %s' % (m.group('title'), m.group('link'))} - - m = detail_line_re.search(line['message']) - if m: - return {'message': '%s / %s / %s' % (m.group('type'), m.group('status'), m.group('assignee'))} - - return {} diff -r 93d27886c099 -r 62e329839625 weechat/relay.conf --- a/weechat/relay.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -# -# weechat -- relay.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[look] -auto_open_buffer = on -raw_messages = 256 - -[color] -client = cyan -status_active = lightblue -status_auth_failed = lightred -status_connecting = yellow -status_disconnected = lightred -status_waiting_auth = brown -text = default -text_bg = default -text_selected = white - -[network] -allow_empty_password = off -allowed_ips = "" -auth_timeout = 60 -bind_address = "" -clients_purge_delay = 0 -compression = 20 -ipv6 = on -max_clients = 5 -nonce_size = 16 -password = "" -password_hash_algo = "*" -password_hash_iterations = 100000 -ssl_cert_key = "%h/ssl/relay.pem" -ssl_priorities = "NORMAL:-VERS-SSL3.0" -totp_secret = "" -totp_window = 0 -websocket_allowed_origins = "" - -[irc] -backlog_max_minutes = 1440 -backlog_max_number = 256 -backlog_since_last_disconnect = on -backlog_since_last_message = off -backlog_tags = "irc_privmsg" -backlog_time_format = "[%H:%M] " - -[weechat] -commands = "" - -[port] - -[path] diff -r 93d27886c099 -r 62e329839625 weechat/rmodifier.conf --- a/weechat/rmodifier.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -# -# rmodifier.conf -- weechat v0.4.3 -# - -[look] -hide_char = "*" - -[modifier] -nickserv = "history_add,input_text_display;^(/(msg|quote) +nickserv +(identify|ghost \S+) +)(.*);1,4*" -oper = "history_add,input_text_display;^(/oper +\S+ +)(.*);1,2*" -set_pass = "history_add;^(/set +\S*password\S* +)(.*);1,2*" diff -r 93d27886c099 -r 62e329839625 weechat/ruby.conf --- a/weechat/ruby.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -# -# weechat -- ruby.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart -# - -[look] -check_license = off -eval_keep_context = on diff -r 93d27886c099 -r 62e329839625 weechat/ruby/autoload/challengeauth.rb --- a/weechat/ruby/autoload/challengeauth.rb Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -# Copyright (c) 2013 Dominik Honnef <dominikh@fork-bomb.org> - -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -# History: -# 2013-04-20, Dominik Honnef -# version 0.0.1: initial version - -require "openssl" - -QBot = "Q@CServe.quakenet.org" -QBotHost = "Q!TheQBot@CServe.quakenet.org" -Request = Struct.new(:username, :hash) - -def weechat_init - @requests = {} - - Weechat.register("challengeauth", - "Dominik Honnef", - "0.0.1", - "MIT", - "Securely authenticate with QuakeNet by using CHALLENGEAUTH", - "", - "") - - Weechat.hook_command("challengeauth", - "Authenticate with Q using CHALLENGEAUTH", - "[username] [password]", - "", - "", - "challengeauth", - "") - - Weechat.hook_modifier("irc_in_notice", "challenge_notice", "") - - return Weechat::WEECHAT_RC_OK -end - -def calculate_q_hash(username, hash, challenge) - username = username.tr("A-Z[]\\\\^", "a-z{}|~") - - key = OpenSSL::Digest::SHA256.hexdigest("#{username}:#{hash}") - return OpenSSL::HMAC.hexdigest("SHA256", key, challenge) -end - -def get_server_buffer(server) - Weechat.buffer_search("irc", "server." + server) -end - -def challengeauth(data, buffer, args) - plugin = Weechat.buffer_get_string(buffer, "localvar_plugin") - if plugin != "irc" - Weechat.print(buffer, "/challengeauth only works for IRC buffers.") - return Weechat.WEECHAT_RC_ERROR - end - - server = Weechat.buffer_get_string(buffer, "localvar_server") - args = args.split(" ", 2) - username = args[0] - password = args[1] - hash = OpenSSL::Digest::SHA256.hexdigest(password[0, 10]) - - @requests[server] = Request.new(username, hash) - server_buffer = get_server_buffer(server) - Weechat.print(server_buffer, "Authenticating as #{username}...") - Weechat.command(server_buffer, "/quote PRIVMSG #{QBot} :CHALLENGE") - - return Weechat::WEECHAT_RC_OK -end - -def challenge_notice(modifier, data, server, line) - return line unless @requests.has_key?(server) - - parts = line.split(" ") - return line unless parts.size > 5 - - host = parts[0][1..-1] - command = parts[3][1..-1] - challenge = parts[4] - - return line if host != QBotHost || command != "CHALLENGE" - - request = @requests[server] - response = calculate_q_hash(request.username, request.hash, challenge) - server_buffer = get_server_buffer(server) - - Weechat.print(server_buffer, "Sending challengeauth for #{request.username}...") - Weechat.command(server_buffer, - "/quote PRIVMSG %s :CHALLENGEAUTH %s %s HMAC-SHA-256" % [QBot, request.username, response]) - - @requests.delete(server) - - return line -end diff -r 93d27886c099 -r 62e329839625 weechat/script.conf --- a/weechat/script.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -# -# weechat -- script.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[look] -columns = "%s %n %V %v %u | %d | %t" -diff_color = on -diff_command = "auto" -display_source = on -quiet_actions = on -sort = "p,n" -translate_description = on -use_keys = on - -[color] -status_autoloaded = cyan -status_held = white -status_installed = lightcyan -status_obsolete = lightmagenta -status_popular = yellow -status_running = lightgreen -status_unknown = lightred -text = default -text_bg = default -text_bg_selected = red -text_date = default -text_date_selected = white -text_delimiters = darkgray -text_description = default -text_description_selected = white -text_extension = default -text_extension_selected = white -text_name = cyan -text_name_selected = lightcyan -text_selected = white -text_tags = brown -text_tags_selected = yellow -text_version = magenta -text_version_loaded = default -text_version_loaded_selected = white -text_version_selected = lightmagenta - -[scripts] -autoload = on -cache_expire = 60 -download_enabled = on -download_timeout = 30 -hold = "" -path = "%h/script" -url = "http://www.weechat.org/files/plugins.xml.gz" diff -r 93d27886c099 -r 62e329839625 weechat/spell.conf --- a/weechat/spell.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -# -# weechat -- spell.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart -# - -[color] -misspelled = lightred -suggestion = default -suggestion_delimiter_dict = cyan -suggestion_delimiter_word = cyan - -[check] -commands = "away,command,cycle,kick,kickban,me,msg,notice,part,query,quit,topic" -default_dict = "" -during_search = off -enabled = off -real_time = off -suggestions = -1 -word_min_length = 2 - -[dict] - -[look] -suggestion_delimiter_dict = " / " -suggestion_delimiter_word = "," - -[option] diff -r 93d27886c099 -r 62e329839625 weechat/tcl.conf --- a/weechat/tcl.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -# -# weechat -- tcl.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use /set or similar command to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart -# - -[look] -check_license = off -eval_keep_context = on diff -r 93d27886c099 -r 62e329839625 weechat/trigger.conf --- a/weechat/trigger.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -# -# weechat -- trigger.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[look] -enabled = on -monitor_strip_colors = off - -[color] -flag_command = lightgreen -flag_conditions = yellow -flag_post_action = lightblue -flag_regex = lightcyan -flag_return_code = lightmagenta -regex = white -replace = cyan -trigger = green -trigger_disabled = red - -[trigger] -beep.arguments = "" -beep.command = "/print -beep" -beep.conditions = "${tg_highlight} || ${tg_msg_pv}" -beep.enabled = on -beep.hook = print -beep.post_action = none -beep.regex = "" -beep.return_code = ok -cmd_pass.arguments = "5000|input_text_display;5000|history_add;5000|irc_command_auth" -cmd_pass.command = "" -cmd_pass.conditions = "" -cmd_pass.enabled = on -cmd_pass.hook = modifier -cmd_pass.post_action = none -cmd_pass.regex = "==^((/(msg|quote) +nickserv +(id|identify|register|ghost +[^ ]+|release +[^ ]+|regain +[^ ]+) +)|/oper +[^ ]+ +|/quote +pass +|/set +[^ ]*password[^ ]* +|/secure +(passphrase|decrypt|set +[^ ]+) +)(.*)==$1$.*+" -cmd_pass.return_code = ok -dumbass_buffer.arguments = "4000|input_text_for_buffer;4000|history_add" -dumbass_buffer.command = "" -dumbass_buffer.conditions = "" -dumbass_buffer.enabled = on -dumbass_buffer.hook = modifier -dumbass_buffer.post_action = none -dumbass_buffer.regex = "==^ +/?b (.+)==/b ${re:1}" -dumbass_buffer.return_code = ok -idiot_buffer.arguments = "4000|input_text_for_buffer;4000|history_add" -idiot_buffer.command = "" -idiot_buffer.conditions = "" -idiot_buffer.enabled = on -idiot_buffer.hook = modifier -idiot_buffer.post_action = none -idiot_buffer.regex = "==^b (.+)==/b ${re:1}" -idiot_buffer.return_code = ok -msg_auth.arguments = "5000|irc_message_auth" -msg_auth.command = "" -msg_auth.conditions = "" -msg_auth.enabled = on -msg_auth.hook = modifier -msg_auth.post_action = none -msg_auth.regex = "==^(.*(id|identify|register|ghost +[^ ]+|release +[^ ]+) +)(.*)==$1$.*+" -msg_auth.return_code = ok -server_pass.arguments = "5000|input_text_display;5000|history_add" -server_pass.command = "" -server_pass.conditions = "" -server_pass.enabled = on -server_pass.hook = modifier -server_pass.post_action = none -server_pass.regex = "==^(/(server|connect) .*-(sasl_)?password=)([^ ]+)(.*)==$1$.*4$5" -server_pass.return_code = ok -uncc.arguments = "weechat_print" -uncc.command = "" -uncc.conditions = "${tg_tag_nick}" -uncc.enabled = on -uncc.hook = modifier -uncc.post_action = none -uncc.regex = "== \[cc: [^ ]+\]====" -uncc.return_code = ok diff -r 93d27886c099 -r 62e329839625 weechat/typing.conf --- a/weechat/typing.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -# -# weechat -- typing.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[look] -delay_purge_paused = 30 -delay_purge_typing = 6 -delay_set_paused = 10 -enabled_nicks = off -enabled_self = off -input_min_chars = 4 -item_max_length = 0 diff -r 93d27886c099 -r 62e329839625 weechat/urlgrab.conf --- a/weechat/urlgrab.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +0,0 @@ -# -# weechat -- urlgrab.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[color] -color_bg_selected = green -color_buffer = red -color_buffer_selected = red -color_time = cyan -color_time_selected = cyan -color_url = blue -color_url_selected = blue - -[default] -copycmd = "xsel -i" -historysize = 20 -localcmd = "xdg-open %s" -method = "local" -output_main_buffer = off -remotecmd = "ssh -x localhost -i ~/.ssh/id_rsa -C "export DISPLAY=":0.0" && firefox %s"" -time_format = "%H:%M:%S" -url_log = "~/.weechat/urls.log" diff -r 93d27886c099 -r 62e329839625 weechat/weechat.conf --- a/weechat/weechat.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,693 +0,0 @@ -# -# WeeChat -- weechat.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart -# - -[debug] - -[startup] -command_after_plugins = "" -command_before_plugins = "" -display_logo = on -display_version = on -sys_rlimit = "" - -[look] -align_end_of_lines = message -align_multiline_words = on -bar_more_down = "++" -bar_more_left = "<<" -bar_more_right = ">>" -bar_more_up = "--" -bare_display_exit_on_input = on -bare_display_time_format = "%H:%M" -buffer_auto_renumber = on -buffer_notify_default = all -buffer_position = end -buffer_search_case_sensitive = off -buffer_search_force_default = off -buffer_search_regex = off -buffer_search_where = prefix_message -buffer_time_format = "%H:%M" -buffer_time_same = "" -color_basic_force_bold = off -color_inactive_buffer = off -color_inactive_message = on -color_inactive_prefix = on -color_inactive_prefix_buffer = on -color_inactive_time = off -color_inactive_window = off -color_nick_offline = off -color_pairs_auto_reset = 5 -color_real_white = off -command_chars = "" -command_incomplete = off -confirm_quit = off -confirm_upgrade = off -day_change = on -day_change_message_1date = "-- %a, %d %b %Y --" -day_change_message_2dates = "-- %%a, %%d %%b %%Y (%a, %d %b %Y) --" -eat_newline_glitch = off -emphasized_attributes = "" -highlight = "sjl,slosh,slj,horrifying,steve.losh,@steve.losh,stevelosh" -highlight_regex = "(steve losh|rob ford|(jesus )?fucking christ|(horse|mouse|clown)fuckers?|((mother)?fuck([ie]ng?|er)?|(god?)?damn(ed)?|dammit|(bull|horse)?shite?){3,})" -highlight_tags = "" -hotlist_add_conditions = "${away} || ${buffer.num_displayed} == 0" -hotlist_buffer_separator = ", " -hotlist_count_max = 2 -hotlist_count_min_msg = 2 -hotlist_names_count = 3 -hotlist_names_length = 0 -hotlist_names_level = 12 -hotlist_names_merged_buffers = off -hotlist_prefix = "H: " -hotlist_remove = merged -hotlist_short_names = on -hotlist_sort = group_time_asc -hotlist_suffix = "" -hotlist_unique_numbers = on -hotlist_update_on_buffer_switch = on -input_cursor_scroll = 20 -input_share = none -input_share_overwrite = off -input_undo_max = 32 -item_away_message = on -item_buffer_filter = "*" -item_buffer_zoom = "!" -item_mouse_status = "M" -item_time_format = "%H:%M" -jump_current_to_previous_buffer = on -jump_previous_buffer_when_closing = on -jump_smart_back_to_buffer = on -key_bind_safe = on -key_grab_delay = 800 -mouse = off -mouse_timer_delay = 100 -nick_color_force = "" -nick_color_hash = djb2 -nick_color_hash_salt = "" -nick_color_stop_chars = "_|[" -nick_prefix = "" -nick_suffix = "" -paste_auto_add_newline = on -paste_bracketed = off -paste_bracketed_timer_delay = 10 -paste_max_lines = 3 -prefix_action = " *" -prefix_align = right -prefix_align_max = 15 -prefix_align_min = 0 -prefix_align_more = "+" -prefix_align_more_after = on -prefix_buffer_align = right -prefix_buffer_align_max = 0 -prefix_buffer_align_more = "+" -prefix_buffer_align_more_after = on -prefix_error = "=!=" -prefix_join = "✔" -prefix_network = "--" -prefix_quit = "✘" -prefix_same_nick = "" -prefix_same_nick_middle = "" -prefix_suffix = "|" -quote_nick_prefix = "<" -quote_nick_suffix = ">" -quote_time_format = "%H:%M:%S" -read_marker = line -read_marker_always_show = on -read_marker_string = "─" -read_marker_update_on_buffer_switch = on -save_config_on_exit = off -save_config_with_fsync = off -save_layout_on_exit = all -scroll_amount = 3 -scroll_bottom_after_switch = off -scroll_page_percent = 100 -search_text_not_found_alert = on -separator_horizontal = "-" -separator_vertical = "" -tab_width = 1 -time_format = "%a, %d %b %Y %T" -window_auto_zoom = off -window_separator_horizontal = on -window_separator_vertical = on -window_title = "" -word_chars_highlight = "!\u00A0,-,_,|,@,.,alnum" -word_chars_input = "!\u00A0,-,_,|,alnum" - -[palette] - -[color] -bar_more = magenta -chat = default -chat_bg = default -chat_buffer = white -chat_channel = white -chat_day_change = cyan -chat_delimiters = green -chat_highlight = 207 -chat_highlight_bg = default -chat_host = cyan -chat_inactive_buffer = darkgray -chat_inactive_window = darkgray -chat_nick = lightcyan -chat_nick_colors = "027,048,068,028,081,082,099,112,129,136,169,178,208,226,113,196,161,23,59,222" -chat_nick_offline = darkgray -chat_nick_offline_highlight = default -chat_nick_offline_highlight_bg = darkgray -chat_nick_other = cyan -chat_nick_prefix = green -chat_nick_self = white -chat_nick_suffix = green -chat_prefix_action = white -chat_prefix_buffer = brown -chat_prefix_buffer_inactive_buffer = darkgray -chat_prefix_error = yellow -chat_prefix_join = lightgreen -chat_prefix_more = lightmagenta -chat_prefix_network = magenta -chat_prefix_quit = lightred -chat_prefix_suffix = green -chat_read_marker = green -chat_read_marker_bg = default -chat_server = brown -chat_tags = red -chat_text_found = yellow -chat_text_found_bg = lightmagenta -chat_time = 238 -chat_time_delimiters = 236 -chat_value = cyan -chat_value_null = blue -emphasized = yellow -emphasized_bg = magenta -input_actions = lightgreen -input_text_not_found = red -item_away = yellow -nicklist_away = cyan -nicklist_group = green -separator = green -status_count_highlight = magenta -status_count_msg = brown -status_count_other = 16 -status_count_private = green -status_data_highlight = lightmagenta -status_data_msg = yellow -status_data_other = 16 -status_data_private = lightgreen -status_filter = green -status_more = 16 -status_mouse = green -status_name = *16 -status_name_ssl = *16 -status_nicklist_count = default -status_number = 16 -status_time = *16 - -[completion] -base_word_until_cursor = on -command_inline = on -default_template = "%(nicks)|%(irc_channels)" -nick_add_space = on -nick_case_sensitive = off -nick_completer = ":" -nick_first_only = off -nick_ignore_chars = "[]`_-^" -partial_completion_alert = on -partial_completion_command = off -partial_completion_command_arg = off -partial_completion_count = on -partial_completion_other = off -partial_completion_templates = "config_options" - -[history] -display_default = 5 -max_buffer_lines_minutes = 0 -max_buffer_lines_number = 4096 -max_commands = 100 -max_visited_buffers = 50 - -[proxy] - -[network] -connection_timeout = 60 -gnutls_ca_system = on -gnutls_ca_user = "" -gnutls_handshake_timeout = 30 -proxy_curl = "" - -[plugin] -autoload = "*" -debug = off -extension = ".so" -path = "%h/plugins" -save_config_on_unload = on - -[signal] -sighup = "${if:${info:weechat_headless}?/reload:/quit -yes}" -sigquit = "/quit -yes" -sigterm = "/quit -yes" -sigusr1 = "" -sigusr2 = "" - -[bar] -buffers.color_bg = default -buffers.color_bg_inactive = default -buffers.color_delim = default -buffers.color_fg = default -buffers.conditions = "" -buffers.filling_left_right = vertical -buffers.filling_top_bottom = horizontal -buffers.hidden = on -buffers.items = "buffers" -buffers.position = left -buffers.priority = 0 -buffers.separator = on -buffers.size = 0 -buffers.size_max = 0 -buffers.type = root -buflist.color_bg = default -buflist.color_bg_inactive = default -buflist.color_delim = default -buflist.color_fg = default -buflist.conditions = "" -buflist.filling_left_right = vertical -buflist.filling_top_bottom = columns_vertical -buflist.hidden = off -buflist.items = "buflist" -buflist.position = left -buflist.priority = 0 -buflist.separator = on -buflist.size = 0 -buflist.size_max = 25 -buflist.type = root -fset.color_bg = default -fset.color_bg_inactive = default -fset.color_delim = cyan -fset.color_fg = default -fset.conditions = "${buffer.full_name} == fset.fset" -fset.filling_left_right = vertical -fset.filling_top_bottom = horizontal -fset.hidden = off -fset.items = "fset" -fset.position = top -fset.priority = 0 -fset.separator = on -fset.size = 3 -fset.size_max = 3 -fset.type = window -input.color_bg = default -input.color_bg_inactive = default -input.color_delim = green -input.color_fg = default -input.conditions = "" -input.filling_left_right = vertical -input.filling_top_bottom = horizontal -input.hidden = off -input.items = "[input_prompt]+(away),[input_search],[input_paste],input_text" -input.position = bottom -input.priority = 1000 -input.separator = off -input.size = 1 -input.size_max = 0 -input.type = window -nicklist.color_bg = default -nicklist.color_bg_inactive = default -nicklist.color_delim = cyan -nicklist.color_fg = default -nicklist.conditions = "nicklist" -nicklist.filling_left_right = vertical -nicklist.filling_top_bottom = columns_vertical -nicklist.hidden = on -nicklist.items = "buffer_nicklist" -nicklist.position = right -nicklist.priority = 200 -nicklist.separator = on -nicklist.size = 0 -nicklist.size_max = 0 -nicklist.type = window -status.color_bg = green -status.color_bg_inactive = default -status.color_delim = 0 -status.color_fg = 0 -status.conditions = "" -status.filling_left_right = vertical -status.filling_top_bottom = horizontal -status.hidden = off -status.items = "[time],buffer_number+:+buffer_name,buffer_title" -status.position = bottom -status.priority = 500 -status.separator = off -status.size = 1 -status.size_max = 0 -status.type = window -title.color_bg = green -title.color_bg_inactive = default -title.color_delim = cyan -title.color_fg = 16 -title.conditions = "" -title.filling_left_right = vertical -title.filling_top_bottom = horizontal -title.hidden = on -title.items = "buffer_title" -title.position = top -title.priority = 500 -title.separator = off -title.size = 1 -title.size_max = 0 -title.type = window - -[layout] - -[notify] -python.slack.10xgenomics.&cloud-alerts-pagerduty = highlight -python.slack.10xgenomics.&cloud-sumo-prod-support-alerts = highlight -python.slack.10xgenomics.&lacework-10xdev = highlight -python.slack.10xgenomics.&lacework-10xprod = highlight -python.slack.10xgenomics.&testing1234 = highlight - -[filter] -irc_smart = on;*;irc_smart_filter;* -nicks = on;*;irc_366;* - -[key] -ctrl-? = "/input delete_previous_char" -ctrl-A = "/input move_beginning_of_line" -ctrl-B = "/brows" -ctrl-Cb = "/input insert \x02" -ctrl-Cc = "/input insert \x03" -ctrl-Ci = "/input insert \x1D" -ctrl-Co = "/input insert \x0F" -ctrl-Cr = "/input insert \x12" -ctrl-Cu = "/input insert \x15" -ctrl-D = "/buffer close" -ctrl-E = "/input move_end_of_line" -ctrl-F = "/input move_next_char" -ctrl-H = "/input delete_previous_char" -ctrl-I = "/input complete_next" -ctrl-J = "/input jump_smart" -ctrl-K = "/input delete_end_of_line" -ctrl-L = "/window refresh" -ctrl-M = "/input return" -ctrl-N = "/buffer +1" -ctrl-O = "/editor" -ctrl-P = "/buffer -1" -ctrl-R = "/input search_text" -ctrl-Sctrl-U = "/input set_unread" -ctrl-T = "/input transpose_chars" -ctrl-U = "/url 1" -ctrl-W = "/input delete_previous_word" -ctrl-X = "/input switch_active_buffer" -ctrl-Y = "/input clipboard_paste" -meta-meta-OP = "/bar scroll buflist * b" -meta-meta-OQ = "/bar scroll buflist * e" -meta-meta2-11~ = "/bar scroll buflist * b" -meta-meta2-12~ = "/bar scroll buflist * e" -meta-meta2-1~ = "/window scroll_top" -meta-meta2-23~ = "/bar scroll nicklist * yb" -meta-meta2-24~ = "/bar scroll nicklist * ye" -meta-meta2-4~ = "/window scroll_bottom" -meta-meta2-5~ = "/window scroll_up" -meta-meta2-6~ = "/window scroll_down" -meta-meta2-7~ = "/window scroll_top" -meta-meta2-8~ = "/window scroll_bottom" -meta-meta2-A = "/buffer move -1" -meta-meta2-B = "/buffer move +1" -meta-meta2-C = "/buffer +1" -meta-meta2-D = "/buffer -1" -meta-0 = "/buffer *10" -meta-1 = "/buffer *1" -meta-2 = "/buffer *2" -meta-3 = "/buffer *3" -meta-4 = "/buffer *4" -meta-5 = "/buffer *5" -meta-6 = "/buffer *6" -meta-7 = "/buffer *7" -meta-8 = "/buffer *8" -meta-9 = "/buffer *9" -meta-< = "/input jump_previously_visited_buffer" -meta-= = "/filter toggle" -meta-> = "/input jump_next_visited_buffer" -meta-B = "/buflist toggle" -meta-OA = "/input history_global_previous" -meta-OB = "/input history_global_next" -meta-OC = "/input move_next_word" -meta-OD = "/input move_previous_word" -meta-OF = "/input move_end_of_line" -meta-OH = "/input move_beginning_of_line" -meta-OP = "/bar scroll buflist * -100%" -meta-OQ = "/bar scroll buflist * +100%" -meta-Oa = "/input history_global_previous" -meta-Ob = "/input history_global_next" -meta-Oc = "/input move_next_word" -meta-Od = "/input move_previous_word" -meta2-11^ = "/bar scroll buflist * -100%" -meta2-11~ = "/bar scroll buflist * -100%" -meta2-12^ = "/bar scroll buflist * +100%" -meta2-12~ = "/bar scroll buflist * +100%" -meta2-15~ = "/bar scroll nicklist * y-100%" -meta2-17~ = "/bar scroll nicklist * y+100%" -meta2-18~ = "/window -1" -meta2-19~ = "/window +1" -meta2-1;3A = "/buffer -1" -meta2-1;3B = "/buffer +1" -meta2-1;3C = "/buffer +1" -meta2-1;3D = "/buffer -1" -meta2-1;3P = "/bar scroll buflist * b" -meta2-1;3Q = "/bar scroll buflist * e" -meta2-1;5A = "/input history_global_previous" -meta2-1;5B = "/input history_global_next" -meta2-1;5P = "/bar scroll buflist * -100%" -meta2-1;5Q = "/bar scroll buflist * +100%" -meta2-1;9A = "/buffer move -1" -meta2-1;9B = "/buffer move +1" -meta2-1~ = "/input move_beginning_of_line" -meta2-20~ = "/bar scroll title * x-50%" -meta2-21~ = "/bar scroll title * x+50%" -meta2-23~ = "/bar scroll nicklist * y-100%" -meta2-24~ = "/bar scroll nicklist * y+100%" -meta2-3~ = "/input delete_next_char" -meta2-4~ = "/input move_end_of_line" -meta2-5;3~ = "/window scroll_up" -meta2-5~ = "/window page_up" -meta2-6;3~ = "/window scroll_down" -meta2-6~ = "/window page_down" -meta2-7~ = "/input move_beginning_of_line" -meta2-8~ = "/input move_end_of_line" -meta2-A = "/input history_previous" -meta2-B = "/input history_next" -meta2-C = "/input move_next_char" -meta2-D = "/input move_previous_char" -meta2-F = "/input move_end_of_line" -meta2-G = "/window page_down" -meta2-H = "/input move_beginning_of_line" -meta2-I = "/window page_up" -meta2-Z = "/input complete_previous" -meta-_ = "/input redo" -meta-a = "/input jump_smart" -meta-b = "/input move_previous_word" -meta-d = "/input delete_next_word" -meta-f = "/input move_next_word" -meta-h = "/input hotlist_clear" -meta-jmeta-l = "/input jump_last_buffer" -meta-jmeta-r = "/server raw" -meta-jmeta-s = "/server jump" -meta-j01 = "/buffer 1" -meta-j02 = "/buffer 2" -meta-j03 = "/buffer 3" -meta-j04 = "/buffer 4" -meta-j05 = "/buffer 5" -meta-j06 = "/buffer 6" -meta-j07 = "/buffer 7" -meta-j08 = "/buffer 8" -meta-j09 = "/buffer 9" -meta-j10 = "/buffer 10" -meta-j11 = "/buffer 11" -meta-j12 = "/buffer 12" -meta-j13 = "/buffer 13" -meta-j14 = "/buffer 14" -meta-j15 = "/buffer 15" -meta-j16 = "/buffer 16" -meta-j17 = "/buffer 17" -meta-j18 = "/buffer 18" -meta-j19 = "/buffer 19" -meta-j20 = "/buffer 20" -meta-j21 = "/buffer 21" -meta-j22 = "/buffer 22" -meta-j23 = "/buffer 23" -meta-j24 = "/buffer 24" -meta-j25 = "/buffer 25" -meta-j26 = "/buffer 26" -meta-j27 = "/buffer 27" -meta-j28 = "/buffer 28" -meta-j29 = "/buffer 29" -meta-j30 = "/buffer 30" -meta-j31 = "/buffer 31" -meta-j32 = "/buffer 32" -meta-j33 = "/buffer 33" -meta-j34 = "/buffer 34" -meta-j35 = "/buffer 35" -meta-j36 = "/buffer 36" -meta-j37 = "/buffer 37" -meta-j38 = "/buffer 38" -meta-j39 = "/buffer 39" -meta-j40 = "/buffer 40" -meta-j41 = "/buffer 41" -meta-j42 = "/buffer 42" -meta-j43 = "/buffer 43" -meta-j44 = "/buffer 44" -meta-j45 = "/buffer 45" -meta-j46 = "/buffer 46" -meta-j47 = "/buffer 47" -meta-j48 = "/buffer 48" -meta-j49 = "/buffer 49" -meta-j50 = "/buffer 50" -meta-j51 = "/buffer 51" -meta-j52 = "/buffer 52" -meta-j53 = "/buffer 53" -meta-j54 = "/buffer 54" -meta-j55 = "/buffer 55" -meta-j56 = "/buffer 56" -meta-j57 = "/buffer 57" -meta-j58 = "/buffer 58" -meta-j59 = "/buffer 59" -meta-j60 = "/buffer 60" -meta-j61 = "/buffer 61" -meta-j62 = "/buffer 62" -meta-j63 = "/buffer 63" -meta-j64 = "/buffer 64" -meta-j65 = "/buffer 65" -meta-j66 = "/buffer 66" -meta-j67 = "/buffer 67" -meta-j68 = "/buffer 68" -meta-j69 = "/buffer 69" -meta-j70 = "/buffer 70" -meta-j71 = "/buffer 71" -meta-j72 = "/buffer 72" -meta-j73 = "/buffer 73" -meta-j74 = "/buffer 74" -meta-j75 = "/buffer 75" -meta-j76 = "/buffer 76" -meta-j77 = "/buffer 77" -meta-j78 = "/buffer 78" -meta-j79 = "/buffer 79" -meta-j80 = "/buffer 80" -meta-j81 = "/buffer 81" -meta-j82 = "/buffer 82" -meta-j83 = "/buffer 83" -meta-j84 = "/buffer 84" -meta-j85 = "/buffer 85" -meta-j86 = "/buffer 86" -meta-j87 = "/buffer 87" -meta-j88 = "/buffer 88" -meta-j89 = "/buffer 89" -meta-j90 = "/buffer 90" -meta-j91 = "/buffer 91" -meta-j92 = "/buffer 92" -meta-j93 = "/buffer 93" -meta-j94 = "/buffer 94" -meta-j95 = "/buffer 95" -meta-j96 = "/buffer 96" -meta-j97 = "/buffer 97" -meta-j98 = "/buffer 98" -meta-j99 = "/buffer 99" -meta-k = "/input grab_key_command" -meta-n = "/window scroll_next_highlight" -meta-p = "/window scroll_previous_highlight" -meta-r = "/input delete_line" -meta-u = "/input scroll_unread" -meta-wmeta-meta2-A = "/window up" -meta-wmeta-meta2-B = "/window down" -meta-wmeta-meta2-C = "/window right" -meta-wmeta-meta2-D = "/window left" -meta-wmeta2-1;3A = "/window up" -meta-wmeta2-1;3B = "/window down" -meta-wmeta2-1;3C = "/window right" -meta-wmeta2-1;3D = "/window left" -meta-wmeta-b = "/window balance" -meta-wmeta-s = "/window swap" -meta-x = "/bar toggle nicklist" -meta-z = "/window zoom" -ctrl-_ = "/input undo" - -[key_search] -ctrl-J = "/input search_stop" -ctrl-M = "/input search_stop" -ctrl-R = "/input search_switch_case" -meta2-A = "/input search_previous" -meta2-B = "/input search_next" - -[key_cursor] -ctrl-J = "/cursor stop" -ctrl-M = "/cursor stop" -meta-meta2-A = "/cursor move area_up" -meta-meta2-B = "/cursor move area_down" -meta-meta2-C = "/cursor move area_right" -meta-meta2-D = "/cursor move area_left" -meta2-1;3A = "/cursor move area_up" -meta2-1;3B = "/cursor move area_down" -meta2-1;3C = "/cursor move area_right" -meta2-1;3D = "/cursor move area_left" -meta2-A = "/cursor move up" -meta2-B = "/cursor move down" -meta2-C = "/cursor move right" -meta2-D = "/cursor move left" -@chat(python.*):D = "hsignal:slack_cursor_delete" -@chat(python.*):L = "hsignal:slack_cursor_linkarchive" -@chat(python.*):M = "hsignal:slack_cursor_message" -@chat(python.*):R = "hsignal:slack_cursor_reply" -@chat(python.*):T = "hsignal:slack_cursor_thread" -@item(buffer_nicklist):K = "/window ${_window_number};/kickban ${nick}" -@item(buffer_nicklist):b = "/window ${_window_number};/ban ${nick}" -@item(buffer_nicklist):k = "/window ${_window_number};/kick ${nick}" -@item(buffer_nicklist):q = "/window ${_window_number};/query ${nick};/cursor stop" -@item(buffer_nicklist):w = "/window ${_window_number};/whois ${nick}" -@chat:Q = "hsignal:chat_quote_time_prefix_message;/cursor stop" -@chat:m = "hsignal:chat_quote_message;/cursor stop" -@chat:q = "hsignal:chat_quote_prefix_message;/cursor stop" - -[key_mouse] -@bar(buflist):ctrl-wheeldown = "hsignal:buflist_mouse" -@bar(buflist):ctrl-wheelup = "hsignal:buflist_mouse" -@bar(input):button2 = "/input grab_mouse_area" -@bar(nicklist):button1-gesture-down = "/bar scroll nicklist ${_window_number} +100%" -@bar(nicklist):button1-gesture-down-long = "/bar scroll nicklist ${_window_number} e" -@bar(nicklist):button1-gesture-up = "/bar scroll nicklist ${_window_number} -100%" -@bar(nicklist):button1-gesture-up-long = "/bar scroll nicklist ${_window_number} b" -@chat(fset.fset):button1 = "/window ${_window_number};/fset -go ${_chat_line_y}" -@chat(fset.fset):button2* = "hsignal:fset_mouse" -@chat(fset.fset):wheeldown = "/fset -down 5" -@chat(fset.fset):wheelup = "/fset -up 5" -@chat(python.*):button2 = "hsignal:slack_mouse" -@chat(script.scripts):button1 = "/window ${_window_number};/script go ${_chat_line_y}" -@chat(script.scripts):button2 = "/window ${_window_number};/script go ${_chat_line_y};/script installremove -q ${script_name_with_extension}" -@chat(script.scripts):wheeldown = "/script down 5" -@chat(script.scripts):wheelup = "/script up 5" -@item(buffer_nicklist):button1 = "/window ${_window_number};/query ${nick}" -@item(buffer_nicklist):button1-gesture-left = "/window ${_window_number};/kick ${nick}" -@item(buffer_nicklist):button1-gesture-left-long = "/window ${_window_number};/kickban ${nick}" -@item(buffer_nicklist):button2 = "/window ${_window_number};/whois ${nick}" -@item(buffer_nicklist):button2-gesture-left = "/window ${_window_number};/ban ${nick}" -@item(buffers):button1* = "hsignal:buffers_mouse" -@item(buffers):button2* = "hsignal:buffers_mouse" -@item(buflist):button1* = "hsignal:buflist_mouse" -@item(buflist):button2* = "hsignal:buflist_mouse" -@item(buflist2):button1* = "hsignal:buflist_mouse" -@item(buflist2):button2* = "hsignal:buflist_mouse" -@item(buflist3):button1* = "hsignal:buflist_mouse" -@item(buflist3):button2* = "hsignal:buflist_mouse" -@bar:wheeldown = "/bar scroll ${_bar_name} ${_window_number} +20%" -@bar:wheelup = "/bar scroll ${_bar_name} ${_window_number} -20%" -@chat:button1 = "/window ${_window_number}" -@chat:button1-gesture-left = "/window ${_window_number};/buffer -1" -@chat:button1-gesture-left-long = "/window ${_window_number};/buffer 1" -@chat:button1-gesture-right = "/window ${_window_number};/buffer +1" -@chat:button1-gesture-right-long = "/window ${_window_number};/input jump_last_buffer" -@chat:wheeldown = "/window scroll_down -window ${_window_number}" -@chat:wheelup = "/window scroll_up -window ${_window_number}" -@*:button3 = "/cursor go ${_x},${_y}" diff -r 93d27886c099 -r 62e329839625 weechat/xfer.conf --- a/weechat/xfer.conf Sun May 18 14:59:11 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -# -# weechat -- xfer.conf -# -# WARNING: It is NOT recommended to edit this file by hand, -# especially if WeeChat is running. -# -# Use commands like /set or /fset to change settings in WeeChat. -# -# For more info, see: https://weechat.org/doc/quickstart/ -# - -[look] -auto_open_buffer = on -progress_bar_size = 20 -pv_tags = "notify_private" - -[color] -status_aborted = lightred -status_active = lightblue -status_connecting = yellow -status_done = lightgreen -status_failed = lightred -status_waiting = lightcyan -text = default -text_bg = default -text_selected = white - -[network] -blocksize = 65536 -fast_send = on -own_ip = "" -port_range = "" -send_ack = on -speed_limit_recv = 0 -speed_limit_send = 0 -timeout = 300 - -[file] -auto_accept_chats = off -auto_accept_files = off -auto_accept_nicks = "" -auto_check_crc32 = off -auto_rename = on -auto_resume = on -convert_spaces = on -download_path = "%h/xfer" -download_temporary_suffix = ".part" -upload_path = "~" -use_nick_in_filename = on