legacy-dotfiles/emacs/.emacs.d/init-circe.org

242 lines
9.7 KiB
Org Mode

#+PROPERTY: tangle site-lisp/circe-init.el
#+STARTUP: content
I used to use ERC mostly because I didn't really use IRC at all and it
was basically the first IRC client in Emacs that was presented to me,
it being built-in and all. When I started to use IRC more and wanted
to customize the way it looks more I was surprised to find that it
wasn't all that easy. A friend of mine was using Circe and he helped
me figure out how to get started with customizing Circe the way I
wanted it. So now I use Circe.
* Require the needed libraries
In order to keep compiler warnings to a minimum, require the
libraries that are used in the configuration of Circe.
#+BEGIN_SRC emacs-lisp
(require 'auth-source)
(require 'lui)
(require 'circe)
(require 's)
#+END_SRC
* Clean-up the display of messages
I once saw a very clean and simple weechat configuration on
[[https://www.reddit.com/r/unixporn][/r/unixporn]] and really wanted to have something similar. This was
the start of my disappointment in ERC, I couldn't figure out how to
change the way messages were printed. With a little help I did find
out how to do it in Circe.
First we create a variable to store the length of the longest known
nick, so we can properly align all messages. This variable should be
buffer-local because each IRC chat will have different users with
different length names. We start with a length of ~0~ because we don't
know what the shortest nick there is going to be.
#+BEGIN_SRC emacs-lisp
(defvar oni:circe-longest-nick 0)
(make-variable-buffer-local 'oni:circe-longest-nick)
#+END_SRC
Then we write the function that will print the most important
messages, the ones people send, including me. Whenever we get a
message or send a message, we check the length of the nick with the
last recorded maximum length. If the new nick is longer that any
previous ones we set this new length as the longest known length and
adjust =lui-fill-type= accordingly. This ensures that continuation
lines are indented to the correct column.
#+BEGIN_SRC emacs-lisp
(defun oni:circe-say-formatter (&rest keywords)
(let* ((nick (plist-get keywords :nick))
(len (length nick)))
(when (> len oni:circe-longest-nick)
(setq oni:circe-longest-nick len)
(setq-local lui-fill-type (make-string (+ len 3) ?\ )))
(format "%s %s" (s-pad-left oni:circe-longest-nick " " nick)
(plist-get keywords :body))))
#+END_SRC
I use this formatter both for messages I send myself and incoming
messages, because they should basically look the same.
#+BEGIN_SRC emacs-lisp
(setq circe-format-self-say #'oni:circe-say-formatter
circe-format-say #'oni:circe-say-formatter)
#+END_SRC
The rest of the formatting functions are basically the same, except
they don't need to change the known size of nicks because they don't
print the nick in the same column, instead they usually print
something like =***= to indicate that it is a system message and not a
user message. We do pad whatever they print with the same number of
spaces to keep them right-justified with the nicks.
#+BEGIN_SRC emacs-lisp
(defun oni:circe-action-formatter (&rest keywords)
(format "%s %s %s" (s-pad-left oni:circe-longest-nick " " "*")
(plist-get keywords :nick)
(plist-get keywords :body)))
(defun oni:circe-server-message-formatter (&rest keywords)
(format "%s %s" (s-pad-left oni:circe-longest-nick " " "***")
(plist-get keywords :body)))
(defun oni:circe-server-join-in-channel-formatter (&rest keywords)
(format "%s Join: %s (%s) joined %s"
(s-pad-left oni:circe-longest-nick " " "***")
(plist-get keywords :nick)
(plist-get keywords :userinfo)
(plist-get keywords :channel)))
(defun oni:circe-server-join-formatter (&rest keywords)
(format "%s %s joined the channel"
(s-pad-left oni:circe-longest-nick " " "***")
(plist-get keywords :nick)))
(defun oni:circe-server-quit-formatter (&rest keywords)
(format "%s %s quit IRC: %s"
(s-pad-left oni:circe-longest-nick " " "***")
(plist-get keywords :nick)
(plist-get keywords :reason)))
(defun oni:circe-server-quit-channel-formatter (&rest keywords)
(format "%s %s left %s: %s"
(s-pad-left oni:circe-longest-nick " " "***")
(plist-get keywords :nick)
(plist-get keywords :channel)
(plist-get keywords :reason)))
(defun oni:circe-server-part-formatter (&rest keywords)
(format "%s %s parted %s: %s"
(s-pad-left oni:circe-longest-nick " " "***")
(plist-get keywords :nick)
(plist-get keywords :channel)
(plist-get keywords :reason)))
(defun oni:circe-server-nick-change-formatter (&rest keywords)
(format "%s %s is now known as %s"
(s-pad-left oni:circe-longest-nick " " "***")
(plist-get keywords :old-nick)
(plist-get keywords :new-nick)))
(setq circe-format-self-action #'oni:circe-action-formatter)
(setq circe-format-action #'oni:circe-action-formatter)
(setq circe-format-server-message #'oni:circe-server-message-formatter)
(setq circe-format-server-join-in-channel
#'oni:circe-server-join-in-channel-formatter)
(setq circe-format-server-join #'oni:circe-server-join-formatter)
(setq circe-format-server-quit #'oni:circe-server-quit-formatter)
(setq circe-format-server-quit-channel
#'oni:circe-server-quit-channel-formatter)
(setq circe-format-server-part #'oni:circe-server-part-formatter)
(setq circe-format-server-nick-change
#'oni:circe-server-nick-change-formatter)
#+END_SRC
* Automatically join some channels
I started using IRC because #mowedline was started and I felt
obligated to join it as I was one of two known Mowedline users at
the time. So now that's the one I'm usually active in. I do like to
keep an eye on #emacs from time to time and #ninthfloor in case
something happens there, though usually not.
#+BEGIN_SRC emacs-lisp
(defun oni:circe-nickserv-password (_)
(let ((found (nth 0 (auth-source-search :max 1
:host "irc.freenode.net"
:require '(:secret)))))
(when found
(let ((secret (plist-get found :secret)))
(if (functionp secret)
(funcall secret)
secret)))))
(setq circe-network-options
`(("Freenode"
:nick "ryuslash"
:channels ("#emacs" "#mowedline" "#ninthfloor")
:nickserv-password oni:circe-nickserv-password)))
#+END_SRC
* Change the time-stamp
I use only a small window to view the IRC channel I'm in usually,
the default format put the time-stamp just a little too far to the
right and would always cause either line truncation or filling to
the next line. So I put the time-stamp in the right margin so it's
always to the right of all messages and no messages can run under
it, so essentially it has it's own column.
#+BEGIN_SRC emacs-lisp
(setq lui-time-stamp-position 'right-margin)
(setq lui-time-stamp-format "%H:%M")
#+END_SRC
Give the right margin just enough room to show the time-stamps, no
more, no less.
#+BEGIN_SRC emacs-lisp
(defun oni:set-circe-margin-width ()
(setq right-margin-width 5))
(add-hook 'lui-mode-hook #'oni:set-circe-margin-width)
#+END_SRC
* Clean-up the channel buffers further
When chatting with people in an IRC channel, there really isn't much
need for any information in the mode-line. This is mostly because
the channel I'm most active on always has its own window. Visual
line mode is very handy to have in chats, in case I type very long
lines. And the =wrap-prefix= is set so that when I do type long lines,
they are filled nicely to the circe prompt.
#+BEGIN_SRC emacs-lisp
(defun oni:remove-mode-line ()
(setq mode-line-format nil))
(defun oni:set-circe-prompt-wrap-prefix ()
(setq wrap-prefix " "))
(add-hook 'circe-channel-mode-hook #'oni:remove-mode-line)
(add-hook 'circe-channel-mode-hook #'oni:set-circe-prompt-wrap-prefix)
(add-hook 'circe-channel-mode-hook 'visual-line-mode)
#+END_SRC
* Show #mowedline in a frame without minibuffer
When I'm chatting on #mowedline I do so in a separate small window.
This window needs no minibuffer as I do very little actualy Emacsy
things in it. Just typing a little and reading. So far I only do
this with #mowedline. In order to specifically show it in a frame
without a minibuffer I use =display-buffer-alist= to specify how to
show it. The function called dynamically binds =default-frame-alist=
to add a =minibuffer= element with the value =nil= (meaning, no
minibuffer). I can't do this in the regular =default-frame-alist=
because I want all other frames to show up /with/ a minibuffer. It
then creates a new frame and switches to the given buffer in it.
#+BEGIN_SRC emacs-lisp
(defun oni:display-in-minibufferless-frame (buffer _)
(let ((default-frame-alist default-frame-alist))
(push '(minibuffer . nil) default-frame-alist)
(let ((frame (make-frame)))
(select-frame frame)
(switch-to-buffer buffer))))
(add-to-list 'display-buffer-alist
'("^\#mowedline$" oni:display-in-minibufferless-frame))
#+END_SRC
* Provide the right feature
In order to be able to use =(require 'circe-init)= we must first
=provide= it.
#+BEGIN_SRC emacs-lisp
(provide 'circe-init)
#+END_SRC