1 ;;; jabber-muc-nick-completion.el --- Add nick completion abilyty to emacs-jabber
3 ;; Copyright (C) 2008 - Terechkov Evgenii - evg@altlinux.org
4 ;; Copyright (C) 2007, 2008 - Kirill A. Korinskiy - catap@catap.ru
5 ;; Copyright (C) 2007 - Serguei Jidkov - jsv@e-mail.ru
7 ;; This file is a part of jabber.el.
9 ;; This program is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2 of the License, or
12 ;; (at your option) any later version.
14 ;; This program is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program; if not, write to the Free Software
21 ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 ;;; User customizations here:
24 (defcustom jabber-muc-completion-delimiter
": "
25 "String to add to end of completion line."
29 (defcustom jabber-muc-looks-personaling-symbols
'("," ":" ">")
30 "Symbols for personaling messages"
31 :type
'(repeat string
)
34 (defcustom jabber-muc-personal-message-bonus
(* 60 20)
35 "Bonus for personal message, in seconds."
39 (defcustom jabber-muc-all-string
"all"
40 "String meaning all conference members (to insert in completion). Note that \":\" or alike not needed (it appended in other string)"
53 (defvar *jabber-muc-participant-last-speaking
* nil
54 "Global alist in form (group . ((member . time-of-last-speaking) ...) ...).")
56 (defun modify-alist (key val alist
)
57 "Update of ALIST's element (KEY . VAL), possibly destructive."
58 (let ((entry (assoc key alist
)))
61 (setf (cdr entry
) val
)
64 (defun jabber-my-nick (&optional group
)
65 "Return my jabber nick in GROUP."
66 (let ((room (or group jabber-group
)))
67 (cdr (or (assoc room
*jabber-active-groupchats
*)
68 (assoc room jabber-muc-default-nicknames
)))
72 (defun jabber-muc-looks-like-personal-p (message &optional group
)
73 "Return non-nil if jabber MESSAGE is addresed to me.
74 Optional argument GROUP to look."
75 (if message
(string-match (concat
77 (jabber-my-nick group
)
78 (regexp-opt jabber-muc-looks-personaling-symbols
))
82 (defun jabber-muc-nicknames ()
83 "List of conference participants, excluding self, or nil if we not in conference."
84 (delete-if '(lambda (nick)
85 (string= nick
(jabber-my-nick)))
86 (append (mapcar 'car
(cdr (assoc jabber-group jabber-muc-participants
))) (list jabber-muc-all-string
))))
88 ;; TODO: optimize this function
89 (defun jabber-muc-participant-update-activity (group nick time
)
90 "Updates NICK's time of last speaking in GROUP to TIME."
91 (let* ((room-activity (cdr (assoc group
*jabber-muc-participant-last-speaking
*)))
92 (old-time (or (cdr (assoc nick room-activity
)) 0)))
93 (when (> time old-time
)
94 (setq *jabber-muc-participant-last-speaking
*
95 (modify-alist group
(modify-alist nick time room-activity
)
96 *jabber-muc-participant-last-speaking
*)))))
98 (defun jabber-muc-track-message-time (nick group buffer text proposed-alert
)
99 "Tracks time of NICK's last speaking in GROUP."
101 (let ((time (float-time)))
102 (jabber-muc-participant-update-activity
105 (if (jabber-muc-looks-like-personal-p text group
)
106 (+ time jabber-muc-personal-message-bonus
)
109 (defun jabber-sort-nicks (nicks group
)
110 "Return list of NICKS in GROUP, sorted."
111 (let ((times (cdr (assoc group
*jabber-muc-participant-last-speaking
*))))
112 (flet ((fetch-time (nick) (or (assoc nick times
) (cons nick
0)))
116 (if (and (zerop t1
) (zerop t2
))
121 (mapcar 'car
(sort (mapcar 'fetch-time nicks
)
124 (defun jabber-muc-beginning-of-line ()
125 "Return position of line begining."
127 (if (looking-back jabber-muc-completion-delimiter
)
128 (backward-char (+ (length jabber-muc-completion-delimiter
) 1)))
129 (skip-syntax-backward "^-")
133 (defun jabber-muc-completion-delete-last-tried ()
134 "Delete last tried competion variand from line."
135 (let ((last-tried (car he-tried-table
)))
137 (goto-char he-string-beg
)
138 (delete-char (length last-tried
))
139 (ignore-errors (delete-char (length jabber-muc-completion-delimiter
)))
142 (defun try-expand-jabber-muc (old)
143 "Try to expand target nick in MUC according to last speaking time.
144 OLD is last tried nickname."
145 (unless jabber-chatting-with
147 (let ((nicknames (jabber-muc-nicknames)))
148 (he-init-string (jabber-muc-beginning-of-line) (point))
149 (setq he-expand-list
(jabber-sort-nicks (all-completions he-search-string
(mapcar 'list nicknames
)) jabber-group
))))
152 (delete-if '(lambda (x)
153 (he-string-member x he-tried-table
))
155 (if (null he-expand-list
)
158 ;; here and later : its hack to workaround
159 ;; he-substitute-string work which cant substitute empty
161 (if (string= he-search-string
"")
162 (jabber-muc-completion-delete-last-tried)
165 (let ((subst (if (eq (line-beginning-position) (jabber-muc-beginning-of-line))
166 (concat (car he-expand-list
) jabber-muc-completion-delimiter
)
167 (car he-expand-list
))))
168 (if (not (string= he-search-string
""))
169 (he-substitute-string subst
)
170 (jabber-muc-completion-delete-last-tried)
173 (if (looking-back (concat "^" (regexp-quote (car he-expand-list
))))
174 (unless (looking-back (concat "^" (regexp-quote (car he-expand-list
)) jabber-muc-completion-delimiter
))
175 (insert jabber-muc-completion-delimiter
)))
178 (setq he-tried-table
(cons (car he-expand-list
) (cdr he-tried-table
)))
179 (setq he-expand-list
(cdr he-expand-list
))
182 (add-hook 'jabber-muc-hooks
'jabber-muc-track-message-time
)
183 (fset 'jabber-muc-completion
(make-hippie-expand-function '(try-expand-jabber-muc)))
184 (define-key jabber-chat-mode-map
[?
\t] 'jabber-muc-completion
)
186 (provide 'jabber-muc-nick-completion
)
188 ;; arch-tag: 2a81ac72-d261-11dc-be91-000a95c2fcd0
189 ;;; jabber-muc-completion.el ends here