diff options
| -rw-r--r-- | modules/erc-config.el | 180 |
1 files changed, 125 insertions, 55 deletions
diff --git a/modules/erc-config.el b/modules/erc-config.el index 03c89aca..55b4c9a7 100644 --- a/modules/erc-config.el +++ b/modules/erc-config.el @@ -9,28 +9,65 @@ ;; - C-c e C : Select and connect to a specific server ;; - C-c e c : Join a channel on current server ;; - C-c e b : Switch between ERC buffers across all servers -;; - C-c C-q : Quit current channel -;; - C-c C-Q : Quit ERC altogether +;; - C-c e l : List connected servers +;; - C-c e q : Quit current channel +;; - C-c e Q : Quit ERC server ;;; Code: -;; Keymap for ERC commands +;; Load cl-lib at compile time and runtime (lightweight, already loaded in most configs) +(require 'cl-lib) + +;; Declare ERC functions to avoid byte-compiler warnings +(declare-function erc-part-from-channel "erc" (&optional reason)) +(declare-function erc-quit-server "erc" (reason)) +(declare-function erc-buffer-list "erc" (&optional predicate proc)) +(declare-function erc-server-process-alive "erc" (&optional buffer)) +(declare-function erc-server-buffer-p "erc" (&optional buffer)) +(declare-function erc-current-nick "erc" ()) +(declare-function erc-join-channel "erc" (channel &optional key)) +(declare-function erc-tls "erc" (&rest r)) +(declare-function erc "erc" (&rest r)) +(declare-function erc-update-modules "erc" ()) +(declare-function erc-get-color-for-nick "erc" (nick)) + +;; Declare ERC variables +(defvar erc-server-process) +(defvar erc-mode-abbrev-table) +(defvar erc-log-channels-directory) +(defvar erc-unique-buffers) +(defvar erc-generate-buffer-name-function) +(defvar erc-track-exclude-types) +(defvar erc-track-exclude-server-buffer) +(defvar erc-track-visibility) +(defvar erc-track-switch-direction) +(defvar erc-track-showcount) +(defvar erc-nick-color-alist) +(defvar erc-nick-color-function) +(defvar erc-modules) +(defvar erc-mode-map) +(defvar user-whole-name) +(defvar erc-image-inline-rescale) + +;; Keymap for ERC commands (bound in use-package :config to defer loading) (defvar cj/erc-command-map (let ((map (make-sparse-keymap))) - (define-key map "C" 'cj/erc-connect-server-with-completion) ;; Connect to server (capital C) - (define-key map "c" 'cj/erc-join-channel-with-completion) ;; join channel (lowercase c) - (define-key map "b" 'cj/erc-switch-to-buffer-with-completion) ;; switch Buffer - (define-key map "l" 'cj/erc-connected-servers) ;; print connected servers in echo area - (define-key map "q" 'erc-part-from-channel) ;; quit channel - (define-key map "Q" 'erc-quit-server) ;; Quit ERC entirely + (keymap-set map "C" #'cj/erc-connect-server-with-completion) ;; Connect to server (capital C) + (keymap-set map "c" #'cj/erc-join-channel-with-completion) ;; join channel (lowercase c) + (keymap-set map "b" #'cj/erc-switch-to-buffer-with-completion) ;; switch Buffer + (keymap-set map "l" #'cj/erc-connected-servers) ;; print connected servers in echo area + (keymap-set map "q" #'erc-part-from-channel) ;; quit channel + (keymap-set map "Q" #'erc-quit-server) ;; Quit ERC entirely map) "Keymap for ERC-related commands.") -(global-set-key (kbd "C-c e") cj/erc-command-map) - ;; ------------------------------------ ERC ------------------------------------ ;; Server definitions and connection settings +(defvar cj/erc-nick "craigjennings" + "Default IRC nickname for ERC connections. +Change this value to use a different nickname.") + (defvar cj/erc-server-alist '(("Libera.Chat" :host "irc.libera.chat" @@ -57,22 +94,26 @@ :channels ("#general" "#lounge"))) "Alist of IRC servers and their connection details.") +;;;###autoload (defun cj/erc-connect-server (server-name) - "Connect to a server specified by SERVER-NAME from =cj/erc-server-alist=." - (let* ((server-info (assoc server-name cj/erc-server-alist)) - (host (plist-get (cdr server-info) :host)) - (port (plist-get (cdr server-info) :port)) - (tls (plist-get (cdr server-info) :tls))) - (if tls - (erc-tls :server host - :port port - :nick "craigjennings" - :full-name user-whole-name) - (erc :server host - :port port - :nick "craigjennings" - :full-name user-whole-name)))) - + "Connect to a server specified by SERVER-NAME from `cj/erc-server-alist'." + (let ((server-info (assoc server-name cj/erc-server-alist))) + (if (not server-info) + (error "Server '%s' not found in cj/erc-server-alist" server-name) + (let ((host (plist-get (cdr server-info) :host)) + (port (plist-get (cdr server-info) :port)) + (tls (plist-get (cdr server-info) :tls))) + (if tls + (erc-tls :server host + :port port + :nick cj/erc-nick + :full-name user-whole-name) + (erc :server host + :port port + :nick cj/erc-nick + :full-name user-whole-name)))))) + +;;;###autoload (defun cj/erc-connect-server-with-completion () "Connect to a server using completion for server selection." (interactive) @@ -80,6 +121,7 @@ (mapcar #'car cj/erc-server-alist)))) (cj/erc-connect-server server-name))) +;;;###autoload (defun cj/erc-connected-servers () "Return a list of currently connected servers and display them in echo area." (interactive) @@ -94,28 +136,51 @@ (when (called-interactively-p 'any) (if server-buffers (message "Connected ERC servers: %s" - (mapconcat 'identity server-buffers ", ")) + (mapconcat #'identity server-buffers ", ")) (message "No active ERC server connections"))) server-buffers)) +;;;###autoload (defun cj/erc-switch-to-buffer-with-completion () - "Switch to an ERC buffer using completion." + "Switch to an ERC buffer using completion. +If no ERC buffers exist, prompt to connect to a server. +Buffer names are shown with server context for clarity." (interactive) - (let* ((erc-buffers (mapcar 'buffer-name (erc-buffer-list))) - (selected (completing-read "Switch to buffer: " erc-buffers))) - (switch-to-buffer selected))) - + (let* ((erc-buffers (erc-buffer-list)) + (buffer-names (mapcar #'buffer-name erc-buffers))) + (if buffer-names + (let ((selected (completing-read "Switch to ERC buffer: " buffer-names nil t))) + (switch-to-buffer selected)) + (message "No ERC buffers found.") + (when (y-or-n-p "Connect to an IRC server? ") + (call-interactively 'cj/erc-connect-server-with-completion))))) + +;;;###autoload (defun cj/erc-server-buffer-active-p () "Return t if the current buffer is an active ERC server buffer." (and (derived-mode-p 'erc-mode) (erc-server-process-alive) (erc-server-buffer-p))) +;;;###autoload +(defun cj/erc-get-channels-for-current-server () + "Get list of channels for the currently connected server." + (when (and (derived-mode-p 'erc-mode) erc-server-process) + (let* ((server-host (process-name erc-server-process)) + (matching-server (cl-find-if + (lambda (server) + (string-match-p (plist-get (cdr server) :host) server-host)) + cj/erc-server-alist))) + (when matching-server + (plist-get (cdr matching-server) :channels))))) + +;;;###autoload (defun cj/erc-join-channel-with-completion () "Join a channel on the current server. -If not in an active ERC server buffer, reconnect first." +If not in an active ERC server buffer, reconnect first. +Auto-adds # prefix if missing. Offers completion from configured channels." (interactive) (unless (cj/erc-server-buffer-active-p) (if (erc-buffer-list) @@ -138,15 +203,20 @@ If not in an active ERC server buffer, reconnect first." ;; At this point we should have an active connection (if (cj/erc-server-buffer-active-p) - (let ((channel (read-string "Join channel: "))) - (when (string-prefix-p "#" channel) + (let* ((channels (cj/erc-get-channels-for-current-server)) + (channel (if channels + (completing-read "Join channel: " channels nil nil "#") + (read-string "Join channel: " "#")))) + ;; Auto-add # prefix if missing + (unless (string-prefix-p "#" channel) + (setq channel (concat "#" channel))) + (when (> (length channel) 1) ; Must have more than just # (erc-join-channel channel))) (message "Failed to establish an active ERC connection"))) ;; Main ERC configuration (use-package erc - :defer 1 :ensure nil ;; built-in :commands (erc erc-tls) :hook @@ -175,18 +245,20 @@ If not in an active ERC server buffer, reconnect first." (plist-get (cdr server) :channels))) cj/erc-server-alist)) - (erc-nick "craigjennings") + (erc-nick cj/erc-nick) (erc-user-full-name user-whole-name) (erc-use-auth-source-for-nickserv-password t) (erc-kill-buffer-on-part t) (erc-kill-queries-on-quit t) (erc-kill-server-buffer-on-quit t) (erc-fill-column 120) - (erc-fill-function 'erc-fill-static) + (erc-fill-function #'erc-fill-static) (erc-fill-static-center 20) :config + ;; Bind global keymap + (keymap-global-set "C-c e" cj/erc-command-map) ;; use all text mode abbrevs in ercmode (abbrev-table-put erc-mode-abbrev-table :parents (list text-mode-abbrev-table)) @@ -197,7 +269,7 @@ If not in an active ERC server buffer, reconnect first." (mkdir erc-log-channels-directory t)) ;; Configure buffer naming to include server name - (setq erc-rename-buffers t) + ;; Note: erc-rename-buffers is obsolete as of Emacs 29.1 (old behavior is now permanent) (setq erc-unique-buffers t) ;; Custom buffer naming function @@ -217,7 +289,11 @@ If not in an active ERC server buffer, reconnect first." erc-track-exclude-server-buffer t erc-track-visibility 'selected-visible erc-track-switch-direction 'importance - erc-track-showcount t)) + erc-track-showcount t) + + ;; Add hooks for notifications and colorization + (add-hook 'erc-text-matched-hook #'cj/erc-notify-on-mention) + (add-hook 'erc-mode-hook #'cj/erc-colorize-setup)) ;; -------------------------------- ERC Track --------------------------------- ;; Better tracking of activity across channels (already included in modules above) @@ -244,7 +320,7 @@ If not in an active ERC server buffer, reconnect first." ;; Implementation for desktop notifications (defun cj/erc-notify-on-mention (match-type nick message) - "Display a notification when MATCH-TYPE is 'current-nick. + "Display a notification when MATCH-TYPE is \\='current-nick. NICK is the sender and MESSAGE is the message text." (when (and (eq match-type 'current-nick) @@ -261,8 +337,6 @@ NICK is the sender and MESSAGE is the message text." :app-name "Emacs ERC" :sound-name 'message)))))) -(add-hook 'erc-text-matched-hook 'cj/erc-notify-on-mention) - ;; ------------------------------ ERC Colorize ------------------------------- ;; Better color management with built-in functionality @@ -276,30 +350,26 @@ NICK is the sender and MESSAGE is the message text." "light blue" "light green" "light red" "light brown" "light purple" "yellow" "white") collect (cons i color))) - (setq erc-nick-color-function 'erc-get-color-for-nick)) - -(add-hook 'erc-mode-hook 'cj/erc-colorize-setup) + (setq erc-nick-color-function #'erc-get-color-for-nick)) ;; -------------------------------- ERC Image --------------------------------- ;; show inlined images (png/jpg/gif/svg) in erc buffers. (use-package erc-image - :defer 1 + :if (locate-library "erc-image") :after erc :config (setq erc-image-inline-rescale 300) (add-to-list 'erc-modules 'image) (erc-update-modules)) -;; -------------------------------- ERC Hl Nicks ------------------------------- -;; uniquely identify names in ERC +;; -------------------------------- ERC Nicks --------------------------------- +;; Nickname highlighting (built-in to Emacs 29+) -(use-package erc-hl-nicks - :defer 1 +(use-package erc-nicks + :ensure nil ;; built-in :after erc - :config - (add-to-list 'erc-modules 'hl-nicks) - (erc-update-modules)) + :hook (erc-mode . erc-nicks-mode)) ;; ------------------------------ ERC Yank To Gist ----------------------------- ;; automatically create a Gist if pasting more than 5 lines @@ -307,7 +377,7 @@ NICK is the sender and MESSAGE is the message text." ;; via ruby: 'gem install gist' via the aur: yay -S gist (use-package erc-yank - :defer 1 + :if (locate-library "erc-yank") :after erc :bind (:map erc-mode-map |
