summaryrefslogtreecommitdiff
path: root/jabber-muc-nick-completion.el
diff options
context:
space:
mode:
Diffstat (limited to 'jabber-muc-nick-completion.el')
-rw-r--r--jabber-muc-nick-completion.el188
1 files changed, 188 insertions, 0 deletions
diff --git a/jabber-muc-nick-completion.el b/jabber-muc-nick-completion.el
new file mode 100644
index 0000000..78ff46d
--- /dev/null
+++ b/jabber-muc-nick-completion.el
@@ -0,0 +1,188 @@
+;;; jabber-muc-nick-completion.el --- Add nick completion abilyty to emacs-jabber
+
+;; Copyright (C) 2008 - Terechkov Evgenii - evg@altlinux.org
+;; Copyright (C) 2007, 2008, 2010 - Kirill A. Korinskiy - catap@catap.ru
+;; Copyright (C) 2007 - Serguei Jidkov - jsv@e-mail.ru
+
+;; This file is a part of jabber.el.
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+;;; User customizations here:
+(defcustom jabber-muc-completion-delimiter ": "
+ "String to add to end of completion line."
+ :type 'string
+ :group 'jabber-chat)
+
+(defcustom jabber-muc-looks-personaling-symbols '("," ":" ">")
+ "Symbols for personaling messages"
+ :type '(repeat string)
+ :group 'jabber-chat)
+
+(defcustom jabber-muc-personal-message-bonus (* 60 20)
+ "Bonus for personal message, in seconds."
+ :type 'integer
+ :group 'jabber-chat)
+
+(defcustom jabber-muc-all-string "all"
+ "String meaning all conference members (to insert in completion). Note that \":\" or alike not needed (it appended in other string)"
+ :type 'string
+ :group 'jabber-chat)
+
+;;; History:
+;;
+
+;;; Code:
+
+(require 'cl)
+(require 'jabber-muc)
+(require 'hippie-exp)
+
+(defvar *jabber-muc-participant-last-speaking* nil
+ "Global alist in form (group . ((member . time-of-last-speaking) ...) ...).")
+
+(defun jabber-my-nick (&optional group)
+ "Return my jabber nick in GROUP."
+ (let ((room (or group jabber-group)))
+ (cdr (or (assoc room *jabber-active-groupchats*)
+ (assoc room jabber-muc-default-nicknames)))
+ ))
+
+;;;###autoload
+(defun jabber-muc-looks-like-personal-p (message &optional group)
+ "Return non-nil if jabber MESSAGE is addresed to me.
+Optional argument GROUP to look."
+ (if message (string-match (concat
+ "^"
+ (jabber-my-nick group)
+ (regexp-opt jabber-muc-looks-personaling-symbols))
+ message)
+ nil))
+
+(defun jabber-muc-nicknames ()
+ "List of conference participants, excluding self, or nil if we not in conference."
+ (delete-if '(lambda (nick)
+ (string= nick (jabber-my-nick)))
+ (append (mapcar 'car (cdr (assoc jabber-group jabber-muc-participants))) (list jabber-muc-all-string))))
+
+(defun jabber-muc-participant-update-activity (group nick time)
+ "Updates NICK's time of last speaking in GROUP to TIME."
+ (let* ((room (assoc group *jabber-muc-participant-last-speaking*))
+ (room-activity (cdr room))
+ (entry (assoc nick room-activity))
+ (old-time (or (cdr entry) 0)))
+ (when (> time old-time)
+ ;; don't use put-alist for speed
+ (progn
+ (if entry (setcdr entry time)
+ (setq room-activity
+ (cons (cons nick time) room-activity)))
+ (if room (setcdr room room-activity)
+ (setq *jabber-muc-participant-last-speaking*
+ (cons (cons group room-activity)
+ *jabber-muc-participant-last-speaking*)))))))
+
+(defun jabber-muc-track-message-time (nick group buffer text &optional title)
+ "Tracks time of NICK's last speaking in GROUP."
+ (when nick
+ (let ((time (float-time)))
+ (jabber-muc-participant-update-activity
+ group
+ nick
+ (if (jabber-muc-looks-like-personal-p text group)
+ (+ time jabber-muc-personal-message-bonus)
+ time)))))
+
+(defun jabber-sort-nicks (nicks group)
+ "Return list of NICKS in GROUP, sorted."
+ (let ((times (cdr (assoc group *jabber-muc-participant-last-speaking*))))
+ (flet ((fetch-time (nick) (or (assoc nick times) (cons nick 0)))
+ (cmp (nt1 nt2)
+ (let ((t1 (cdr nt1))
+ (t2 (cdr nt2)))
+ (if (and (zerop t1) (zerop t2))
+ (string<
+ (car nt1)
+ (car nt2))
+ (> t1 t2)))))
+ (mapcar 'car (sort (mapcar 'fetch-time nicks)
+ 'cmp)))))
+
+(defun jabber-muc-beginning-of-line ()
+ "Return position of line begining."
+ (save-excursion
+ (if (looking-back jabber-muc-completion-delimiter)
+ (backward-char (+ (length jabber-muc-completion-delimiter) 1)))
+ (skip-syntax-backward "^-")
+ (point)))
+
+;;; One big hack:
+(defun jabber-muc-completion-delete-last-tried ()
+ "Delete last tried competion variand from line."
+ (let ((last-tried (car he-tried-table)))
+ (when last-tried
+ (goto-char he-string-beg)
+ (delete-char (length last-tried))
+ (ignore-errors (delete-char (length jabber-muc-completion-delimiter)))
+ )))
+
+(defun try-expand-jabber-muc (old)
+ "Try to expand target nick in MUC according to last speaking time.
+OLD is last tried nickname."
+ (unless jabber-chatting-with
+ (unless old
+ (let ((nicknames (jabber-muc-nicknames)))
+ (he-init-string (jabber-muc-beginning-of-line) (point))
+ (setq he-expand-list (jabber-sort-nicks (all-completions he-search-string (mapcar 'list nicknames)) jabber-group))))
+
+ (setq he-expand-list
+ (delete-if '(lambda (x)
+ (he-string-member x he-tried-table))
+ he-expand-list))
+ (if (null he-expand-list)
+ (progn
+ (when old
+ ;; here and later : its hack to workaround
+ ;; he-substitute-string work which cant substitute empty
+ ;; lines
+ (if (string= he-search-string "")
+ (jabber-muc-completion-delete-last-tried)
+ (he-reset-string)))
+ ())
+ (let ((subst (if (eq (line-beginning-position) (jabber-muc-beginning-of-line))
+ (concat (car he-expand-list) jabber-muc-completion-delimiter)
+ (car he-expand-list))))
+ (if (not (string= he-search-string ""))
+ (he-substitute-string subst)
+ (jabber-muc-completion-delete-last-tried)
+ (progn
+ (insert subst)
+ (if (looking-back (concat "^" (regexp-quote (car he-expand-list))))
+ (unless (looking-back (concat "^" (regexp-quote (car he-expand-list)) jabber-muc-completion-delimiter))
+ (insert jabber-muc-completion-delimiter)))
+ )
+ ))
+ (setq he-tried-table (cons (car he-expand-list) (cdr he-tried-table)))
+ (setq he-expand-list (cdr he-expand-list))
+ t)))
+
+(add-hook 'jabber-muc-hooks 'jabber-muc-track-message-time)
+(fset 'jabber-muc-completion (make-hippie-expand-function '(try-expand-jabber-muc)))
+(define-key jabber-chat-mode-map [?\t] 'jabber-muc-completion)
+
+(provide 'jabber-muc-nick-completion)
+
+;; arch-tag: 2a81ac72-d261-11dc-be91-000a95c2fcd0
+;;; jabber-muc-completion.el ends here