From 526dc846a10978763f1d5c883c0ec61fe43fb9bf Mon Sep 17 00:00:00 2001 From: Michael Olson Date: Sat, 8 Sep 2007 03:07:09 +0000 Subject: [PATCH] Sync ERC 5.3 (devel) from upstream --- doc/misc/ChangeLog | 5 + doc/misc/erc.texi | 27 +++-- etc/ChangeLog | 5 + etc/ERC-NEWS | 16 +++ lisp/erc/erc-backend.el | 111 ++++++++++------- lisp/erc/erc-button.el | 2 +- lisp/erc/erc-compat.el | 13 ++ lisp/erc/erc-goodies.el | 15 +-- lisp/erc/erc-identd.el | 3 +- lisp/erc/erc-log.el | 67 +++++++---- lisp/erc/erc-sound.el | 10 +- lisp/erc/erc-stamp.el | 76 +++++++++++- lisp/erc/erc-track.el | 97 +++++++++++---- lisp/erc/erc.el | 255 ++++++++++++++++++++++++++++------------ 14 files changed, 512 insertions(+), 190 deletions(-) diff --git a/doc/misc/ChangeLog b/doc/misc/ChangeLog index 3d11858295..3652fb7365 100644 --- a/doc/misc/ChangeLog +++ b/doc/misc/ChangeLog @@ -1,3 +1,8 @@ +2007-09-08 Michael Olson + + * erc.texi (Copying): New section included from gpl.texi. This matches + the look of the upstream ERC manual. + 2007-09-07 Jay Belanger * calc.texi (History and Acknowledgements): Adjust the diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index ee1029321d..3ff8fce947 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -68,6 +68,10 @@ and modified without restriction. * Advanced Usage:: Cool ways of using ERC. * Getting Help and Reporting Bugs:: * History:: The history of ERC. +* Copying:: The GNU General Public License gives you + permission to redistribute ERC on + certain terms; it also explains that + there is no warranty. * GNU Free Documentation License:: The license for this documentation. * Concept Index:: Search for terms. @@ -900,7 +904,7 @@ stuff, to the current ERC buffer." @c previous chapter) This section has not yet been written. For now, the easiest way to -check out the available option for ERC is to do +check out the available options for ERC is to do @kbd{M-x customize-group erc RET}. @@ -916,7 +920,7 @@ or if you have bugs to report, there are several places you can go. @itemize @bullet @item -@uref{http://www.emacswiki.org/cgi-bin/wiki/EmacsIRCClient} is the +@uref{http://www.emacswiki.org/cgi-bin/wiki/ERC} is the emacswiki.org page for ERC. Anyone may add tips, hints, or bug descriptions to it. @@ -929,14 +933,11 @@ The mailing lists are also available on Gmane. accessing the mailing lists, adding content to them, and searching them. @enumerate -@item gmane.emacs.erc.announce -Announcements +@item gmane.emacs.erc.announce: Announcements -@item gmane.emacs.erc.discuss -General discussion +@item gmane.emacs.erc.discuss: General discussion -@item gmane.emacs.erc.cvs -Log messages for changes to the ERC source code +@item gmane.emacs.erc.cvs: Log messages for changes to the ERC source code @end enumerate @@ -948,7 +949,7 @@ questions. @end itemize -@node History, GNU Free Documentation License, Getting Help and Reporting Bugs, Top +@node History, Copying, Getting Help and Reporting Bugs, Top @comment node-name, next, previous, up @chapter History @cindex history, of ERC @@ -1010,8 +1011,12 @@ our revision control system. Our mailing list address changed as well. @end itemize -@node GNU Free Documentation License, Concept Index, History, Top -@appendix GNU Free Documentation License +@node Copying, GNU Free Documentation License, History, Top +@comment node-name, next, previous, up +@include gpl.texi + +@node GNU Free Documentation License, Concept Index, Copying, Top +@comment node-name, next, previous, up @include doclicense.texi @node Concept Index, , GNU Free Documentation License, Top diff --git a/etc/ChangeLog b/etc/ChangeLog index 8760888dcb..0ec046d506 100644 --- a/etc/ChangeLog +++ b/etc/ChangeLog @@ -1,3 +1,8 @@ +2007-09-08 Michael Olson + + * ERC-NEWS: Update for changes to the development version of ERC + 5.3. + 2007-09-06 Glenn Morris * ctags.1, emacs.1, emacsclient.1, etags.1: Move from etc/ to diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index f5bf1e89dd..409dcf03da 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -3,6 +3,22 @@ ERC NEWS -*- outline -*- Copyright (C) 2006, 2007 Free Software Foundation, Inc. See the end of the file for license conditions. +* Changes in ERC 5.3 + +** New function `erc-tls' is to be used for connecting to a server via TLS. +The function `erc-ssl' should never be used for that purpose any +longer, which was the case with the version of ERC that is included +with Emacs. + +** Changes and additions to modules + +*** Channel tracking (erc-track.el) + +If erc-track-position-in-mode-line is set to nil, the tracking +information won't be shown in the mode line, which is a change +from the previous behavior of showing it "After all other +information". + * Changes in ERC 5.2 ** M-x erc RET now starts ERC. 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 -- 2.20.1