aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorMichael Olson <[email protected]>2007-09-08 03:07:09 +0000
committerMichael Olson <[email protected]>2007-09-08 03:07:09 +0000
commit526dc846a10978763f1d5c883c0ec61fe43fb9bf (patch)
tree3bbde03d323d54c6fa8065eff28d1a25ca6502c2 /lisp
parent9a4d5e0c05815ade4cf75523b54686594dcb9dfc (diff)
Sync ERC 5.3 (devel) from upstream
Diffstat (limited to 'lisp')
-rw-r--r--lisp/erc/erc-backend.el111
-rw-r--r--lisp/erc/erc-button.el2
-rw-r--r--lisp/erc/erc-compat.el13
-rw-r--r--lisp/erc/erc-goodies.el15
-rw-r--r--lisp/erc/erc-identd.el3
-rw-r--r--lisp/erc/erc-log.el67
-rw-r--r--lisp/erc/erc-sound.el10
-rw-r--r--lisp/erc/erc-stamp.el76
-rw-r--r--lisp/erc/erc-track.el97
-rw-r--r--lisp/erc/erc.el255
10 files changed, 470 insertions, 179 deletions
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 349f913706..4e250490e9 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -550,11 +550,12 @@ We will store server variables in the buffer given by BUFFER."
(defun erc-server-reconnect ()
"Reestablish the current IRC connection.
Make sure you are in an ERC buffer when running this."
- (let ((server (erc-server-buffer)))
- (unless (and server
- (buffer-live-p server))
- (error "Couldn't switch to server buffer"))
- (with-current-buffer server
+ (let ((buffer (erc-server-buffer)))
+ (unless (buffer-live-p buffer)
+ (if (eq major-mode 'erc-mode)
+ (setq buffer (current-buffer))
+ (error "Reconnect must be run from an ERC buffer")))
+ (with-current-buffer buffer
(erc-update-mode-line)
(erc-set-active-buffer (current-buffer))
(setq erc-server-last-sent-time 0)
@@ -609,39 +610,61 @@ EVENT is the message received from the closed connection process."
;; open-network-stream-nowait error for connection refused
(not (string-match "^failed with code 111" event)))))
-(defun erc-process-sentinel-1 (event)
+(defun erc-process-sentinel-2 (event buffer)
+ "Called when `erc-process-sentinel-1' has detected an unexpected disconnect."
+ (if (not (buffer-live-p buffer))
+ (erc-update-mode-line)
+ (with-current-buffer buffer
+ (let ((reconnect-p (erc-server-reconnect-p event)))
+ (erc-display-message nil 'error (current-buffer)
+ (if reconnect-p 'disconnected
+ 'disconnected-noreconnect))
+ (if (not reconnect-p)
+ ;; terminate, do not reconnect
+ (progn
+ (erc-display-message nil 'error (current-buffer)
+ 'terminated ?e event)
+ ;; Update mode line indicators
+ (erc-update-mode-line)
+ (set-buffer-modified-p nil))
+ ;; reconnect
+ (condition-case err
+ (progn
+ (setq erc-server-reconnecting nil)
+ (erc-server-reconnect)
+ (setq erc-server-reconnect-count 0))
+ (error (when (buffer-live-p buffer)
+ (set-buffer buffer)
+ (if (integerp erc-server-reconnect-attempts)
+ (setq erc-server-reconnect-count
+ (1+ erc-server-reconnect-count))
+ (message "%s ... %s"
+ "Reconnecting until we succeed"
+ "kill the ERC server buffer to stop"))
+ (if (numberp erc-server-reconnect-timeout)
+ (run-at-time erc-server-reconnect-timeout nil
+ #'erc-process-sentinel-2
+ event buffer)
+ (error (concat "`erc-server-reconnect-timeout`"
+ " must be a number")))))))))))
+
+(defun erc-process-sentinel-1 (event buffer)
"Called when `erc-process-sentinel' has decided that we're disconnecting.
Determine whether user has quit or whether erc has been terminated.
Conditionally try to reconnect and take appropriate action."
- (if erc-server-quitting
- ;; normal quit
- (progn
- (erc-display-message nil 'error (current-buffer) 'finished)
- (when erc-kill-server-buffer-on-quit
+ (with-current-buffer buffer
+ (if erc-server-quitting
+ ;; normal quit
+ (progn
+ (erc-display-message nil 'error (current-buffer) 'finished)
+ ;; Update mode line indicators
+ (erc-update-mode-line)
+ ;; Kill server buffer if user wants it
(set-buffer-modified-p nil)
- (kill-buffer (current-buffer))))
- ;; unexpected disconnect
- (let ((again t))
- (while again
- (setq again nil)
- (erc-display-message nil 'error (current-buffer)
- (if (erc-server-reconnect-p event)
- 'disconnected
- 'disconnected-noreconnect))
- (if (erc-server-reconnect-p event)
- (condition-case err
- (progn
- (setq erc-server-reconnecting nil)
- (erc-server-reconnect)
- (setq erc-server-reconnect-count 0))
- (error (when (integerp erc-server-reconnect-attempts)
- (setq erc-server-reconnect-count
- (1+ erc-server-reconnect-count))
- (sit-for erc-server-reconnect-timeout)
- (setq again t))))
- ;; terminate, do not reconnect
- (erc-display-message nil 'error (current-buffer)
- 'terminated ?e event))))))
+ (when erc-kill-server-buffer-on-quit
+ (kill-buffer (current-buffer))))
+ ;; unexpected disconnect
+ (erc-process-sentinel-2 event buffer))))
(defun erc-process-sentinel (cproc event)
"Sentinel function for ERC process."
@@ -668,12 +691,7 @@ Conditionally try to reconnect and take appropriate action."
(delete-region (point) (point-max))
;; Decide what to do with the buffer
;; Restart if disconnected
- (erc-process-sentinel-1 event)
- ;; Make sure we don't write to the buffer if it has been
- ;; killed
- (when (buffer-live-p buf)
- (erc-update-mode-line)
- (set-buffer-modified-p nil))))))
+ (erc-process-sentinel-1 event buf)))))
;;;; Sending messages
@@ -1054,8 +1072,11 @@ Would expand to:
\"Some non-generic variable documentation.
Hook called upon receiving a WHOIS server response.
+
Each function is called with two arguments, the process associated
- with the response and the parsed response.
+ with the response and the parsed response. If the function returns
+ non-nil, stop processing the hook. Otherwise, continue.
+
See also `erc-server-311'.\")
(defalias 'erc-server-WI 'erc-server-311)
@@ -1064,7 +1085,9 @@ Would expand to:
Hook called upon receiving a WI server response.
Each function is called with two arguments, the process associated
- with the response and the parsed response.
+ with the response and the parsed response. If the function returns
+ non-nil, stop processing the hook. Otherwise, continue.
+
See also `erc-server-311'.\"))
\(fn (NAME &rest ALIASES) &optional EXTRA-FN-DOC EXTRA-VAR-DOC &rest FN-BODY)"
@@ -1078,7 +1101,9 @@ Would expand to:
(fn-name (intern (format "erc-server-%s" name)))
(hook-doc (format "%sHook called upon receiving a %%s server response.
Each function is called with two arguments, the process associated
-with the response and the parsed response.
+with the response and the parsed response. If the function returns
+non-nil, stop processing the hook. Otherwise, continue.
+
See also `%s'."
(if extra-var-doc
(concat extra-var-doc "\n\n")
diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el
index 35a20d5279..81c604d053 100644
--- a/lisp/erc/erc-button.el
+++ b/lisp/erc/erc-button.el
@@ -99,7 +99,7 @@ above them."
(concat "\\(www\\.\\|\\(s?https?\\|"
"ftp\\|file\\|gopher\\|news\\|telnet\\|wais\\|mailto\\):\\)"
"\\(//[-a-zA-Z0-9_.]+:[0-9]*\\)?"
- "[-a-zA-Z0-9_=!?#$@~`%&*+\\/:;.,]+[-a-zA-Z0-9_=#$@~`%&*+\\/]")
+ "[-a-zA-Z0-9_=!?#$@~`%&*+\\/:;.,()]+[-a-zA-Z0-9_=#$@~`%&*+\\/()]")
"Regular expression that matches URLs."
:group 'erc-button
:type 'regexp)
diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el
index 8be3bed1a7..47bdd94ade 100644
--- a/lisp/erc/erc-compat.el
+++ b/lisp/erc/erc-compat.el
@@ -56,6 +56,18 @@ See `erc-encoding-coding-alist'."
(format-time-string "%Y-%m-%d" emacs-build-time))
"Time at which Emacs was dumped out.")
+;; Emacs 21 and XEmacs do not have user-emacs-directory, but XEmacs
+;; has user-init-directory.
+(defvar erc-user-emacs-directory
+ (cond ((boundp 'user-emacs-directory)
+ user-emacs-directory)
+ ((boundp 'user-init-directory)
+ user-init-directory)
+ (t "~/.emacs.d/"))
+ "Directory beneath which additional per-user Emacs-specific files
+are placed.
+Note that this should end with a directory separator.")
+
;; XEmacs' `replace-match' does not replace matching subexpressions in strings.
(defun erc-replace-match-subexpression-in-string
(newtext string match subexp start &optional fixedcase literal)
@@ -68,6 +80,7 @@ See `replace-match' for explanations of FIXEDCASE and LITERAL."
(replace-match newtext fixedcase literal string))
(t (replace-match newtext fixedcase literal string subexp))))
+(defalias 'erc-with-selected-window 'with-selected-window)
(defalias 'erc-cancel-timer 'cancel-timer)
(defalias 'erc-make-obsolete 'make-obsolete)
(defalias 'erc-make-obsolete-variable 'make-obsolete-variable)
diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el
index 49a0451373..9131ce6828 100644
--- a/lisp/erc/erc-goodies.el
+++ b/lisp/erc/erc-goodies.el
@@ -84,8 +84,7 @@ DISPLAY-START is ignored."
;; works, but it solves the problem, and has no negative side effects.
;; (Fran Litterio, 2003/01/07)
(let ((resize-mini-windows nil))
- (save-selected-window
- (select-window window)
+ (erc-with-selected-window window
(save-restriction
(widen)
(when (and erc-insert-marker
@@ -282,10 +281,8 @@ The value `erc-interpret-controls-p' must also be t for this to work."
"Fetches the right face for background color N (0-15)."
(if (stringp n) (setq n (string-to-number n)))
(if (not (numberp n))
- (progn
- (message "erc-get-bg-color-face: n is NaN: %S" n)
- (beep)
- 'default)
+ (prog1 'default
+ (erc-error "erc-get-bg-color-face: n is NaN: %S" n))
(when (> n 16)
(erc-log (format " Wrong color: %s" n))
(setq n (mod n 16)))
@@ -298,10 +295,8 @@ The value `erc-interpret-controls-p' must also be t for this to work."
"Fetches the right face for foreground color N (0-15)."
(if (stringp n) (setq n (string-to-number n)))
(if (not (numberp n))
- (progn
- (message "erc-get-fg-color-face: n is NaN: %S" n)
- (beep)
- 'default)
+ (prog1 'default
+ (erc-error "erc-get-fg-color-face: n is NaN: %S" n))
(when (> n 16)
(erc-log (format " Wrong color: %s" n))
(setq n (mod n 16)))
diff --git a/lisp/erc/erc-identd.el b/lisp/erc/erc-identd.el
index 4b72ee171b..db933094e1 100644
--- a/lisp/erc/erc-identd.el
+++ b/lisp/erc/erc-identd.el
@@ -74,7 +74,8 @@ This can be either a string or a number."
(format "%s, %s : USERID : %s : %s\n"
port-on-server port-on-client
system-type (user-login-name)))
- (process-send-eof erc-identd-process)))))
+ (stop-process erc-identd-process)
+ (delete-process proc)))))
;;;###autoload
(defun erc-identd-start (&optional port)
diff --git a/lisp/erc/erc-log.el b/lisp/erc/erc-log.el
index 88132afae0..856f1dca89 100644
--- a/lisp/erc/erc-log.el
+++ b/lisp/erc/erc-log.el
@@ -31,17 +31,26 @@
;; Quick start:
;;
-;; (setq erc-enable-logging t)
+;; (require 'erc-log)
;; (setq erc-log-channels-directory "/path/to/logfiles") ; must be writable
+;; (erc-log-enable)
;;
-;; There are two ways to setup logging. The first will write to the log files
-;; on each incoming or outgoing line - this may not be optimal on a laptop
-;; HDD. To do this, M-x customize-variable erc-modules, and add "log".
+;; Or:
;;
-;; The second method will save buffers on /part, /quit, or killing the
-;; channel buffer. To do this, add the following to your .emacs:
+;; M-x customize-variable erc-modules, and add "log".
;;
-;; (require 'erc-log)
+;; There are two ways to setup logging. The first (default) method
+;; will save buffers on /part, /quit, or killing the channel
+;; buffer.
+;;
+;; The second will write to the log files on each incoming or outgoing
+;; line - this may not be optimal on a laptop HDD. To use this
+;; method, add the following to the above instructions.
+;;
+;; (setq erc-save-buffer-on-part nil
+;; erc-save-queries-on-quit nil
+;; erc-log-write-after-send t
+;; erc-log-write-after-insert t)
;;
;; If you only want to save logs for some buffers, customise the
;; variable `erc-enable-logging'.
@@ -99,15 +108,19 @@ The function must take five arguments: BUFFER, TARGET, NICK, SERVER and PORT.
BUFFER is the buffer to be saved,
TARGET is the name of the channel, or the target of the query,
NICK is the current nick,
-SERVER and PORT are the parameters used to connect BUFFERs
-`erc-server-process'."
+SERVER and PORT are the parameters that were used to connect to BUFFERs
+`erc-server-process'.
+
+If you want to write logs into different directories, make a
+custom function which returns the directory part and set
+`erc-log-channels-directory' to its name."
:group 'erc-log
:type '(choice (const :tag "Long style" erc-generate-log-file-name-long)
(const :tag "Long, but with network name rather than server"
erc-generate-log-file-name-network)
(const :tag "Short" erc-generate-log-file-name-short)
(const :tag "With date" erc-generate-log-file-name-with-date)
- (symbol :tag "Other function")))
+ (function :tag "Other function")))
(defcustom erc-truncate-buffer-on-save nil
"Truncate any ERC (channel, query, server) buffer when it is saved."
@@ -134,10 +147,16 @@ Log files are stored in `erc-log-channels-directory'."
"The directory to place log files for channels.
Leave blank to disable logging. If not nil, all the channel
buffers are logged in separate files in that directory. The
-directory should not end with a trailing slash."
+directory should not end with a trailing slash.
+
+If this is the name of a function, the function will be called
+with the buffer, target, nick, server, and port arguments. See
+`erc-generate-log-file-name-function' for a description of these
+arguments."
:group 'erc-log
:type '(choice directory
- (const nil)))
+ (function "Function")
+ (const :tag "Disable logging" nil)))
(defcustom erc-log-insert-log-on-open nil
"*Insert log file contents into the buffer if a log file exists."
@@ -297,7 +316,8 @@ Logging is enabled if `erc-log-channels-directory' is non-nil, the directory
is writeable (it will be created as necessary) and
`erc-enable-logging' returns a non-nil value."
(and erc-log-channels-directory
- (erc-directory-writable-p erc-log-channels-directory)
+ (or (functionp erc-log-channels-directory)
+ (erc-directory-writable-p erc-log-channels-directory))
(if (functionp erc-enable-logging)
(funcall erc-enable-logging (or buffer (current-buffer)))
erc-enable-logging)))
@@ -316,14 +336,19 @@ filename is downcased."
If BUFFER is nil, the value of `current-buffer' is used.
This is determined by `erc-generate-log-file-name-function'.
The result is converted to lowercase, as IRC is case-insensitive"
- (expand-file-name
- (erc-log-standardize-name
- (funcall erc-generate-log-file-name-function
- (or buffer (current-buffer))
- (or (buffer-name buffer) (erc-default-target))
- (erc-current-nick)
- erc-session-server erc-session-port))
- erc-log-channels-directory))
+ (unless buffer (setq buffer (current-buffer)))
+ (let ((target (or (buffer-name buffer) (erc-default-target)))
+ (nick (erc-current-nick))
+ (server erc-session-server)
+ (port erc-session-port))
+ (expand-file-name
+ (erc-log-standardize-name
+ (funcall erc-generate-log-file-name-function
+ buffer target nick server port))
+ (if (functionp erc-log-channels-directory)
+ (funcall erc-log-channels-directory
+ buffer target nick server port)
+ erc-log-channels-directory))))
(defun erc-generate-log-file-name-with-date (buffer &rest ignore)
"This function computes a short log file name.
diff --git a/lisp/erc/erc-sound.el b/lisp/erc/erc-sound.el
index 4d3d792b1b..d02887a69d 100644
--- a/lisp/erc/erc-sound.el
+++ b/lisp/erc/erc-sound.el
@@ -125,7 +125,7 @@ See also `play-sound-file'."
(if (and (not filepath) erc-default-sound)
(setq filepath erc-default-sound))
(cond ((and filepath (file-exists-p filepath))
- (play-sound-file filepath))
+ (play-sound-file filepath))
(t (beep)))
(erc-log (format "Playing sound file %S" filepath))))
@@ -142,5 +142,11 @@ See also `play-sound-file'."
(provide 'erc-sound)
-;; arch-tag: 53657d1d-007f-4a20-91c1-588e71cf0cee
;;; erc-sound.el ends here
+;;
+;; Local Variables:
+;; indent-tabs-mode: t
+;; tab-width: 8
+;; End:
+
+;; arch-tag: 53657d1d-007f-4a20-91c1-588e71cf0cee
diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el
index d67dffeaed..3b7f5ba18f 100644
--- a/lisp/erc/erc-stamp.el
+++ b/lisp/erc/erc-stamp.el
@@ -58,16 +58,48 @@ If nil, timestamping is turned off."
:type '(choice (const nil)
(string)))
-(defcustom erc-insert-timestamp-function 'erc-insert-timestamp-right
+(defcustom erc-timestamp-format-left "\n[%a %b %e %Y]\n"
+ "*If set to a string, messages will be timestamped.
+This string is processed using `format-time-string'.
+Good examples are \"%T\" and \"%H:%M\".
+
+This timestamp is used for timestamps on the left side of the
+screen when `erc-insert-timestamp-function' is set to
+`erc-insert-timestamp-left-and-right'.
+
+If nil, timestamping is turned off."
+ :group 'erc-stamp
+ :type '(choice (const nil)
+ (string)))
+
+(defcustom erc-timestamp-format-right " [%H:%M]"
+ "*If set to a string, messages will be timestamped.
+This string is processed using `format-time-string'.
+Good examples are \"%T\" and \"%H:%M\".
+
+This timestamp is used for timestamps on the right side of the
+screen when `erc-insert-timestamp-function' is set to
+`erc-insert-timestamp-left-and-right'.
+
+If nil, timestamping is turned off."
+ :group 'erc-stamp
+ :type '(choice (const nil)
+ (string)))
+
+(defcustom erc-insert-timestamp-function 'erc-insert-timestamp-left-and-right
"*Function to use to insert timestamps.
It takes a single argument STRING which is the final string
which all text-properties already appended. This function only cares about
inserting this string at the right position. Narrowing is in effect
while it is called, so (point-min) and (point-max) determine the region to
-operate on."
+operate on.
+
+You will probably want to set
+`erc-insert-away-timestamp-function' to the same value."
:group 'erc-stamp
- :type '(choice (const :tag "Right" erc-insert-timestamp-right)
+ :type '(choice (const :tag "Both sides" erc-insert-timestamp-left-and-right)
+ (const :tag "Right" erc-insert-timestamp-right)
(const :tag "Left" erc-insert-timestamp-left)
function))
@@ -82,12 +114,14 @@ If `erc-timestamp-format' is set, this will not be used."
:type '(choice (const nil)
(string)))
-(defcustom erc-insert-away-timestamp-function 'erc-insert-timestamp-right
+(defcustom erc-insert-away-timestamp-function
+ 'erc-insert-timestamp-left-and-right
"*Function to use to insert the away timestamp.
See `erc-insert-timestamp-function' for details."
:group 'erc-stamp
- :type '(choice (const :tag "Right" erc-insert-timestamp-right)
+ :type '(choice (const :tag "Both sides" erc-insert-timestamp-left-and-right)
+ (const :tag "Right" erc-insert-timestamp-right)
(const :tag "Left" erc-insert-timestamp-left)
function))
@@ -160,6 +194,18 @@ or `erc-send-modify-hook'."
"Last timestamp inserted into the buffer.")
(make-variable-buffer-local 'erc-timestamp-last-inserted)
+(defvar erc-timestamp-last-inserted-left nil
+ "Last timestamp inserted into the left side of the buffer.
+This is used when `erc-insert-timestamp-function' is set to
+`erc-timestamp-left-and-right'")
+(make-variable-buffer-local 'erc-timestamp-last-inserted-left)
+
+(defvar erc-timestamp-last-inserted-right nil
+ "Last timestamp inserted into the right side of the buffer.
+This is used when `erc-insert-timestamp-function' is set to
+`erc-timestamp-left-and-right'")
+(make-variable-buffer-local 'erc-timestamp-last-inserted-right)
+
(defcustom erc-timestamp-only-if-changed-flag t
"*Insert timestamp only if its value changed since last insertion.
If `erc-insert-timestamp-function' is `erc-insert-timestamp-left', a
@@ -272,6 +318,26 @@ be printed just before the window-width."
(when erc-timestamp-intangible
(erc-put-text-property from (1+ (point)) 'intangible t)))))
+(defun erc-insert-timestamp-left-and-right (string)
+ "This is another function that can be assigned to
+`erc-insert-timestamp-function'. If the date is changed, it will
+print a blank line, the date, and another blank line. If the time is
+changed, it will then print it off to the right."
+ (let* ((ct (current-time))
+ (ts-left (erc-format-timestamp ct erc-timestamp-format-left))
+ (ts-right (erc-format-timestamp ct erc-timestamp-format-right)))
+ ;; insert left timestamp
+ (unless (string-equal ts-left erc-timestamp-last-inserted-left)
+ (goto-char (point-min))
+ (erc-put-text-property 0 (length ts-left) 'field 'erc-timestamp ts-left)
+ (insert ts-left)
+ (setq erc-timestamp-last-inserted-left ts-left))
+ ;; insert right timestamp
+ (let ((erc-timestamp-only-if-changed-flag t)
+ (erc-timestamp-last-inserted erc-timestamp-last-inserted-right))
+ (erc-insert-timestamp-right ts-right)
+ (setq erc-timestamp-last-inserted-right ts-right))))
+
;; for testing: (setq erc-timestamp-only-if-changed-flag nil)
(defun erc-format-timestamp (time format)
diff --git a/lisp/erc/erc-track.el b/lisp/erc/erc-track.el
index f72a5be1de..5865257434 100644
--- a/lisp/erc/erc-track.el
+++ b/lisp/erc/erc-track.el
@@ -95,6 +95,12 @@ Activity means that there was no user input in the last 10 seconds."
:group 'erc-track
:type '(repeat string))
+(defcustom erc-track-remove-disconnected-buffers nil
+ "*If true, remove buffers associated with a server that is
+disconnected from `erc-modified-channels-alist'."
+ :group 'erc-track
+ :type 'boolean)
+
(defcustom erc-track-exclude-types '("NICK")
"*List of message types to be ignored.
This list could look like '(\"JOIN\" \"PART\")."
@@ -151,6 +157,16 @@ If nil instead of a function, shortening is disabled."
:type '(choice (const :tag "Disabled")
function))
+(defcustom erc-track-list-changed-hook nil
+ "Hook that is run whenever the contents of
+`erc-modified-channels-alist' changes.
+
+This is useful for people that don't use the default mode-line
+notification but instead use a separate mechanism to provide
+notification of channel activity."
+ :group 'erc-track
+ :type 'hook)
+
(defcustom erc-track-use-faces t
"*Use faces in the mode-line.
The faces used are the same as used for text in the buffers.
@@ -192,12 +208,14 @@ Setting this variable only has effects in GNU Emacs versions above 21.3.
Choices are:
'before-modes - add to the beginning of `mode-line-modes'
'after-modes - add to the end of `mode-line-modes'
-
-Any other value means add to the end of `global-mode-string'."
+t - add to the end of `global-mode-string'.
+nil - don't add to mode line
+"
:group 'erc-track
:type '(choice (const :tag "Just before mode information" before-modes)
(const :tag "Just after mode information" after-modes)
- (const :tag "After all other information" nil))
+ (const :tag "After all other information" t)
+ (const :tag "Don't display in mode line" nil))
:set (lambda (sym val)
(set sym val)
(when (and (boundp 'erc-track-mode)
@@ -263,12 +281,14 @@ when there are no more active channels."
(defcustom erc-track-switch-direction 'oldest
"Direction `erc-track-switch-buffer' should switch.
+ importance - find buffer with the most important message
oldest - find oldest active buffer
newest - find newest active buffer
leastactive - find buffer with least unseen messages
mostactive - find buffer with most unseen messages."
:group 'erc-track
- :type '(choice (const oldest)
+ :type '(choice (const importance)
+ (const oldest)
(const newest)
(const leastactive)
(const mostactive)))
@@ -296,7 +316,7 @@ See `erc-track-position-in-mode-line' for possible values."
(boundp 'mode-line-modes))
(add-to-list 'mode-line-modes
'(t erc-modified-channels-object) t))
- (t
+ ((eq position t)
(when (not global-mode-string)
(setq global-mode-string '(""))) ; Padding for mode-line wart
(add-to-list 'global-mode-string
@@ -644,14 +664,21 @@ only consider active buffers visible.")
(setq erc-buffer-activity (erc-current-time))
(erc-track-modified-channels))
+(defun erc-track-get-buffer-window (buffer frame-param)
+ (if (eq frame-param 'selected-visible)
+ (if (eq (frame-visible-p (selected-frame)) t)
+ (get-buffer-window buffer nil)
+ nil)
+ (get-buffer-window buffer frame-param)))
+
(defun erc-buffer-visible (buffer)
"Return non-nil when the buffer is visible."
(if erc-track-when-inactive
(when erc-buffer-activity; could be nil
- (and (get-buffer-window buffer erc-track-visibility)
+ (and (erc-track-get-buffer-window buffer erc-track-visibility)
(<= (erc-time-diff erc-buffer-activity (erc-current-time))
erc-buffer-activity-timeout)))
- (get-buffer-window buffer erc-track-visibility)))
+ (erc-track-get-buffer-window buffer erc-track-visibility)))
;;; Tracking the channel modifications
@@ -668,18 +695,22 @@ called via `window-configuration-change-hook'.
ARGS are ignored."
(interactive)
(unless erc-modified-channels-update-inside
- (let ((erc-modified-channels-update-inside t))
+ (let ((erc-modified-channels-update-inside t)
+ (removed-channel nil))
(mapcar (lambda (elt)
(let ((buffer (car elt)))
(when (or (not (bufferp buffer))
(not (buffer-live-p buffer))
(erc-buffer-visible buffer)
+ (and erc-track-remove-disconnected-buffers
(not (with-current-buffer buffer
- erc-server-connected)))
+ erc-server-connected))))
+ (setq removed-channel t)
(erc-modified-channels-remove-buffer buffer))))
erc-modified-channels-alist)
+ (when removed-channel
(erc-modified-channels-display)
- (force-mode-line-update t))))
+ (force-mode-line-update t)))))
(defvar erc-track-mouse-face (if (featurep 'xemacs)
'modeline-mousable
@@ -729,10 +760,13 @@ If FACES are provided, color STRING with them."
"Set `erc-modified-channels-object'
according to `erc-modified-channels-alist'.
Use `erc-make-mode-line-buffer-name' to create buttons."
- (if (or
- (eq 'mostactive erc-track-switch-direction)
- (eq 'leastactive erc-track-switch-direction))
- (erc-track-sort-by-activest))
+ (cond ((or (eq 'mostactive erc-track-switch-direction)
+ (eq 'leastactive erc-track-switch-direction))
+ (erc-track-sort-by-activest))
+ ((eq 'importance erc-track-switch-direction)
+ (erc-track-sort-by-importance)))
+ (run-hooks 'erc-track-list-changed-hook)
+ (unless (eq erc-track-position-in-mode-line nil)
(if (null erc-modified-channels-alist)
(setq erc-modified-channels-object (erc-modified-channels-object nil))
;; erc-modified-channels-alist contains all the data we need. To
@@ -768,7 +802,7 @@ Use `erc-make-mode-line-buffer-name' to create buttons."
(when (featurep 'xemacs)
(erc-modified-channels-object nil))
(setq erc-modified-channels-object
- (erc-modified-channels-object strings)))))
+ (erc-modified-channels-object strings))))))
(defun erc-modified-channels-remove-buffer (buffer)
"Remove BUFFER from `erc-modified-channels-alist'."
@@ -802,8 +836,7 @@ is in `erc-mode'."
(if (and (not (erc-buffer-visible (current-buffer)))
(not (member this-channel erc-track-exclude))
(not (and erc-track-exclude-server-buffer
- (string= this-channel
- (buffer-name (erc-server-buffer)))))
+ (erc-server-buffer-p)))
(not (erc-message-type-member
(or (erc-find-parsed-property)
(point-min))
@@ -847,10 +880,10 @@ is in `erc-mode'."
(erc-modified-channels-display)))
;; Else if the active buffer is the current buffer, remove it
;; from our list.
- (when (or (erc-buffer-visible (current-buffer))
+ (when (and (or (erc-buffer-visible (current-buffer))
(and this-channel
- (assq (current-buffer) erc-modified-channels-alist)
(member this-channel erc-track-exclude)))
+ (assq (current-buffer) erc-modified-channels-alist))
;; Remove it from mode-line if buffer is visible or
;; channel was added to erc-track-exclude recently.
(erc-modified-channels-remove-buffer (current-buffer))
@@ -887,6 +920,29 @@ That means the number of unseen messages in a channel."
(sort erc-modified-channels-alist
(lambda (a b) (> (nth 1 a) (nth 1 b))))))
+(defun erc-track-face-priority (face)
+ "Return a number indicating the priority of FACE in
+`erc-track-faces-priority-list'. Lower number means higher
+priority.
+
+If face is not in `erc-track-faces-priority-list', it will have a
+higher number than any other face in that list."
+ (let ((count 0))
+ (catch 'done
+ (dolist (item erc-track-faces-priority-list)
+ (if (eq item face)
+ (throw 'done t)
+ (setq count (1+ count)))))
+ count))
+
+(defun erc-track-sort-by-importance ()
+ "Sort erc-modified-channels-alist by importance.
+That means the position of the face in `erc-track-faces-priority-list'."
+ (setq erc-modified-channels-alist
+ (sort erc-modified-channels-alist
+ (lambda (a b) (< (erc-track-face-priority (cddr a))
+ (erc-track-face-priority (cddr b)))))))
+
(defun erc-track-get-active-buffer (arg)
"Return the buffer name of ARG in `erc-modified-channels-alist'.
Negative arguments index in the opposite direction. This direction is
@@ -898,7 +954,8 @@ relative to `erc-track-switch-direction'"
(oldest 'newest)
(newest 'oldest)
(mostactive 'leastactive)
- (leastactive 'mostactive)))
+ (leastactive 'mostactive)
+ (importance 'oldest)))
(setq arg (- arg)))
(setq offset (case dir
((oldest leastactive)
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 2ebadd1a5d..2c5786adff 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -66,7 +66,7 @@
;;; Code:
-(defconst erc-version-string "Version 5.2"
+(defconst erc-version-string "Version 5.3 (devel)"
"ERC version. This is used by function `erc-version'.")
(eval-when-compile (require 'cl))
@@ -836,8 +836,9 @@ See `erc-server-flood-margin' for other flood-related parameters.")
;; Script parameters
(defcustom erc-startup-file-list
- '("~/.emacs.d/.ercrc.el" "~/.emacs.d/.ercrc"
- "~/.ercrc.el" "~/.ercrc" ".ercrc.el" ".ercrc")
+ (list (concat erc-user-emacs-directory ".ercrc.el")
+ (concat erc-user-emacs-directory ".ercrc")
+ "~/.ercrc.el" "~/.ercrc" ".ercrc.el" ".ercrc")
"List of files to try for a startup script.
The first existent and readable one will get executed.
@@ -1460,7 +1461,7 @@ Turning on `erc-mode' runs the hook `erc-mode-hook'."
(defconst erc-default-server "irc.freenode.net"
"IRC server to use if it cannot be detected otherwise.")
-(defconst erc-default-port "6667"
+(defconst erc-default-port 6667
"IRC port to use if it cannot be detected otherwise.")
(defcustom erc-join-buffer 'buffer
@@ -1491,6 +1492,14 @@ This only has effect when `erc-join-buffer' is set to `frame'."
:group 'erc-buffers
:type 'boolean)
+(defcustom erc-reuse-frames t
+ "*Determines whether new frames are always created.
+Non-nil means that a new frame is not created to display an ERC
+buffer if there is already a window displaying it. This only has
+effect when `erc-join-buffer' is set to `frame'."
+ :group 'erc-buffers
+ :type 'boolean)
+
(defun erc-channel-p (channel)
"Return non-nil if CHANNEL seems to be an IRC channel name."
(cond ((stringp channel)
@@ -1888,14 +1897,16 @@ removed from the list will be disabled."
((eq erc-join-buffer 'bury)
nil)
((eq erc-join-buffer 'frame)
- (funcall '(lambda (frame)
+ (when (or (not erc-reuse-frames)
+ (not (get-buffer-window buffer t)))
+ ((lambda (frame)
(raise-frame frame)
(select-frame frame))
(make-frame (or erc-frame-alist
default-frame-alist)))
(switch-to-buffer buffer)
(when erc-frame-dedicated-flag
- (set-window-dedicated-p (selected-window) t)))
+ (set-window-dedicated-p (selected-window) t))))
(t
(if (active-minibuffer-window)
(display-buffer buffer)
@@ -2155,16 +2166,48 @@ Arguments are the same as for `erc'."
"Open an SSL stream to an IRC server.
The process will be given the name NAME, its target buffer will be
BUFFER. HOST and PORT specify the connection target."
- (when (require 'tls)
- (let ((proc (open-tls-stream name buffer host port)))
+ (when (condition-case nil
+ (require 'ssl)
+ (error (message "You don't have ssl.el. %s"
+ "Try using `erc-tls' instead.")
+ nil))
+ (let ((proc (open-ssl-stream name buffer host port)))
;; Ugly hack, but it works for now. Problem is it is
;; very hard to detect when ssl is established, because s_client
;; doesn't give any CONNECTIONESTABLISHED kind of message, and
;; most IRC servers send nothing and wait for you to identify.
- ;; Disabled when switching to tls.el -- jas
- ;(sit-for 5)
+ (sit-for 5)
proc)))
+(defun erc-tls (&rest r)
+ "Interactively select TLS connection parameters and run ERC.
+Arguments are the same as for `erc'."
+ (interactive (erc-select-read-args))
+ (let ((erc-server-connect-function 'erc-open-tls-stream))
+ (apply 'erc r)))
+
+(defun erc-open-tls-stream (name buffer host port)
+ "Open an TLS stream to an IRC server.
+The process will be given the name NAME, its target buffer will be
+BUFFER. HOST and PORT specify the connection target."
+ (when (condition-case nil
+ (require 'tls)
+ (error (message "You don't have tls.el. %s"
+ "Try using `erc-ssl' instead.")
+ nil))
+ (open-tls-stream name buffer host port)))
+
+;;; Displaying error messages
+
+(defun erc-error (&rest args)
+ "Pass ARGS to `format', and display the result as an error message.
+If `debug-on-error' is set to non-nil, then throw a real error with this
+message instead, to make debugging easier."
+ (if debug-on-error
+ (apply #'error args)
+ (apply #'message args)
+ (beep)))
+
;;; Debugging the protocol
(defvar erc-debug-irc-protocol nil
@@ -2456,6 +2499,14 @@ See also `erc-server-send'."
(match-string 1 arglist)
arglist)))
+(defun erc-command-no-process-p (str)
+ "Return non-nil if STR is an ERC command that can be run when the process
+is not alive, nil otherwise."
+ (let ((fun (erc-extract-command-from-line str)))
+ (and fun
+ (symbolp (car fun))
+ (get (car fun) 'process-not-needed))))
+
(defun erc-command-name (cmd)
"For CMD being the function name of a ERC command, something like
erc-cmd-FOO, this returns a string /FOO."
@@ -2565,6 +2616,7 @@ VALUE is computed by evaluating the rest of LINE in Lisp."
(defalias 'erc-cmd-VAR 'erc-cmd-SET)
(defalias 'erc-cmd-VARIABLE 'erc-cmd-SET)
(put 'erc-cmd-SET 'do-not-parse-args t)
+(put 'erc-cmd-SET 'process-not-needed t)
(defun erc-cmd-default (line)
"Fallback command.
@@ -2623,6 +2675,7 @@ If no USER argument is specified, list the contents of `erc-ignore-list'."
"Clear the window content."
(recenter 0)
t)
+(put 'erc-cmd-CLEAR 'process-not-needed t)
(defun erc-cmd-OPS ()
"Show the ops in the current channel."
@@ -2656,6 +2709,7 @@ If no USER argument is specified, list the contents of `erc-ignore-list'."
(erc-display-message
nil 'notice 'active 'country-unknown ?d tld))
t))
+(put 'erc-cmd-COUNTRY 'process-not-needed t)
(defun erc-cmd-AWAY (line)
"Mark the user as being away, the reason being indicated by LINE.
@@ -2736,6 +2790,7 @@ For a list of user commands (/join /part, ...):
t))
(defalias 'erc-cmd-H 'erc-cmd-HELP)
+(put 'erc-cmd-HELP 'process-not-needed t)
(defun erc-cmd-JOIN (channel &optional key)
"Join the channel given in CHANNEL, optionally with KEY.
@@ -2973,6 +3028,7 @@ the matching is case-sensitive."
(occur line)
t)
(put 'erc-cmd-LASTLOG 'do-not-parse-args t)
+(put 'erc-cmd-LASTLOG 'process-not-needed t)
(defun erc-send-message (line &optional force)
"Send LINE to the current channel or user and display it.
@@ -3195,20 +3251,34 @@ the message given by REASON."
(defalias 'erc-cmd-EXIT 'erc-cmd-QUIT)
(defalias 'erc-cmd-SIGNOFF 'erc-cmd-QUIT)
(put 'erc-cmd-QUIT 'do-not-parse-args t)
+(put 'erc-cmd-QUIT 'process-not-needed t)
(defun erc-cmd-GQUIT (reason)
"Disconnect from all servers at once with the same quit REASON."
(erc-with-all-buffers-of-server nil #'erc-open-server-buffer-p
- (erc-cmd-QUIT reason)))
+ (erc-cmd-QUIT reason))
+ (when erc-kill-queries-on-quit
+ ;; if the query buffers have not been killed within 4 seconds,
+ ;; kill them
+ (run-at-time
+ 4 nil
+ (lambda ()
+ (dolist (buffer (erc-buffer-list (lambda (buf)
+ (not (erc-server-buffer-p buf)))))
+ (kill-buffer buffer)))))
+ t)
(defalias 'erc-cmd-GQ 'erc-cmd-GQUIT)
(put 'erc-cmd-GQUIT 'do-not-parse-args t)
+(put 'erc-cmd-GQUIT 'process-not-needed t)
(defun erc-cmd-RECONNECT ()
"Try to reconnect to the current IRC server."
- (let ((buffer (or (erc-server-buffer) (current-buffer)))
+ (let ((buffer (erc-server-buffer))
(process nil))
- (with-current-buffer (if (bufferp buffer) buffer (current-buffer))
+ (unless (buffer-live-p buffer)
+ (setq buffer (current-buffer)))
+ (with-current-buffer buffer
(setq erc-server-quitting nil)
(setq erc-server-reconnecting t)
(setq erc-server-reconnect-count 0)
@@ -3218,6 +3288,7 @@ the message given by REASON."
(erc-server-reconnect))
(setq erc-server-reconnecting nil)))
t)
+(put 'erc-cmd-RECONNECT 'process-not-needed t)
(defun erc-cmd-SERVER (server)
"Connect to SERVER, leaving existing connection intact."
@@ -3225,9 +3296,9 @@ the message given by REASON."
(condition-case nil
(erc :server server :nick (erc-current-nick))
(error
- (message "Cannot find host %s." server)
- (beep)))
+ (erc-error "Cannot find host %s." server)))
t)
+(put 'erc-cmd-SERVER 'process-not-needed t)
(eval-when-compile
(defvar motif-version-string)
@@ -4411,33 +4482,65 @@ See also `erc-channel-begin-receiving-names'."
erc-channel-users)
(setq erc-channel-new-member-names nil))
+(defun erc-parse-prefix ()
+ "Return an alist of valid prefix character types and their representations.
+Example: (operator) o => @, (voiced) v => +."
+ (let ((str (or (cdr (assoc "PREFIX" (erc-with-server-buffer
+ erc-server-parameters)))
+ ;; provide a sane default
+ "(ov)@+"))
+ types chars)
+ (when (string-match "^(\\([^)]+\\))\\(.+\\)$" str)
+ (setq types (match-string 1 str)
+ chars (match-string 2 str))
+ (let ((len (min (length types) (length chars)))
+ (i 0)
+ (alist nil))
+ (while (< i len)
+ (setq alist (cons (cons (elt types i) (elt chars i))
+ alist))
+ (setq i (1+ i)))
+ alist))))
+
(defun erc-channel-receive-names (names-string)
"This function is for internal use only.
Update `erc-channel-users' according to NAMES-STRING.
NAMES-STRING is a string listing some of the names on the
channel."
- (let (names name op voice)
- ;; We need to delete "" because in XEmacs, (split-string "a ")
- ;; returns ("a" "").
- (setq names (delete "" (split-string names-string)))
- (let ((erc-channel-members-changed-hook nil))
- (dolist (item names)
- (cond ((string-match "^@\\(.*\\)$" item)
- (setq name (match-string 1 item)
- op 'on
- voice 'off))
- ((string-match "^+\\(.*\\)$" item)
- (setq name (match-string 1 item)
- op 'off
- voice 'on))
- (t (setq name item
- op 'off
- voice 'off)))
- (puthash (erc-downcase name) t
- erc-channel-new-member-names)
- (erc-update-current-channel-member
- name name t op voice)))
+ (let (prefix op-ch voice-ch names name op voice)
+ (setq prefix (erc-parse-prefix))
+ (setq op-ch (cdr (assq ?o prefix))
+ voice-ch (cdr (assq ?v prefix)))
+ ;; We need to delete "" because in XEmacs, (split-string "a ")
+ ;; returns ("a" "").
+ (setq names (delete "" (split-string names-string)))
+ (let ((erc-channel-members-changed-hook nil))
+ (dolist (item names)
+ (let ((updatep t)
+ ch)
+ (if (rassq (elt item 0) prefix)
+ (cond ((= (length item) 1)
+ (setq updatep nil))
+ ((eq (elt item 0) op-ch)
+ (setq name (substring item 1)
+ op 'on
+ voice 'off))
+ ((eq (elt item 0) voice-ch)
+ (setq name (substring item 1)
+ op 'off
+ voice 'on))
+ (t (setq name (substring item 1)
+ op 'off
+ voice 'off)))
+ (setq name item
+ op 'off
+ voice 'off))
+ (when updatep
+ (puthash (erc-downcase name) t
+ erc-channel-new-member-names)
+ (erc-update-current-channel-member
+ name name t op voice)))))
(run-hooks 'erc-channel-members-changed-hook)))
(defcustom erc-channel-members-changed-hook nil
@@ -4529,15 +4632,15 @@ See also: `erc-update-user' and `erc-update-channel-member'."
(setq changed t)
(setf (erc-channel-user-op cuser)
(cond ((eq op 'on) t)
- ((eq op 'off) nil)
- (t op))))
+ ((eq op 'off) nil)
+ (t op))))
(when (and voice
(not (eq (erc-channel-user-voice cuser) voice)))
(setq changed t)
(setf (erc-channel-user-voice cuser)
(cond ((eq voice 'on) t)
- ((eq voice 'off) nil)
- (t voice))))
+ ((eq voice 'off) nil)
+ (t voice))))
(when update-message-time
(setf (erc-channel-user-last-message-time cuser) (current-time)))
(setq user-changed
@@ -4559,11 +4662,11 @@ See also: `erc-update-user' and `erc-update-channel-member'."
(erc-server-user-buffers user))))
(setq cuser (make-erc-channel-user
:op (cond ((eq op 'on) t)
- ((eq op 'off) nil)
- (t op))
+ ((eq op 'off) nil)
+ (t op))
:voice (cond ((eq voice 'on) t)
- ((eq voice 'off) nil)
- (t voice))
+ ((eq voice 'off) nil)
+ (t voice))
:last-message-time
(if update-message-time (current-time))))
(puthash (erc-downcase nick) (cons user cuser)
@@ -4892,39 +4995,37 @@ Specifically, return the position of `erc-insert-marker'."
(interactive)
(save-restriction
(widen)
- (cond
- ((< (point) (erc-beg-of-input-line))
- (message "Point is not in the input area")
- (beep))
- ((not (erc-server-buffer-live-p))
- (message "ERC: No process running")
- (beep))
- (t
- (erc-set-active-buffer (current-buffer))
+ (if (< (point) (erc-beg-of-input-line))
+ (erc-error "Point is not in the input area")
(let ((inhibit-read-only t)
(str (erc-user-input))
(old-buf (current-buffer)))
-
- ;; Kill the input and the prompt
- (delete-region (erc-beg-of-input-line)
- (erc-end-of-input-line))
-
- (unwind-protect
- (erc-send-input str)
- ;; Fix the buffer if the command didn't kill it
- (when (buffer-live-p old-buf)
- (with-current-buffer old-buf
- (save-restriction
- (widen)
- (goto-char (point-max))
- (set-marker (process-mark erc-server-process) (point))
- (set-marker erc-insert-marker (point))
- (let ((buffer-modified (buffer-modified-p)))
- (erc-display-prompt)
- (set-buffer-modified-p buffer-modified))))))
-
- ;; Only when last hook has been run...
- (run-hook-with-args 'erc-send-completed-hook str))))))
+ (if (and (not (erc-server-buffer-live-p))
+ (not (erc-command-no-process-p str)))
+ (erc-error "ERC: No process running")
+ (erc-set-active-buffer (current-buffer))
+
+ ;; Kill the input and the prompt
+ (delete-region (erc-beg-of-input-line)
+ (erc-end-of-input-line))
+
+ (unwind-protect
+ (erc-send-input str)
+ ;; Fix the buffer if the command didn't kill it
+ (when (buffer-live-p old-buf)
+ (with-current-buffer old-buf
+ (save-restriction
+ (widen)
+ (goto-char (point-max))
+ (when (processp erc-server-process)
+ (set-marker (process-mark erc-server-process) (point)))
+ (set-marker erc-insert-marker (point))
+ (let ((buffer-modified (buffer-modified-p)))
+ (erc-display-prompt)
+ (set-buffer-modified-p buffer-modified))))))
+
+ ;; Only when last hook has been run...
+ (run-hook-with-args 'erc-send-completed-hook str))))))
(defun erc-user-input ()
"Return the input of the user in the current buffer."
@@ -4985,7 +5086,8 @@ This returns non-nil only if we actually send anything."
(erc-put-text-property beg (point)
'face 'erc-command-indicator-face)
(insert "\n"))
- (set-marker (process-mark erc-server-process) (point))
+ (when (processp erc-server-process)
+ (set-marker (process-mark erc-server-process) (point)))
(set-marker erc-insert-marker (point))
(save-excursion
(save-restriction
@@ -5004,7 +5106,8 @@ current position."
(erc-put-text-property beg (point)
'face 'erc-input-face))
(insert "\n")
- (set-marker (process-mark erc-server-process) (point))
+ (when (processp erc-server-process)
+ (set-marker (process-mark erc-server-process) (point)))
(set-marker erc-insert-marker (point))
(save-excursion
(save-restriction