d6994bb226355b6633efe8fb0eb405be6dca1324
[riece] / lisp / riece.el
1 ;;; riece.el --- IRC client for Emacsen
2 ;; Copyright (C) 1998-2003 Daiki Ueno
3
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
5 ;; Created: 1998-09-28
6 ;; Keywords: IRC, riece
7
8 ;; This file is part of Riece.
9
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Code:
26
27 (require 'riece-filter)
28 (require 'riece-display)
29 (require 'riece-server)
30 (require 'riece-compat)
31 (require 'riece-commands)
32
33 (defvar riece-channel-list-mode-map (make-sparse-keymap))
34 (defvar riece-user-list-mode-map (make-sparse-keymap))
35
36 (defvar riece-dialogue-mode-map
37   (let ((keymap (make-keymap)))
38     (suppress-keymap keymap 'nodigit)
39     keymap))
40
41 (defvar riece-command-mode-map (make-keymap))
42 (defvar riece-command-map (make-sparse-keymap))
43
44 (defvar riece-command-mode-syntax-table nil)
45
46 (put 'riece-command-mode 'mode-class 'special)
47 (put 'riece-dialogue-mode 'mode-class 'special)
48 (put 'riece-others-mode 'derived-mode-parent 'riece-dialogue-mode)
49 (put 'riece-channel-list-mode 'mode-class 'special)
50 (put 'riece-user-list-mode 'mode-class 'special)
51 (put 'riece-channel-mode 'derived-mode-parent 'riece-dialogue-mode)
52
53 (defvar riece-buffer-alist
54   '((riece-command-buffer "*Commands*" riece-command-mode)
55     (riece-dialogue-buffer "*Dialogue*" riece-dialogue-mode)
56     (riece-others-buffer "*Others*" riece-others-mode)
57     (riece-channel-list-buffer "*Channels*" riece-channel-list-mode)
58     (riece-user-list-buffer " *Users*" riece-user-list-mode)))
59
60 (defvar riece-select-keys
61   `("1" riece-command-switch-to-channel-by-number-1
62     "2" riece-command-switch-to-channel-by-number-2
63     "3" riece-command-switch-to-channel-by-number-3
64     "4" riece-command-switch-to-channel-by-number-4
65     "5" riece-command-switch-to-channel-by-number-5
66     "6" riece-command-switch-to-channel-by-number-6
67     "7" riece-command-switch-to-channel-by-number-7
68     "8" riece-command-switch-to-channel-by-number-8
69     "9" riece-command-switch-to-channel-by-number-9
70     "0" riece-command-switch-to-channel-by-number-10
71     ,(concat riece-command-prefix "1")
72     riece-command-switch-to-channel-by-number-11
73     ,(concat riece-command-prefix "2")
74     riece-command-switch-to-channel-by-number-12
75     ,(concat riece-command-prefix "3")
76     riece-command-switch-to-channel-by-number-13
77     ,(concat riece-command-prefix "4")
78     riece-command-switch-to-channel-by-number-14
79     ,(concat riece-command-prefix "5")
80     riece-command-switch-to-channel-by-number-15
81     ,(concat riece-command-prefix "6")
82     riece-command-switch-to-channel-by-number-16
83     ,(concat riece-command-prefix "7")
84     riece-command-switch-to-channel-by-number-17
85     ,(concat riece-command-prefix "8")
86     riece-command-switch-to-channel-by-number-18
87     ,(concat riece-command-prefix "9")
88     riece-command-switch-to-channel-by-number-19
89     ,(concat riece-command-prefix "0")
90     riece-command-switch-to-channel-by-number-20))
91
92 ;;; Keymap macros. -- borrowed from `gnus-util.el'.
93 (defmacro riece-local-set-keys (&rest plist)
94   "Set the keys in PLIST in the current keymap."
95   `(riece-define-keys-1 (current-local-map) ',plist))
96
97 (defmacro riece-define-keys (keymap &rest plist)
98   "Assign KEYMAP keys from PLIST."
99   `(riece-define-keys-1 ',keymap ',plist))
100
101 (defmacro riece-define-keys-safe (keymap &rest plist)
102   "Assign KEYMAP keys from PLIST without overwriting previous definitions."
103   `(riece-define-keys-1 ',keymap ',plist t))
104
105 (put 'riece-define-keys 'lisp-indent-function 1)
106 (put 'riece-define-keys-safe 'lisp-indent-function 1)
107 (put 'riece-local-set-keys 'lisp-indent-function 1)
108
109 (defun riece-define-keys-1 (keymap plist &optional safe)
110   "Assign KEYMAP keys from PLIST.
111 If optional argument SAFE is nil, overwrite previous definitions."
112   (unless keymap
113     (error "Can't set keys in a null keymap"))
114   (cond
115    ((symbolp keymap)
116     (setq keymap (symbol-value keymap)))
117    ((keymapp keymap))
118    ((listp keymap)
119     (set (car keymap) nil)
120     (define-prefix-command (car keymap))
121     (define-key (symbol-value (nth 2 keymap))
122       (if (symbolp (nth 1 keymap))
123           (symbol-value (nth 1 keymap))
124         (nth 1 keymap))
125       (car keymap))
126     (setq keymap (symbol-value (car keymap)))))
127   (let (key)
128     (while plist
129       (if (symbolp (setq key (car plist)))
130           (setq key (symbol-value key)))
131       (setq plist (cdr plist))
132       (if (or (not safe)
133               (eq (lookup-key keymap key) 'undefined))
134           (define-key keymap key (car plist))
135         (car plist))
136       (setq plist (cdr plist)))))
137
138 (when t
139   (riece-define-keys riece-dialogue-mode-map
140     "\177" scroll-down
141     [delete] scroll-down
142     [backspace] scroll-down
143     [return] scroll-up
144     " " scroll-up
145     "$" end-of-buffer
146     "/" riece-command-raw
147     ">" end-of-buffer
148     "<" beginning-of-buffer
149     "\C-ta" riece-command-toggle-away
150     "c" riece-command-select-command-buffer
151     "f" riece-command-finger
152     "\C-tf" riece-command-toggle-freeze
153     "\C-to" riece-command-toggle-own-freeze
154     "\C-tu" riece-command-toggle-user-list-buffer-mode
155     "\C-tc" riece-command-toggle-channel-buffer-mode
156     "\C-tC" riece-command-toggle-channel-list-buffer-mode
157     "\C-tl" riece-command-change-layout
158     "i" riece-command-invite
159     "j" riece-command-join
160     "\C-k" riece-command-kick
161     "l" riece-command-list
162     "M" riece-command-change-mode
163     "n" riece-command-change-nickname
164     "N" riece-command-names
165     "o" other-window
166     "O" riece-command-open-server
167     "C" riece-command-close-server
168     "M" riece-command-universal-server-name-argument
169     "q" riece-command-quit
170     "r" riece-command-configure-windows
171     "x" riece-command-copy-region
172     "t" riece-command-topic
173     "w" riece-command-who)
174
175   (riece-define-keys riece-command-mode-map
176     "\r" riece-command-enter-message
177     [(control return)] riece-command-enter-message-as-notice)
178
179   (riece-define-keys (riece-command-map riece-command-prefix
180                                         riece-command-mode-map)
181     "\177" riece-command-scroll-down
182     [delete] riece-command-scroll-down
183     [backspace] riece-command-scroll-down
184     " " riece-command-scroll-up
185     "$" riece-command-end-of-buffer
186     ">" riece-command-next-channel
187     "<" riece-command-previous-channel
188     "\C-j" riece-command-next-channel
189     "\C-n" riece-command-names
190     "l" riece-command-list
191     "\C-m" riece-command-change-mode
192     "o" riece-command-set-operators
193     "\C-p" riece-command-part
194     "r" riece-command-configure-windows
195     "v" riece-command-set-speakers
196     "V" riece-version)
197   (set-keymap-parent riece-command-map riece-dialogue-mode-map)
198
199   (riece-define-keys riece-user-list-mode-map
200     "o" riece-command-set-operators
201     "v" riece-command-set-voices
202     "f" riece-command-finger
203     " " riece-command-nick-scroll-up
204     "\177" riece-command-nick-scroll-down
205     [delete] riece-command-nick-scroll-down
206     [backspace] riece-command-nick-scroll-down
207     "c" riece-command-select-command-buffer)
208
209   (riece-define-keys riece-channel-list-mode-map
210     ">" riece-command-next-channel
211     "<" riece-command-previous-channel
212     "o" other-window
213     "c" riece-command-select-command-buffer)
214
215   (riece-define-keys-1 riece-dialogue-mode-map riece-select-keys)
216   (riece-define-keys-1 riece-channel-list-mode-map riece-select-keys))
217
218 (defun riece-read-variables-files (&optional file)
219   "Read variables FILEs."
220   (or (file-directory-p riece-directory)
221       (make-directory riece-directory))
222   (let ((files (if file
223                    (setq riece-variables-file file
224                          riece-variables-files (list file))
225                  riece-variables-files)))
226     (while files
227       (condition-case nil
228           (load (expand-file-name (car files)))
229         (file-error nil))
230       (setq files (cdr files)))))
231
232 (defvar print-quoted)
233 (defvar print-escape-multibyte)
234 (defun riece-save-variables-files ()
235   "Save current settings to `riece-variables-file'."
236   (with-temp-file riece-saved-variables-file
237     (let ((print-quoted t)
238           (print-readably t)
239           print-escape-multibyte
240           print-level
241           print-length
242           (variables riece-saved-forms))
243       (while variables
244         (prin1 `(setq ,(car variables)
245                       ',(symbol-value (car variables)))
246                (current-buffer))
247         (insert "\n")
248         (setq variables (cdr variables)))))
249   (setq riece-save-variables-are-dirty nil))
250
251 ;;;###autoload
252 (defun riece (&optional confirm)
253   "Connect to the IRC server and start chatting.
254 If optional argument CONFIRM is non-nil, ask which IRC server to connect."
255   (interactive "P")
256   (riece-read-variables-files (if noninteractive
257                                   (car command-line-args-left)))
258   (riece-insinuate-addons riece-addons)
259   (run-hooks 'riece-after-load-startup-hook)
260   (if (riece-server-opened)
261       (error "Already running"))
262   (if (or confirm (null riece-server))
263       (setq riece-server (completing-read "Server: " riece-server-alist)))
264   (if (stringp riece-server)
265       (setq riece-server (riece-server-name-to-server riece-server)))
266   (riece-create-buffers)
267   (switch-to-buffer riece-command-buffer)
268   (riece-redisplay-buffers)
269   (riece-open-server riece-server "")
270   (run-hooks 'riece-startup-hook)
271   (message "%s" (substitute-command-keys "Type \\[describe-mode] for help")))
272
273 (defun riece-exit ()
274   (if riece-save-variables-are-dirty
275       (riece-save-variables-files))
276   (while riece-buffer-list
277     (if (and (get-buffer (car riece-buffer-list))
278              (buffer-live-p (car riece-buffer-list)))
279         (funcall riece-buffer-dispose-function (car riece-buffer-list)))
280     (setq riece-buffer-list (cdr riece-buffer-list)))
281   (setq riece-server nil
282         riece-current-channels nil