about summary refs log tree commit diff
path: root/emacs/.emacs.d/wpc/irc.el
diff options
context:
space:
mode:
Diffstat (limited to 'emacs/.emacs.d/wpc/irc.el')
-rw-r--r--emacs/.emacs.d/wpc/irc.el177
1 files changed, 177 insertions, 0 deletions
diff --git a/emacs/.emacs.d/wpc/irc.el b/emacs/.emacs.d/wpc/irc.el
new file mode 100644
index 000000000000..b9a1e3131769
--- /dev/null
+++ b/emacs/.emacs.d/wpc/irc.el
@@ -0,0 +1,177 @@
+;;; irc.el --- Configuration for IRC chat -*- lexical-binding: t -*-
+;; Author: William Carroll <wpcarro@gmail.com>
+
+;;; Commentary:
+;; Need to decide which client I will use for IRC.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Dependencies
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(require 'erc)
+(require 'cycle)
+(require 'string)
+(require 'prelude)
+(require 'alist)
+(require 'set)
+(require 'maybe)
+(require 'macros)
+(require 'password-store)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Configuration
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defconst irc/enable-tests? t
+  "When t, run the tests defined herein.")
+
+(setq erc-rename-buffers t)
+
+;; TODO: Find a way to avoid putting "freenode" and "#freenode" as channels
+;; here.  I'm doing it because when erc first connects, it's `(buffer-name)' is
+;; "freenode", so when `irc/next-channel' is called, it 404s on the
+;; `cycle/contains?' call in `irc/channel->cycle" unless "freenode" is there. To
+;; make matters even uglier, when `erc-join-channel' is called with "freenode"
+;; as the value, it connects to the "#freenode" channel, so unless "#freenode"
+;; exists in this cycle also, `irc/next-channel' breaks again.  This doesn't
+;; pass my smell test.
+(defconst irc/server->channels
+  `(("irc.freenode.net"    . ,(cycle/new "freenode" "#freenode" "#nixos" "#emacs" "#pass"))
+    ("irc.corp.google.com" . ,(cycle/new "#omg" "#london" "#panic" "#prod-team")))
+  "Mapping of IRC servers to a cycle of my preferred channels.")
+
+;; TODO: Assert that no two servers have a channel with the same name. We need
+;; this because that's the assumption that underpins the `irc/channel->server'
+;; function. This will probably be an O(n^2) operation.
+(prelude/assert
+ (set/distinct? (set/from-list
+                 (cycle/to-list
+                  (alist/get "irc.freenode.net"
+                             irc/server->channels)))
+                (set/from-list
+                 (cycle/to-list
+                  (alist/get "irc.corp.google.com"
+                             irc/server->channels)))))
+
+(defun irc/channel->server (server->channels channel)
+  "Resolve an IRC server from a given CHANNEL."
+  (let ((result (alist/find (lambda (k v) (cycle/contains? channel v))
+                            server->channels)))
+    (prelude/assert (maybe/some? result))
+    result))
+
+(defun irc/channel->cycle (server->channels channel)
+  "Resolve an IRC's channels cycle from a given CHANNEL."
+  (alist/get (irc/channel->server server->channels channel)
+             server->channels))
+
+;; Setting `erc-join-buffer' to 'bury prevents erc from stealing focus of the
+;; current buffer when it connects to IRC servers.
+(setq erc-join-buffer 'bury)
+
+;; TODO: Here is another horrible hack that should be revisted.
+(setq erc-autojoin-channels-alist
+      (->> irc/server->channels
+           (alist/map-values #'cycle/to-list)
+           (alist/map-keys (>> (s-chop-prefix "irc.")
+                               (s-chop-suffix ".net")))))
+
+(defcustom irc/install-kbds? t
+  "When t, install the keybindings defined herein.")
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Library
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun irc/message (x)
+  "Print message X in a structured way."
+  (message (string/format "[irc.el] %s" x)))
+
+;; TODO: Integrate Google setup with Freenode setup.
+
+;; TODO: Support function or KBD for switching to an ERC buffer.
+
+(defun irc/kill-all-erc-processes ()
+  "Kills all ERC buffers and processes."
+  (interactive)
+  (->> (erc-buffer-list)
+       (-map #'kill-buffer)))
+
+(defun irc/switch-to-erc-buffer ()
+  "Switch to an ERC buffer."
+  (interactive)
+  (let ((buffers (erc-buffer-list)))
+    (if (list/empty? buffers)
+        (error "[irc.el] No ERC buffers available")
+      (switch-to-buffer (list/head (erc-buffer-list))))))
+
+(defun irc/connect-to-freenode ()
+  "Connect to Freenode IRC."
+  (interactive)
+  (erc-ssl :server "irc.freenode.net"
+           :port 6697
+           :nick "wpcarro"
+           :password (password-store-get "programming/irc/freenode")
+           :full-name "William Carroll"))
+
+;; TODO: Handle failed connections.
+(defun irc/connect-to-google ()
+  "Connect to Google's Corp IRC using ERC."
+  (interactive)
+  (erc-ssl :server "irc.corp.google.com"
+           :port 6697
+           :nick "wpcarro"
+           :full-name "William Carroll"))
+
+;; TODO: Prefer defining these with a less homespun solution. There is a
+;; function call `erc-buffer-filter' that would be more appropriate for the
+;; implementation of `irc/next-channel' and `irc/prev-channel'.
+(defun irc/next-channel ()
+  "Join the next channel for the active server."
+  (interactive)
+  (with-current-buffer (current-buffer)
+    (let ((cycle (irc/channel->cycle irc/server->channels (buffer-name))))
+      (erc-join-channel
+       (cycle/next cycle))
+      (irc/message
+       (string/format "Current IRC channel: %s" (cycle/current cycle))))))
+
+(defun irc/prev-channel ()
+  "Join the previous channel for the active server."
+  (interactive)
+  (with-current-buffer (current-buffer)
+    (let ((cycle (irc/channel->cycle irc/server->channels (buffer-name))))
+      (erc-join-channel
+       (cycle/prev cycle))
+      (irc/message
+       (string/format "Current IRC channel: %s" (cycle/current cycle))))))
+
+(add-hook 'erc-mode-hook (disable auto-fill-mode))
+(add-hook 'erc-mode-hook (disable company-mode))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Keybindings
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when irc/install-kbds?
+  (general-define-key
+   :keymaps 'erc-mode-map
+   "<C-tab>" #'irc/next-channel
+   "<C-S-iso-lefttab>" #'irc/prev-channel))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Tests
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(when irc/enable-tests?
+  (prelude/assert
+   (equal
+    (irc/channel->server `(("irc.dairy.com" . ,(cycle/new "#cheese" "#milk"))
+                           ("irc.color.com" . ,(cycle/new "#red" "#blue")))
+                         "#cheese")
+    "irc.dairy.com")))
+
+(provide 'irc)
+;;; irc.el ends here