diff options
Diffstat (limited to 'lisp/net/rcirc.el')
-rw-r--r-- | lisp/net/rcirc.el | 201 |
1 files changed, 136 insertions, 65 deletions
diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el index b4f97466baa..964f9c44ccc 100644 --- a/lisp/net/rcirc.el +++ b/lisp/net/rcirc.el @@ -1,9 +1,11 @@ ;;; rcirc.el --- default, simple IRC client. -;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 +;; Free Software Foundation, Inc. -;; Author: Ryan Yeske -;; URL: http://www.nongnu.org/rcirc +;; Author: Ryan Yeske <rcyeske@gmail.com> +;; Maintainers: Ryan Yeske <rcyeske@gmail.com>, +;; Deniz Dogan <deniz.a.m.dogan@gmail.com> ;; Keywords: comm ;; This file is part of GNU Emacs. @@ -114,15 +116,15 @@ connected to automatically." :type 'string :group 'rcirc) -(defcustom rcirc-default-user-name (user-login-name) +(defcustom rcirc-default-user-name "user" "Your user name sent to the server when connecting." + :version "24.1" ; changed default :type 'string :group 'rcirc) -(defcustom rcirc-default-full-name (if (string= (user-full-name) "") - rcirc-default-user-name - (user-full-name)) +(defcustom rcirc-default-full-name "unknown" "The full name sent to the server when connecting." + :version "24.1" ; changed default :type 'string :group 'rcirc) @@ -375,6 +377,9 @@ and the cdr part is used for encoding." (defvar rcirc-nick-name-history nil "History variable for \\[rcirc] call.") +(defvar rcirc-user-name-history nil + "History variable for \\[rcirc] call.") + ;;;###autoload (defun rcirc (arg) "Connect to all servers in `rcirc-server-alist'. @@ -399,8 +404,12 @@ If ARG is non-nil, instead prompt for connection parameters." (or (plist-get server-plist :nick) rcirc-default-nick) 'rcirc-nick-name-history)) - (password (read-passwd "IRC Password: " - (plist-get server-plist 'password))) + (user-name (read-string "IRC Username: " + (or (plist-get server-plist :user-name) + rcirc-default-user-name) + 'rcirc-user-name-history)) + (password (read-passwd "IRC Password: " nil + (plist-get server-plist :password))) (channels (split-string (read-string "IRC Channels: " (mapconcat 'identity @@ -408,11 +417,7 @@ If ARG is non-nil, instead prompt for connection parameters." :channels) " ")) "[, ]+" t))) - - (when (= 0 (length password)) - (setq password nil)) - - (rcirc-connect server port nick rcirc-default-user-name + (rcirc-connect server port nick user-name rcirc-default-full-name channels password)) ;; connect to servers in `rcirc-server-alist' @@ -466,8 +471,8 @@ If ARG is non-nil, instead prompt for connection parameters." (defvar rcirc-process nil) ;;;###autoload -(defun rcirc-connect (server &optional port nick user-name full-name - startup-channels password) +(defun rcirc-connect (server &optional port nick user-name + full-name startup-channels password) (save-excursion (message "Connecting to %s..." server) (let* ((inhibit-eol-conversion) @@ -520,8 +525,7 @@ If ARG is non-nil, instead prompt for connection parameters." (rcirc-send-string process (concat "PASS " password))) (rcirc-send-string process (concat "NICK " nick)) (rcirc-send-string process (concat "USER " user-name - " hostname servername :" - full-name)) + " 0 * :" full-name)) ;; setup ping timer if necessary (unless rcirc-keepalive-timer @@ -771,42 +775,64 @@ If SILENT is non-nil, do not print the message in any irc buffer." (setq rcirc-input-ring-index (1- rcirc-input-ring-index)) (insert (rcirc-prev-input-string -1)))) -(defvar rcirc-nick-completions nil) -(defvar rcirc-nick-completion-start-offset nil) - -(defun rcirc-complete-nick () - "Cycle through nick completions from list of nicks in channel." +(defvar rcirc-server-commands + '("/admin" "/away" "/connect" "/die" "/error" "/info" + "/invite" "/ison" "/join" "/kick" "/kill" "/links" + "/list" "/lusers" "/mode" "/motd" "/names" "/nick" + "/notice" "/oper" "/part" "/pass" "/ping" "/pong" + "/privmsg" "/quit" "/rehash" "/restart" "/service" "/servlist" + "/server" "/squery" "/squit" "/stats" "/summon" "/time" + "/topic" "/trace" "/user" "/userhost" "/users" "/version" + "/wallops" "/who" "/whois" "/whowas") + "A list of user commands by IRC server. +The value defaults to RFCs 1459 and 2812.") + +;; /me and /ctcp are not defined by `defun-rcirc-command'. +(defvar rcirc-client-commands '("/me" "/ctcp") + "A list of user commands defined by IRC client rcirc. +The list is updated automatically by `defun-rcirc-command'.") + +(defun rcirc-completion-at-point () + "Function used for `completion-at-point-functions' in `rcirc-mode'." + (let* ((beg (save-excursion + (if (re-search-backward " " rcirc-prompt-end-marker t) + (1+ (point)) + rcirc-prompt-end-marker))) + (table (if (and (= beg rcirc-prompt-end-marker) + (eq (char-after beg) ?/)) + (delete-dups + (nconc + (sort (copy-sequence rcirc-client-commands) 'string-lessp) + (sort (copy-sequence rcirc-server-commands) 'string-lessp))) + (rcirc-channel-nicks (rcirc-buffer-process) rcirc-target)))) + (list beg (point) table))) + +(defvar rcirc-completions nil) +(defvar rcirc-completion-start nil) + +(defun rcirc-complete () + "Cycle through completions from list of nicks in channel or IRC commands. +IRC command completion is performed only if '/' is the first input char." (interactive) (if (eq last-command this-command) - (setq rcirc-nick-completions - (append (cdr rcirc-nick-completions) - (list (car rcirc-nick-completions)))) - (setq rcirc-nick-completion-start-offset - (- (save-excursion - (if (re-search-backward " " rcirc-prompt-end-marker t) - (1+ (point)) - rcirc-prompt-end-marker)) - rcirc-prompt-end-marker)) - (setq rcirc-nick-completions - (let ((completion-ignore-case t)) - (all-completions - (buffer-substring - (+ rcirc-prompt-end-marker - rcirc-nick-completion-start-offset) - (point)) - (mapcar (lambda (x) (cons x nil)) - (rcirc-channel-nicks (rcirc-buffer-process) - rcirc-target)))))) - (let ((completion (car rcirc-nick-completions))) + (setq rcirc-completions + (append (cdr rcirc-completions) (list (car rcirc-completions)))) + (let ((completion-ignore-case t) + (table (rcirc-completion-at-point))) + (setq rcirc-completion-start (car table)) + (setq rcirc-completions + (all-completions (buffer-substring rcirc-completion-start + (cadr table)) + (nth 2 table))))) + (let ((completion (car rcirc-completions))) (when completion - (delete-region (+ rcirc-prompt-end-marker - rcirc-nick-completion-start-offset) - (point)) - (insert (concat completion - (if (= (+ rcirc-prompt-end-marker - rcirc-nick-completion-start-offset) - rcirc-prompt-end-marker) - ": ")))))) + (delete-region rcirc-completion-start (point)) + (insert + (concat completion + (cond + ((= (aref completion 0) ?/) " ") + ((= rcirc-completion-start rcirc-prompt-end-marker) ": ") + (t ""))))))) (defun set-rcirc-decode-coding-system (coding-system) "Set the decode coding system used in this channel." @@ -824,7 +850,7 @@ If SILENT is non-nil, do not print the message in any irc buffer." (define-key rcirc-mode-map (kbd "RET") 'rcirc-send-input) (define-key rcirc-mode-map (kbd "M-p") 'rcirc-insert-prev-input) (define-key rcirc-mode-map (kbd "M-n") 'rcirc-insert-next-input) -(define-key rcirc-mode-map (kbd "TAB") 'rcirc-complete-nick) +(define-key rcirc-mode-map (kbd "TAB") 'rcirc-complete) (define-key rcirc-mode-map (kbd "C-c C-b") 'rcirc-browse-url) (define-key rcirc-mode-map (kbd "C-c C-c") 'rcirc-edit-multiline) (define-key rcirc-mode-map (kbd "C-c C-j") 'rcirc-cmd-join) @@ -870,6 +896,7 @@ Each element looks like (FILENAME . TEXT).") This number is independent of the number of lines in the buffer.") (defun rcirc-mode (process target) + ;; FIXME: Use define-derived-mode. "Major mode for IRC channel buffers. \\{rcirc-mode-map}" @@ -945,7 +972,10 @@ This number is independent of the number of lines in the buffer.") rcirc-buffer-alist)))) (rcirc-update-short-buffer-names)) - (run-hooks 'rcirc-mode-hook)) + (add-hook 'completion-at-point-functions + 'rcirc-completion-at-point nil 'local) + + (run-mode-hooks 'rcirc-mode-hook)) (defun rcirc-update-prompt (&optional all) "Reset the prompt string in the current buffer. @@ -1339,6 +1369,12 @@ Logfiles are kept in `rcirc-log-directory'." :type 'integer :group 'rcirc) +(defcustom rcirc-log-process-buffers nil + "Non-nil if rcirc process buffers should be logged to disk." + :group 'rcirc + :type 'boolean + :version "24.1") + (defun rcirc-last-quit-line (process nick target) "Return the line number where NICK left TARGET. Returns nil if the information is not recorded." @@ -1504,14 +1540,21 @@ record activity." (when (not (rcirc-channel-p rcirc-target)) 'nick))) - (when rcirc-log-flag + (when (and rcirc-log-flag + (or target + rcirc-log-process-buffers)) (rcirc-log process sender response target text)) (sit-for 0) ; displayed text before hook (run-hook-with-args 'rcirc-print-hooks process sender response target text))))) -(defcustom rcirc-log-filename-function 'rcirc-generate-new-buffer-name +(defun rcirc-generate-log-filename (process target) + (if target + (rcirc-generate-new-buffer-name process target) + (process-name process))) + +(defcustom rcirc-log-filename-function 'rcirc-generate-log-filename "A function to generate the filename used by rcirc's logging facility. It is called with two arguments, PROCESS and TARGET (see @@ -1648,6 +1691,31 @@ if NICK is also on `rcirc-ignore-list-automatic'." rcirc-ignore-list (delete nick rcirc-ignore-list)))) +(defun rcirc-nickname< (s1 s2) + "Return t if IRC nickname S1 is less than S2, and nil otherwise. +Operator nicknames (@) are considered less than voiced +nicknames (+). Any other nicknames are greater than voiced +nicknames. The comparison is case-insensitive." + (setq s1 (downcase s1) + s2 (downcase s2)) + (let* ((s1-op (eq ?@ (string-to-char s1))) + (s2-op (eq ?@ (string-to-char s2)))) + (if s1-op + (if s2-op + (string< (substring s1 1) (substring s2 1)) + t) + (if s2-op + nil + (string< s1 s2))))) + +(defun rcirc-sort-nicknames-join (input sep) + "Return a string of sorted nicknames. +INPUT is a string containing nicknames separated by SEP. +This function does not alter the INPUT string." + (let* ((parts (split-string input sep t)) + (sorted (sort parts 'rcirc-nickname<))) + (mapconcat 'identity sorted sep))) + ;;; activity tracking (defvar rcirc-track-minor-mode-map (make-sparse-keymap) "Keymap for rcirc track minor mode.") @@ -1963,16 +2031,18 @@ activity. Only run if the buffer is not visible and ;; containing the text following the /cmd. (defmacro defun-rcirc-command (command argument docstring interactive-form - &rest body) + &rest body) "Define a command." - `(defun ,(intern (concat "rcirc-cmd-" (symbol-name command))) - (,@argument &optional process target) - ,(concat docstring "\n\nNote: If PROCESS or TARGET are nil, the values given" - "\nby `rcirc-buffer-process' and `rcirc-target' will be used.") - ,interactive-form - (let ((process (or process (rcirc-buffer-process))) - (target (or target rcirc-target))) - ,@body))) + `(progn + (add-to-list 'rcirc-client-commands ,(concat "/" (symbol-name command))) + (defun ,(intern (concat "rcirc-cmd-" (symbol-name command))) + (,@argument &optional process target) + ,(concat docstring "\n\nNote: If PROCESS or TARGET are nil, the values given" + "\nby `rcirc-buffer-process' and `rcirc-target' will be used.") + ,interactive-form + (let ((process (or process (rcirc-buffer-process))) + (target (or target rcirc-target))) + ,@body)))) (defun-rcirc-command msg (message) "Send private MESSAGE to TARGET." @@ -2561,7 +2631,8 @@ keywords when no KEYWORD is given." (buffer (rcirc-get-temp-buffer-create process channel))) (with-current-buffer buffer (rcirc-print process sender "NAMES" channel - (buffer-substring (point-min) (point-max)))) + (let ((content (buffer-substring (point-min) (point-max)))) + (rcirc-sort-nicknames-join content " ")))) (kill-buffer buffer))) (defun rcirc-handler-433 (process sender args text) |