summaryrefslogtreecommitdiffstats
path: root/emacs/.emacs.d/init-circe.org
blob: d0ab011a96e879a80f892b762a41095b1278792e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#+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-getter (host)
      (lambda (_)
        (let ((found (nth 0 (auth-source-search :max 1
                                                :host host
                                                :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"
                        "#dispass"
                        "#linuxvoice"
                        "#conkeror")
             :nickserv-password ,(oni:circe-nickserv-password-getter "irc.freenode.net"))
            ("Twitch"
             :use-tls nil
             :nick "ryuslash"
             :host "irc.twitch.tv"
             :pass ,(oni:circe-nickserv-password-getter "irc.twitch.tv")
             :port 6667)))
  #+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

* Show colored nicks

  Show colored nicks in IRC buffers.

  #+BEGIN_SRC emacs-lisp
    (require 'circe-color-nicks)
    (enable-circe-color-nicks)
  #+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