;;; rcirc.el --- default, simple IRC client.
-;; Copyright (C) 2005-2011 Free Software Foundation, Inc.
+;; Copyright (C) 2005-2012 Free Software Foundation, Inc.
;; Author: Ryan Yeske <rcyeske@gmail.com>
;; Maintainers: Ryan Yeske <rcyeske@gmail.com>,
;; one-to-one communication.
;; Rcirc has simple defaults and clear and consistent behavior.
-;; Message arrival timestamps, activity notification on the modeline,
+;; Message arrival timestamps, activity notification on the mode line,
;; message filling, nick completion, and keepalive pings are all
;; enabled by default, but can easily be adjusted or turned off. Each
;; discussion takes place in its own buffer and there is a single
:group 'rcirc)
(defcustom rcirc-fill-flag t
- "*Non-nil means line-wrap messages printed in channel buffers."
+ "Non-nil means line-wrap messages printed in channel buffers."
:type 'boolean
:group 'rcirc)
(defcustom rcirc-fill-column nil
- "*Column beyond which automatic line-wrapping should happen.
+ "Column beyond which automatic line-wrapping should happen.
If nil, use value of `fill-column'. If 'frame-width, use the
maximum frame width."
:type '(choice (const :tag "Value of `fill-column'")
:group 'rcirc)
(defcustom rcirc-fill-prefix nil
- "*Text to insert before filled lines.
+ "Text to insert before filled lines.
If nil, calculate the prefix dynamically to line up text
underneath each nick."
:type '(choice (const :tag "Dynamic" nil)
(make-variable-buffer-local 'rcirc-omit-mode)
(defcustom rcirc-time-format "%H:%M "
- "*Describes how timestamps are printed.
+ "Describes how timestamps are printed.
Used as the first arg to `format-time-string'."
:type 'string
:group 'rcirc)
(defcustom rcirc-input-ring-size 1024
- "*Size of input history ring."
+ "Size of input history ring."
:type 'integer
:group 'rcirc)
(defcustom rcirc-read-only-flag t
- "*Non-nil means make text in IRC buffers read-only."
+ "Non-nil means make text in IRC buffers read-only."
:type 'boolean
:group 'rcirc)
(defcustom rcirc-buffer-maximum-lines nil
- "*The maximum size in lines for rcirc buffers.
+ "The maximum size in lines for rcirc buffers.
Channel buffers are truncated from the top to be no greater than this
number. If zero or nil, no truncating is done."
:type '(choice (const :tag "No truncation" nil)
:group 'rcirc)
(defcustom rcirc-scroll-show-maximum-output t
- "*If non-nil, scroll buffer to keep the point at the bottom of
+ "If non-nil, scroll buffer to keep the point at the bottom of
the window."
:type 'boolean
:group 'rcirc)
:group 'rcirc)
(defcustom rcirc-auto-authenticate-flag t
- "*Non-nil means automatically send authentication string to server.
+ "Non-nil means automatically send authentication string to server.
See also `rcirc-authinfo'."
:type 'boolean
:group 'rcirc)
(defcustom rcirc-authenticate-before-join t
- "*Non-nil means authenticate to services before joining channels.
+ "Non-nil means authenticate to services before joining channels.
Currently only works with NickServ on some networks."
:version "24.1"
:type 'boolean
:type 'string
:group 'rcirc)
+(defcustom rcirc-kill-channel-buffers nil
+ "When non-nil, kill channel buffers when the server buffer is killed.
+Only the channel buffers associated with the server in question
+will be killed."
+ :version "24.2"
+ :type 'boolean
+ :group 'rcirc)
+
(defvar rcirc-nick nil)
(defvar rcirc-prompt-start-marker nil)
"List of buffers with unviewed activity.")
(defvar rcirc-activity-string ""
- "String displayed in modeline representing `rcirc-activity'.")
+ "String displayed in mode line representing `rcirc-activity'.")
(put 'rcirc-activity-string 'risky-local-variable t)
(defvar rcirc-server-buffer nil
rcirc-default-full-name))
(channels (plist-get (cdr c) :channels))
(password (plist-get (cdr c) :password))
- (encryption (plist-get (cdr c) :encryption)))
+ (encryption (plist-get (cdr c) :encryption))
+ contact)
(when server
(let (connected)
(dolist (p (rcirc-process-list))
full-name channels password encryption)
(quit (message "Quit connecting to %s" server)))
(with-current-buffer (process-buffer connected)
- (setq connected-servers
- (cons (process-contact (get-buffer-process
- (current-buffer)) :host)
- connected-servers))))))))
+ (setq contact (process-contact
+ (get-buffer-process (current-buffer)) :host))
+ (setq connected-servers
+ (cons (if (stringp contact) contact server)
+ connected-servers))))))))
(when connected-servers
(message "Already connected to %s"
(if (cdr connected-servers)
(let ((msg "Encryption (default %s): ")
(choices '("plain" "tls"))
(default (or (plist-get server-plist :encryption)
- "plain")))
+ 'plain)))
(intern
(completing-read (format msg default)
- choices nil t "" nil default))))
+ choices nil t nil nil (symbol-name default)))))
(defun rcirc-keepalive ()
"Send keep alive pings to active rcirc processes.
(defun rcirc-disconnect-buffer (&optional buffer)
(with-current-buffer (or buffer (current-buffer))
;; set rcirc-target to nil for each channel so cleanup
- ;; doesnt happen when we reconnect
+ ;; doesn't happen when we reconnect
(setq rcirc-target nil)
(setq mode-line-process ":disconnected")))
(defvar rcirc-input-ring nil)
(defvar rcirc-input-ring-index 0)
+
(defun rcirc-prev-input-string (arg)
(ring-ref rcirc-input-ring (+ rcirc-input-ring-index arg)))
-(defun rcirc-insert-prev-input (arg)
- (interactive "p")
+(defun rcirc-insert-prev-input ()
+ (interactive)
(when (<= rcirc-prompt-end-marker (point))
(delete-region rcirc-prompt-end-marker (point-max))
(insert (rcirc-prev-input-string 0))
(setq rcirc-input-ring-index (1+ rcirc-input-ring-index))))
-(defun rcirc-insert-next-input (arg)
- (interactive "p")
+(defun rcirc-insert-next-input ()
+ (interactive)
(when (<= rcirc-prompt-end-marker (point))
(delete-region rcirc-prompt-end-marker (point-max))
(setq rcirc-input-ring-index (1- rcirc-input-ring-index))
map)
"Keymap for rcirc mode.")
-(defvar rcirc-browse-url-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "RET") 'rcirc-browse-url-at-point)
- (define-key map (kbd "<mouse-2>") 'rcirc-browse-url-at-mouse)
- (define-key map [follow-link] 'mouse-face)
- map)
- "Keymap used for browsing URLs in `rcirc-mode'.")
-
(defvar rcirc-short-buffer-name nil
"Generated abbreviation to use to indicate buffer activity.")
(setq mode-line-process nil)
(set (make-local-variable 'rcirc-input-ring)
- (make-ring rcirc-input-ring-size))
+ ;; If rcirc-input-ring is already a ring with desired size do
+ ;; not re-initialize.
+ (if (and (ring-p rcirc-input-ring)
+ (= (ring-size rcirc-input-ring)
+ rcirc-input-ring-size))
+ rcirc-input-ring
+ (make-ring rcirc-input-ring-size)))
(set (make-local-variable 'rcirc-server-buffer) (process-buffer process))
(set (make-local-variable 'rcirc-target) target)
(set (make-local-variable 'rcirc-topic) nil)
(set (make-local-variable 'rcirc-recent-quit-alist) nil)
(set (make-local-variable 'rcirc-current-line) 0)
+ (use-hard-newlines t)
(set (make-local-variable 'rcirc-short-buffer-name) nil)
(set (make-local-variable 'rcirc-urls) nil)
(setq buffer-invisibility-spec '())
(setq buffer-display-table (make-display-table))
(set-display-table-slot buffer-display-table 4
- (let ((glyph (make-glyph-code
+ (let ((glyph (make-glyph-code
?. 'font-lock-keyword-face)))
(make-vector 3 glyph)))
:group 'rcirc)
(defun rcirc-kill-buffer-hook ()
- "Part the channel when killing an rcirc buffer."
+ "Part the channel when killing an rcirc buffer.
+
+If `rcirc-kill-channel-buffers' is non-nil and the killed buffer
+is a server buffer, kills all of the channel buffers associated
+with it."
(when (eq major-mode 'rcirc-mode)
(when (and rcirc-log-flag
rcirc-log-directory)
(rcirc-log-write))
- (rcirc-clean-up-buffer "Killed buffer")))
+ (rcirc-clean-up-buffer "Killed buffer")
+ (when (and rcirc-buffer-alist ;; it's a server buffer
+ rcirc-kill-channel-buffers)
+ (dolist (channel rcirc-buffer-alist)
+ (kill-buffer (cdr channel))))))
(defun rcirc-change-major-mode-hook ()
"Part the channel when changing the major-mode."
(rcirc-generate-new-buffer-name process target))))
(with-current-buffer new-buffer
(rcirc-mode process target)
- (rcirc-put-nick-channel process (rcirc-nick process) target
+ (rcirc-put-nick-channel process (rcirc-nick process) target
rcirc-current-line))
new-buffer)))))
(interactive)
(let ((pos (1+ (- (point) rcirc-prompt-end-marker))))
(goto-char (point-max))
- (let ((text (buffer-substring-no-properties rcirc-prompt-end-marker
+ (let ((text (buffer-substring-no-properties rcirc-prompt-end-marker
(point)))
(parent (buffer-name)))
(delete-region rcirc-prompt-end-marker (point))
"Keymap for multiline mode in rcirc.")
(define-minor-mode rcirc-multiline-minor-mode
- "Minor mode for editing multiple lines in rcirc."
+ "Minor mode for editing multiple lines in rcirc.
+With a prefix argument ARG, enable the mode if ARG is positive,
+and disable it otherwise. If called from Lisp, enable the mode
+if ARG is omitted or nil."
:init-value nil
:lighter " rcirc-mline"
:keymap rcirc-multiline-minor-mode-map
(match-string 1 text)))
rcirc-ignore-list))
;; do not ignore if we sent the message
- (not (string= sender (rcirc-nick process))))
+ (not (string= sender (rcirc-nick process))))
(let* ((buffer (rcirc-target-buffer process sender response target text))
(inhibit-read-only t))
(with-current-buffer buffer
;; keep window on bottom line if it was already there
(when rcirc-scroll-show-maximum-output
- (walk-windows (lambda (w)
- (when (eq (window-buffer w) (current-buffer))
- (with-current-buffer (window-buffer w)
- (when (eq major-mode 'rcirc-mode)
- (with-selected-window w
- (when (<= (- (window-height)
- (count-screen-lines (window-point)
- (window-start))
- 1)
- 0)
- (recenter -1)))))))
- nil t))
+ (let ((window (get-buffer-window)))
+ (when window
+ (with-selected-window window
+ (when (eq major-mode 'rcirc-mode)
+ (when (<= (- (window-height)
+ (count-screen-lines (window-point)
+ (window-start))
+ 1)
+ 0)
+ (recenter -1)))))))
;; flush undo (can we do something smarter here?)
(buffer-disable-undo)
(buffer-enable-undo))
- ;; record modeline activity
+ ;; record mode line activity
(when (and activity
(not rcirc-ignore-buffer-activity-flag)
(not (and rcirc-dim-nicks sender
(defun rcirc-view-log-file ()
"View logfile corresponding to the current buffer."
(interactive)
- (find-file-other-window
- (expand-file-name (funcall rcirc-log-filename-function
+ (find-file-other-window
+ (expand-file-name (funcall rcirc-log-filename-function
(rcirc-buffer-process) rcirc-target)
rcirc-log-directory)))
;;;###autoload
(define-minor-mode rcirc-track-minor-mode
- "Global minor mode for tracking activity in rcirc buffers."
+ "Global minor mode for tracking activity in rcirc buffers.
+With a prefix argument ARG, enable the mode if ARG is positive,
+and disable it otherwise. If called from Lisp, enable the mode
+if ARG is omitted or nil."
:init-value nil
:lighter ""
:keymap rcirc-track-minor-mode-map
buffers ","))
(defun rcirc-short-buffer-name (buffer)
- "Return a short name for BUFFER to use in the modeline indicator."
+ "Return a short name for BUFFER to use in the mode line indicator."
(with-current-buffer buffer
(or rcirc-short-buffer-name (buffer-name))))
(dolist (b buffers) ;; order the new channel buffers in the buffer list
(switch-to-buffer b)))))
+(defun-rcirc-command invite (nick-channel)
+ "Invite NICK to CHANNEL."
+ (interactive (list
+ (concat
+ (completing-read "Invite nick: "
+ (with-rcirc-server-buffer rcirc-nick-table))
+ " "
+ (read-string "Channel: "))))
+ (rcirc-send-string process (concat "INVITE " nick-channel)))
+
;; TODO: /part #channel reason, or consider removing #channel altogether
(defun-rcirc-command part (channel)
"Part CHANNEL."
(browse-url (completing-read "rcirc browse-url: "
completions nil nil initial-input 'history)
arg)))
-
-(defun rcirc-browse-url-at-point (point)
- "Send URL at point to `browse-url'."
- (interactive "d")
- (let ((beg (previous-single-property-change (1+ point) 'mouse-face))
- (end (next-single-property-change point 'mouse-face)))
- (browse-url (buffer-substring-no-properties beg end))))
-
-(defun rcirc-browse-url-at-mouse (event)
- "Send URL at mouse click to `browse-url'."
- (interactive "e")
- (let ((position (event-end event)))
- (with-current-buffer (window-buffer (posn-window position))
- (rcirc-browse-url-at-point (posn-point position)))))
-
\f
(defun rcirc-markup-timestamp (sender response)
(goto-char (point-min))
(delete-region (match-beginning 1) (match-end 1))
(goto-char (match-beginning 1)))
;; remove the ^O characters now
+ (goto-char (point-min))
(while (re-search-forward "\C-o+" nil t)
(delete-region (match-beginning 0) (match-end 0))))
(while (and rcirc-url-regexp ;; nil means disable URL catching
(re-search-forward rcirc-url-regexp nil t))
(let ((start (match-beginning 0))
- (end (match-end 0)))
- (rcirc-add-face start end 'rcirc-url)
- (add-text-properties start end (list 'mouse-face 'highlight
- 'keymap rcirc-browse-url-map))
+ (end (match-end 0))
+ (url (match-string-no-properties 0)))
+ (make-button start end
+ 'face 'rcirc-url
+ 'follow-link t
+ 'rcirc-url url
+ 'action (lambda (button)
+ (browse-url (button-get button 'rcirc-url))))
;; record the url
- (push (buffer-substring-no-properties start end) rcirc-urls))))
+ (push url rcirc-urls))))
(defun rcirc-markup-keywords (sender response)
(when (and (string= response "PRIVMSG")
rcirc-fill-column)
(t fill-column))
;; make sure ... doesn't cause line wrapping
- 3)))
+ 3)))
(fill-region (point) (point-max) nil t))))
\f
;;; handlers
(member message
(list
(format "You are now identified for \C-b%s\C-b." rcirc-nick)
+ (format "You are successfully identified as \C-b%s\C-b." rcirc-nick)
"Password accepted - you are now recognized."
)))
(and ;; quakenet
(setq rcirc-topic (caddr args)))))
(defun rcirc-handler-333 (process sender args text)
- "Not in rfc1459.txt"
+ "333 says who set the topic and when.
+Not in rfc1459.txt"
(let ((buffer (or (rcirc-get-buffer process (cadr args))
(rcirc-get-temp-buffer-create process (cadr args)))))
(with-current-buffer buffer
;; quakenet authentication doesn't rely on the user's nickname.
;; the variable `nick' here represents the Q account name.
(when (eq method 'quakenet)
- (rcirc-send-privmsg
+ (rcirc-send-privmsg
process
"Q@CServe.quakenet.org"
(format "AUTH %s %s" nick (car args))))))))))