-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcirce-znc.el
147 lines (121 loc) · 5.61 KB
/
circe-znc.el
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
;;; -*- lexical-binding: t -*-
;;; circe-znc.el --- A convenient interface to *controlpanel
;; Author: alphor
;; Version: 0.0.1
;; Keywords: circe znc
;; This set of functions requires you to have the controlpanel module enabled.
;; The neat thing about the controlpanel module is that it allows you to message
;; commands that modify configuration that would require you to use the web front
;; end. This is a little tedious. But the syntax for controlpanel is also kind of
;; tedious.
;; These functions make it very easy to do what you want.
(require 'circe-actions)
(require 'subr-x)
(defvar circe-znc-status-table
(let ((hash-table (make-hash-table :test #'equal)))
(puthash "help" (lambda () (message "Test passed!")) hash-table)
hash-table)
"")
(defvar circe-znc-collect-timeout 10
"Number of seconds to wait before deactivating listener for some
extended ZNC output (AKA to a buffer). Raise this if output is cut
off (ie missing help messages). Lower this if subsequent requests
are piped to the same buffer.")
(defvar circe-znc-controlpanel-table
(let ((hash-table (make-hash-table :test #'equal)))
(puthash "help" (lambda () (message "test failed. :(")) hash-table)
hash-table)
"Do NOT access this directly. Instead, use `circe-znc-get-command'")
(defvar circe-znc-modules-table
(let ((hash-table (make-hash-table :test #'equal)))
(puthash "*controlpanel" circe-znc-controlpanel-table hash-table)
(puthash "*status" circe-znc-status-table hash-table)
hash-table)
"A top level hash table linking modules to their options defined in the last version of ZNC (1.6.3). Do not access this directly! Instead use `circe-znc-get-command-table'. This is to allow for modification of this table down the line.")
(defvar circe-znc--help-sentinels
(let ((table (make-hash-table :test #'equal)))
;; thank computer jesus for re-builder
(puthash "*controlpanel" '(:re "^+=\+\\+=\+\\+$" :times 3) table)
table)
"set of conditions that determine if help output has ceased. As of now only supports :re and :times as conditions, eventual support for custom timeouts.")
(defun circe-znc-get-command-table (module-name)
"Get the hash table of a specific ZNC module, given its name."
(gethash module-name circe-znc-modules-table))
(defun circe-znc-get-command (module-name command)
"Get appropriate command from module, given its name. Usage:
(circe-znc-get-command \"*status\" \"broadcast\")
=> (lambda (&optional broadcast-string) ...)"
(let ((module-commands (gethash module-name circe-znc-modules-table)))
(gethash command module-commands)))
(defun circe-znc-module-help (&optional module)
"Prompt for a module, call the help function of that modules table."
(interactive)
;; should I wrap this and the next let-expr in a let*?
;; it's for sure uglier looking
(when (not module)
(setq module (completing-read "Module\: "
(hash-table-keys circe-znc-modules-table)
nil
t)))
(funcall (gethash "help"
(circe-znc-get-command-table module))))
(defun circe-znc--collect-response-in-buf (module-name suffix string)
(let* ((bufname (concat "* " module-name suffix " *"))
(buf (circe-znc--get-buffer bufname)))
(if (funcall circe-znc--buf-is-live-p)
(progn
(setq-local circe-znc--sentinel-reached
(circe-znc--sentinel-p string))
(let ((buffer-read-only nil))
(insert string))))))
(defun circe-znc--collect-response-in-buf (bufname string)
"if no buffer, create it and display it.
Insert string at end of buffer."
(let ((buffer (circe-znc--get-buffer-create bufname)))
(with-current-buffer buffer
;; is this the right way to output to a read only buffer?
(let ((buffer-read-only nil))
(insert string)))
;; pop-to-buffer instead?
(display-buffer buffer)))
(defun circe-znc--get-buffer (bufname)
"If circe-znc--output-stale is set, clear the buffer.
This means that the associated handler has been deactivated!
(An alternate implementation might be to associate the symbol as a
buffer-local variable and simply check if the assoc handler is
deactivated.)
Otherwise simply return the buffer."
(if (get-buffer bufname) ; returns nil if it doesn't exist or killed
(with-current-buffer bufname
(if (funcall circe-znc--is-live-p) ; is buffer's handler still alive?
bufname
(kill-buffer bufname)
(circe-znc--get-buffer-create bufname)))
(let ((newbuf (generate-new-buffer bufname)))
(with-current-buffer newbuf
(circe-znc-output-mode)
(setq-local circe-znc--is-live-p (lambda () t)) ; initialize live-p
newbuf))))
(defun circe-znc--deactivation-p-gen (module-name)
"given a module-name, look up the sentinel in
`circe-znc--help-sentinels' and generate a closure for it, returning
true when the sentinel's :re and :times is satisfied."
(let* ((sentinel (gethash module-name circe-znc--help-sentinels))
(re (plist-get sentinel :re))
(times (plist-get sentinel :times))
(matches 0))
(lambda (string)
(if (string-match-p re string)
(if (<= times matches)
t
(setq matches (1+ matches)))))))
(defun circe-znc--is-live-p-gen ()
"As of now, just check to see if the re sentinels have been hit."
(lambda ()
circe-znc--is-live-p))
(define-derived-mode circe-znc-output-mode
special-mode
"*ZNC Command Output*"
"a (very) thin wrapper around `special-mode'")
(provide 'circe-znc)
;;; circe-znc.el ends here