about summary refs log tree commit diff stats
path: root/lisp/acdw-erc.el
blob: dd8525d4895ad3dcc669e291641eef42fe2896d9 (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
224
225
226
227
228
;;; acdw-erc.el -*- lexical-binding: t; coding: utf-8-unix -*-

;; Author: Case Duckworth <acdw@acdw.net>
;; Created: 24 May 2021
;; Keywords: configuration
;; URL: https://tildegit.org/acdw/emacs

;; This file is NOT part of GNU Emacs.

;;; License:
;; Everyone is permitted to do whatever with this software, without
;; limitation.  This software comes without any warranty whatsoever,
;; but with two pieces of advice:
;; - Don't hurt yourself.
;; - Make good choices.

;;; Commentary:
;; `acdw-erc' is a dumping ground for functions and stuff for ERC, so they
;; don't clutter up `init.el'.

;;; Code:

(defgroup acdw-erc nil
  "Customizations for ERC."
  :group 'erc)


;;; Show a different header-line face when ERC is disconnected.
;; https://www.emacswiki.org/emacs/ErcModeline#h5o-1

(defface erc/header-line-disconnected
  '((t (:foreground "black" :background "indianred")))
  "Face to use when ERC has been disconnected.")

(defun erc/update-header-line-show-disconnected ()
  "Use a different face in the header-line when disconnected."
  (erc-with-server-buffer
    (cond ((erc-server-process-alive) 'erc-header-line)
          (t 'erc/header-line-disconnected))))


;;; Convenience functions
;; from Prelude:
;; https://github.com/bbatsov/prelude/blob/master/modules/prelude-erc.el#L114

(defcustom erc/servers nil
  "The list of IRC servers to connect to with `erc/connect'."
  :type '(list string))

(defcustom erc/bye-message "See You Space Cowpokes."
  "Quit message sent when calling `erc/disconnect'."
  :type 'string)

(defun connect-to-erc (server &optional use-tls port nick)
  "Connects to IRC SERVER at PORT with NICK.
If USE-TLS is non-nil, use TLS."
  (let* ((use-tls (or use-tls t))
         (erc-fn (if use-tls #'erc-tls #'erc))
         (port (or port (if use-tls 6697 6667)))
         (nick (or nick erc-nick)))
    (funcall erc-fn
             :server server
             :port port
             :nick nick)))

(defun erc/connect ()
  "Connect to all the servers in `erc/servers'."
  (interactive)
  (require 'erc)
  (mapcar #'connect-to-erc erc/servers))

(defun filter-server-buffers ()
  (delq nil (mapcar (lambda (x)
                      (and (erc-server-buffer-p x) x))
                    (buffer-list))))

(defun erc/reconnect ()
  "Reconnect to all IRC servers."
  (interactive)
  (dolist (buffer (filter-server-buffers))
    (with-current-buffer buffer
      (ignore-errors
        (erc-cmd-RECONNECT)))))

(defun erc/disconnect ()
  "Disconnect from all IRC servers."
  (interactive)
  (dolist (buffer (filter-server-buffers))
    (with-message (format "Killing server buffer: %s" (buffer-name buffer))
      (with-current-buffer buffer
        (erc-quit-server erc/bye-message))))
  ;; TODO: kill all channel buffers
  (force-mode-line-update))

(defun acdw-erc/prompt ()
  "The prompt to show for ERC."
  ;; Rewrite s-truncate to avoid dependency.
  (let ((name (buffer-name))
        (ellipsis "~")
        (len erc-fill-static-center))
    (if (and len (> (length name) (- len 2)))
        (format "%s%s>"
                (substring name 0 (- len 2 (length ellipsis)))
                ellipsis)
      (propertize
       (format "%s%s>"
               name
               (let ((ss)               ; Rewrite s-repeat to avoid dependency.
                     (num (- len 2 (length name))))
                 (while (> num 0)
                   (setq ss (cons " " ss))
                   (setq num (1- num)))
                 (apply #'concat ss)))
       'read-only t
       'intangible t
       'cursor-intangible t))))

(defcustom erc-nick-truncate nil
  "The width at which to truncate a nick with `erc-format-truncate-@nick'."
  :group 'erc
  :type 'integer)

(defalias 'erc-propertize 'propertize)  ; I guess...taken out in 28 ?

(defun erc-format-truncate-@nick (&optional user channel-data)
  "Format the nickname of USER as in `erc-format-@nick', with truncation.
Truncation is customized using the `erc-nick-truncate' variable.
See also `erc-format-nick-function'."
  (when user
    (let* ((nick (erc-server-user-nickname user))
           (prefix (erc-get-user-mode-prefix nick))
           (ellipsis "~")
           (max-len (- erc-nick-truncate 2 ; one each for < and >
                       (length ellipsis)
                       (length prefix))))
      (concat (erc-propertize
               prefix
               'font-lock-face 'erc-nick-prefix-face)
              (if (and max-len (> (length nick) max-len))
                  (format "%s%s" (substring nick 0 max-len)
                          ellipsis)
                nick)))))


;;; Uh

(defun acdw-erc/erc-switch-to-buffer (&optional arg)
  "Prompt for ERC buffer to switch to.
Reverse prefix argument from `erc-switch-to-buffer'."
  (interactive "P")
  (erc-switch-to-buffer (not arg)))


;;; ERC-Bar
;; NEEDS MUCH WORK

(defun erc-bar-move-back (n)
  "Moves back n message lines. Ignores wrapping, and server messages."
  (interactive "nHow many lines ? ")
  (re-search-backward "^.*<.*>" nil t n))

(defun erc-bar-update-overlay ()
  "Update the overlay for current buffer, based on the content of
erc-modified-channels-alist. Should be executed on window change."
  (interactive)
  (let* ((info (assq (current-buffer) erc-modified-channels-alist))
         (count (cadr info)))
    (if (and info (> count erc-bar-threshold))
        (save-excursion
          (end-of-buffer)
          (when (erc-bar-move-back count)
            (let ((inhibit-field-text-motion t))
              (move-overlay erc-bar-overlay
                            (line-beginning-position)
                            (line-end-position)
                            (current-buffer)))))
      (delete-overlay erc-bar-overlay))))

(defvar erc-bar-threshold 0
  "Display bar when there are more than erc-bar-threshold unread messages.")

(defvar erc-bar-overlay nil
  "Overlay used to set bar")

(setq erc-bar-overlay (make-overlay 0 0))
(overlay-put erc-bar-overlay 'face '(:overline "gray"))

(with-eval-after-load 'erc-track
  ;;put the hook before erc-modified-channels-update
  (defadvice erc-track-mode (after erc-bar-setup-hook
                                   (&rest args) activate)
    (add-hook 'window-configuration-change-hook 'erc-bar-update-overlay -90))

  (add-hook 'erc-send-completed-hook (lambda (str)
                                       (erc-bar-update-overlay))))


;;; ZNC babeee
;; needed variables are stored in private.el
(defun znc/connect (znc-server znc-port znc-nick irc-servers)
  (interactive (let ((zserv (or znc/server
                                (read-string "ZNC Server: ")))
                     (zport (or znc/port
                                (read-number "ZNC Port: ")))
                     (znick (or znc/nick
                                (read-string "ZNC Nick: ")))
                     (servers (or znc/irc-servers
                                  (list
                                   (cons
                                    (read-string "IRC Server to connect to: ")
                                    (read-passwd "Password: "))))))
                 (list zserv zport znick servers)))
  (let ((si 0))
    (dolist (server irc-servers)
      (run-at-time si nil
                   (lambda ()
                     (erc-tls :server znc-server
                              :port znc-port
                              :nick znc-nick
                              :password (format "%s/%s:%s"
                                                znc-nick
                                                (car server)
                                                (cdr server)))))
      (setq si (1+ si)))))


(provide 'acdw-erc)
;;; acdw-erc.el ends here