;;; irc.el -*- lexical-binding: t; -*- ;;; ;;; Author: Jakob L. Kreuze ;;; URL: https://git.sr.ht/~jakob/.emacs.d/ ;;; ;;; Configuration of ERC, as well as additional custom defuns for making an ;;; enjoyable IRC experience within Emacs. ;;; ;; Functions for connecting to and authenticating with my IRC bouncer. (defun read-bouncer-password () "Pull the password for my bouncer from authinfo" (let ((auth (auth-source-search :host "jakob.space" :user "jakob" :port 6697))) (unless auth (error "No auth entry for bouncer.")) (let ((secretf (plist-get (car auth) :secret))) (unless secretf (error "No secret for bouncer's auth entry.")) (funcall secretf)))) (defvar *bouncer-port-alist* '(("freenode" . 6697) ("tildetown" . 6671))) (defun connect-bouncer (server) "Connect to `SERVER' on the bouncer and rename the buffer" (let* ((port (cdr (assoc server *bouncer-port-alist*))) (buf (erc-tls :server "jakob.space" :port port :password (read-bouncer-password)))) (erc-with-buffer (buf (rename-buffer server))))) ;; Interactive function for connecting to all of my bouncer's IRC servers. (defvar irc-autoconnect-networks '("freenode" "tildetown") "List of networks to automatically connect to when 'irc' is invoked.") (defun irc () "Connect to every network in `irc-autoconnect-networks'." (interactive) (dolist (network irc-autoconnect-networks) (connect-bouncer network))) (defun irc-quit () "Disconnects from and kills all buffers associated with ERC." (interactive) (let ((server-buffers (cl-remove-if-not #'erc-server-buffer-p (erc-buffer-list)))) (dolist (buffer server-buffers) (erc-with-buffer (buffer) (erc-quit-server (funcall erc-quit-reason nil)))))) (use-package erc :straight nil ;; Only load the modules I actually use. This list deviates from the default ;; by including truncate, but omitting autojoin. :config (setq erc-modules '(button completion fill irccontrols list match menu move-to-prompt netsplit networks noncommands readonly ring stamp track truncate)) (erc-update-modules) ;; Configure personal details. :init (setq erc-nick '("jakob" "tsarfox") erc-user-full-name "Jakob " erc-quit-reason (lambda (reason) (or reason (concat "Program received signal " "SIGSEGV, Segmentation fault.")))) ;; Display the current nick in the prompt. :init (setq erc-prompt (lambda () (format "%s>" (erc-current-nick)))) ;; Center everything. :init (setq erc-fill-function 'erc-fill-static erc-fill-column 100 erc-fill-static-center 22) ;; Enable MIRC and control sequences so I can partake in figlet spam, ;; objectively the best part of the IRC experience. :init (setq erc-interpret-controls-p t erc-interpret-mirc-color t) ;; Enable timestamps, and show them to the left of the messages. :init (setq erc-hide-timestamps nil erc-insert-timestamp-function 'erc-insert-timestamp-left) ;; Although 'log' is omitted from `erc-modules', I still explicitly disable ;; logging. I can just save the buffer if I want to save a conversation. :init (setq erc-enable-logging nil erc-save-buffer-on-part nil) ;; Similarly, 'autowaway' is omitted from `erc-modules', but I'm disabling it ;; anyway. :init (setq erc-auto-set-away nil erc-auto-discard-away nil) ;; Kill buffers when I disconnect. :init (setq erc-kill-buffer-on-part t erc-kill-queries-on-quit t erc-kill-server-buffer-on-quit t) ;; Don't get in my way by popping new windows when someone queries me, and ;; don't assault me with windows when I connect to my bouncer. :init (setq erc-auto-query 'bury erc-join-buffer 'bury) ;; Show CTCP requests. Not for any reason in particular, I just like seeing ;; when people ping me. :init (setq erc-paranoid t) ;; Hide JOIN/PART/QUIT messages from idlers. :init (setq erc-lurker-hide-list '("JOIN" "PART" "QUIT") erc-lurker-threshold-time 3600) ;; Configure `erc-track' to ignore the less interesting message types. :init (setq erc-track-exclude-server-buffer t erc-track-exclude-types '("JOIN" "NICK" "PART" "QUIT" "MODE" "324" "329" "332" "333" "353" "477")) ;; Enable channel tracking. :config (erc-track-minor-mode 1) (erc-track-mode 1) ;; Move to the prompt as soon as I begin typing. I've configured the buffer ;; text preceding it to be read-only, anyway. :config (erc-move-to-prompt-enable) ;; Bind a key for resetting =erc-track=, since I tend to get absolutely ;; bombarded upon reconnecting. :bind (:map erc-mode-map ("C-c f" . (lambda () (interactive) (setq erc-modified-channels-alist nil) (erc-modified-channels-update)))) ;; Let `erc-fill' handle filling. :hook (erc-mode . (lambda () (auto-fill-mode 0)))) ;; Configure 'erc-hl-nicks' to show names using pretty colors. (use-package erc-hl-nicks :after erc :config (erc-hl-nicks-enable)) ;; Display a bar delimiting read and unread messages. Adapted from [1]. ;; ;; [1]: https://www.emacswiki.org/emacs/ErcBar (defvar erc-bar-overlay nil "Overlay used to set bar") (defvar erc-bar-threshold 1 "The minimum number of messages required for the bar to be displayed.") (defun erc-bar-move-back (n) "Moves back n message lines. Ignores wrapping, and server messages." (interactive "nHow many lines ? ") (re-search-backward "^.*<.*>" nil t n)) (defun erc-bar-update-overlay () "Update the overlay for current buffer, based on the content of erc-modified-channels-alist. Should be executed on window change." (interactive) (let* ((info (assq (current-buffer) erc-modified-channels-alist)) (count (cadr info))) (if (and info (> count erc-bar-threshold)) (save-excursion (goto-char (point-max)) (when (erc-bar-move-back count) (let ((inhibit-field-text-motion t)) (move-overlay erc-bar-overlay (line-beginning-position) (line-end-position) (current-buffer))))) (delete-overlay erc-bar-overlay)))) (with-eval-after-load 'erc ;; Run the hook before 'erc-modified-channels-update (defadvice erc-track-mode (after erc-bar-setup-hook (&rest args) activate) (remove-hook 'window-configuration-change-hook 'erc-bar-update-overlay) (add-hook 'window-configuration-change-hook 'erc-bar-update-overlay)) (add-hook 'erc-send-completed-hook (lambda (str) (ignore str) (erc-bar-update-overlay)))) ;; Display the bar as a highlight on the most recently unread message. (with-palette (setq erc-bar-overlay (make-overlay 0 0)) (overlay-put erc-bar-overlay 'face `(:background ,black-2)))