223 lines
9 KiB
Org Mode
223 lines
9 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.
|
|
|
|
* Enable lexical binding
|
|
|
|
#+BEGIN_SRC emacs-lisp :padline no
|
|
;; -*- lexical-binding: t -*-
|
|
#+END_SRC
|
|
|
|
* 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 '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) ?\ )))
|
|
(plist-put keywords :nick (s-pad-left oni:circe-longest-nick " " nick))
|
|
(lui-format "{nick} {body}" keywords)))
|
|
#+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
|
|
|
|
* 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
|