unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#17755: 24.3; ERC user mode support
@ 2014-06-11 10:34 kelvin.white77
  2014-06-11 11:45 ` Kelvin White
  2014-10-02 19:31 ` Paul Eggert
  0 siblings, 2 replies; 8+ messages in thread
From: kelvin.white77 @ 2014-06-11 10:34 UTC (permalink / raw)
  To: 17755

ERC lacks support for user modes other than +o/+v (OP/VOICE), making it
difficult for IRC users to know what modes any user may have. Currently
user nicknames do not include any mode prefix by default. By setting
`erc-format-nick-function' to erc-format-@nick, a user can enable prefixes
@, or +, added to user nicknames. While that may be a sane default, most IRC
servers support more user modes. ERC already parses the prefixes sent in
the server parameters, and adds available modes to a list, but they are
never utilized.


In GNU Emacs 24.3.1 (x86_64-pc-linux-gnu)
 of 2013-07-26 on roseapple, modified by Debian
System Description:	Ubuntu 13.10

Configured using:
 `configure '--build' 'x86_64-linux-gnu' '--build' 'x86_64-linux-gnu'
 '--prefix=/usr' '--sharedstatedir=/var/lib' '--libexecdir=/usr/lib'
 '--localstatedir=/var/lib' '--infodir=/usr/share/info'
 '--mandir=/usr/share/man' '--with-pop=yes'
 '--enable-locallisppath=/etc/emacs24:/etc/emacs:/usr/local/share/emacs/24.3/site-lisp:/usr/local/share/emacs/site-lisp:/usr/share/emacs/24.3/site-lisp:/usr/share/emacs/site-lisp'
 '--with-crt-dir=/usr/lib/x86_64-linux-gnu' '--with-x=no'
 '--without-gconf' 'build_alias=x86_64-linux-gnu' 'CFLAGS=-g -O2
 -fstack-protector --param=ssp-buffer-size=4 -Wformat
 -Werror=format-security -Wall' 'LDFLAGS=-Wl,-Bsymbolic-functions
 -Wl,-z,relro' 'CPPFLAGS=-D_FORTIFY_SOURCE=2''

Important settings:
  value of $LC_CTYPE: en_US.UTF-8
  value of $LANG: en_US.UTF-8
  locale-coding-system: utf-8-unix
  default enable-multibyte-characters: t

Major mode: Lisp Interaction

Minor modes in effect:
  paredit-mode: t
  erc-services-mode: t
  ido-everywhere: t
  recentf-mode: t
  show-paren-mode: t
  erc-list-mode: t
  erc-menu-mode: t
  erc-autojoin-mode: t
  erc-ring-mode: t
  erc-networks-mode: t
  erc-pcomplete-mode: t
  erc-track-mode: t
  erc-track-minor-mode: t
  erc-match-mode: t
  erc-button-mode: t
  erc-fill-mode: t
  erc-stamp-mode: t
  erc-netsplit-mode: t
  erc-irccontrols-mode: t
  erc-noncommands-mode: t
  erc-move-to-prompt-mode: t
  erc-readonly-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  line-number-mode: t
  transient-mark-mode: t

Recent input:
A C-x C-s C-x ESC O C C-x ESC O D C-x ESC O C C-x ESC 
O D C-x ESC O C h a h a RET n i c e RET C-x ESC O D 
C-x ESC O C C-x ESC O D ESC O B ESC O B C-x C-s C-x 
f e r c . e l RET ESC O A ESC O A C-a C-k C-y \ RET 
DEL RET RET C-y ESC O A ESC O A ESC O D ESC O D ESC 
O D ESC O D ESC O D ESC O D ESC O D m y - C-x C-s ESC 
O A ESC O A ESC O A ESC O A ESC O A ESC O A ESC O A 
ESC O A ESC O A ESC O A ESC O A ESC O A ESC O A ESC 
O A ESC O A ESC O A ESC O A ESC O A ESC O A ESC O A 
ESC O A TAB ESC O B TAB ESC O B TAB ESC O B TAB ESC 
O B TAB ESC O B TAB ESC O A TAB ESC O A TAB ESC O A 
TAB ESC O A C-a TAB ESC O D C-@ C-a DEL ESC O B TAB 
ESC O D C-@ C-a DEL ESC O B TAB ESC O D C-@ C-a DEL 
ESC O B TAB ESC O D C-@ C-a DEL C-x C-s C-x C-c ESC 
[ > 0 ; 9 5 ; c C-x C-c ESC [ > 0 ; 9 5 ; c C-x C-c 
ESC [ > 0 ; 9 5 ; c ESC x r e p o r t - e m a c s - 
b u g RET

Recent messages:
Wrote /home/l3thal/projects/emacs-dev/lisp/erc/erc.el
Mark set [4 times]
Saving file /home/l3thal/projects/emacs-dev/lisp/erc/erc.el...
Wrote /home/l3thal/projects/emacs-dev/lisp/erc/erc.el
(No files need saving)
When done with this frame, type C-x 5 0
(No files need saving)
When done with this frame, type C-x 5 0
(No files need saving)
When done with this frame, type C-x 5 0

Load-path shadows:
/usr/share/emacs/24.3/site-lisp/debian-startup hides /usr/share/emacs/site-lisp/debian-startup
/usr/share/emacs24/site-lisp/dictionaries-common/flyspell hides /usr/share/emacs/24.3/lisp/textmodes/flyspell
/usr/share/emacs24/site-lisp/dictionaries-common/ispell hides /usr/share/emacs/24.3/lisp/textmodes/ispell

Features:
(shadow sort mail-extr emacsbug message rfc822 mml mml-sec mm-decode
mm-bodies mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader
sendmail rfc2047 rfc2045 ietf-drums mail-utils tabify misearch
multi-isearch vc-git gnutls network-stream starttls tls server
magit-autoloads info git-rebase-mode-autoloads git-commit-mode-autoloads
finder-inf package awesome untabify-file paredit erc-init erc-services
erc-names ido recentf tree-widget paren erc-menu erc-join erc-ring
erc-networks erc-pcomplete pcomplete erc-track erc-match erc-button
wid-edit erc-fill erc-stamp erc-netsplit erc-goodies erc erc-backend
erc-compat format-spec auth-source eieio gnus-util time-date mm-util
mail-prsvr password-cache cus-start cus-load warnings slime-fancy
slime-trace-dialog slime-fontifying-fu slime-package-fu slime-references
slime-compiler-notes-tree slime-scratch slime-presentations bridge
slime-fuzzy slime-fancy-trace slime-fancy-inspector slime-c-p-c
slime-editing-commands slime-autodoc advice advice-preload eldoc
slime-repl slime-parse slime byte-opt bytecomp byte-compile cconv
derived help-fns edmacro kmacro gud compile tool-bar apropos etags
arc-mode archive-mode noutline outline easy-mmode easymenu pp comint
regexp-opt ansi-color ring hyperspec cl-macs gv thingatpt browse-url cl
cl-lib slime-autoloads ediff-hook vc-hooks lisp-float-type
tabulated-list newcomment lisp-mode register page menu-bar rfn-eshadow
timer select mouse jit-lock font-lock syntax facemenu font-core frame
cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
korean japanese hebrew greek romanian slovak czech european ethiopic
indian cyrillic chinese case-table epa-hook jka-cmpr-hook help simple
abbrev minibuffer loaddefs button faces cus-face macroexp files
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget hashtable-print-readable backquote make-network-process
dbusbind multi-tty emacs)





^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#17755: 24.3; ERC user mode support
  2014-06-11 10:34 bug#17755: 24.3; ERC user mode support kelvin.white77
@ 2014-06-11 11:45 ` Kelvin White
  2014-06-17 16:03   ` Stefan Monnier
  2014-10-02 19:31 ` Paul Eggert
  1 sibling, 1 reply; 8+ messages in thread
From: Kelvin White @ 2014-06-11 11:45 UTC (permalink / raw)
  To: 17755


[-- Attachment #1.1: Type: text/plain, Size: 6183 bytes --]

Here is the patch to add this feature


On Wed, Jun 11, 2014 at 6:34 AM, <kelvin.white77@gmail.com> wrote:

> ERC lacks support for user modes other than +o/+v (OP/VOICE), making it
> difficult for IRC users to know what modes any user may have. Currently
> user nicknames do not include any mode prefix by default. By setting
> `erc-format-nick-function' to erc-format-@nick, a user can enable prefixes
> @, or +, added to user nicknames. While that may be a sane default, most
> IRC
> servers support more user modes. ERC already parses the prefixes sent in
> the server parameters, and adds available modes to a list, but they are
> never utilized.
>
>
> In GNU Emacs 24.3.1 (x86_64-pc-linux-gnu)
>  of 2013-07-26 on roseapple, modified by Debian
> System Description:     Ubuntu 13.10
>
> Configured using:
>  `configure '--build' 'x86_64-linux-gnu' '--build' 'x86_64-linux-gnu'
>  '--prefix=/usr' '--sharedstatedir=/var/lib' '--libexecdir=/usr/lib'
>  '--localstatedir=/var/lib' '--infodir=/usr/share/info'
>  '--mandir=/usr/share/man' '--with-pop=yes'
>
>  '--enable-locallisppath=/etc/emacs24:/etc/emacs:/usr/local/share/emacs/24.3/site-lisp:/usr/local/share/emacs/site-lisp:/usr/share/emacs/24.3/site-lisp:/usr/share/emacs/site-lisp'
>  '--with-crt-dir=/usr/lib/x86_64-linux-gnu' '--with-x=no'
>  '--without-gconf' 'build_alias=x86_64-linux-gnu' 'CFLAGS=-g -O2
>  -fstack-protector --param=ssp-buffer-size=4 -Wformat
>  -Werror=format-security -Wall' 'LDFLAGS=-Wl,-Bsymbolic-functions
>  -Wl,-z,relro' 'CPPFLAGS=-D_FORTIFY_SOURCE=2''
>
> Important settings:
>   value of $LC_CTYPE: en_US.UTF-8
>   value of $LANG: en_US.UTF-8
>   locale-coding-system: utf-8-unix
>   default enable-multibyte-characters: t
>
> Major mode: Lisp Interaction
>
> Minor modes in effect:
>   paredit-mode: t
>   erc-services-mode: t
>   ido-everywhere: t
>   recentf-mode: t
>   show-paren-mode: t
>   erc-list-mode: t
>   erc-menu-mode: t
>   erc-autojoin-mode: t
>   erc-ring-mode: t
>   erc-networks-mode: t
>   erc-pcomplete-mode: t
>   erc-track-mode: t
>   erc-track-minor-mode: t
>   erc-match-mode: t
>   erc-button-mode: t
>   erc-fill-mode: t
>   erc-stamp-mode: t
>   erc-netsplit-mode: t
>   erc-irccontrols-mode: t
>   erc-noncommands-mode: t
>   erc-move-to-prompt-mode: t
>   erc-readonly-mode: t
>   file-name-shadow-mode: t
>   global-font-lock-mode: t
>   font-lock-mode: t
>   auto-composition-mode: t
>   auto-encryption-mode: t
>   auto-compression-mode: t
>   line-number-mode: t
>   transient-mark-mode: t
>
> Recent input:
> A C-x C-s C-x ESC O C C-x ESC O D C-x ESC O C C-x ESC
> O D C-x ESC O C h a h a RET n i c e RET C-x ESC O D
> C-x ESC O C C-x ESC O D ESC O B ESC O B C-x C-s C-x
> f e r c . e l RET ESC O A ESC O A C-a C-k C-y \ RET
> DEL RET RET C-y ESC O A ESC O A ESC O D ESC O D ESC
> O D ESC O D ESC O D ESC O D ESC O D m y - C-x C-s ESC
> O A ESC O A ESC O A ESC O A ESC O A ESC O A ESC O A
> ESC O A ESC O A ESC O A ESC O A ESC O A ESC O A ESC
> O A ESC O A ESC O A ESC O A ESC O A ESC O A ESC O A
> ESC O A TAB ESC O B TAB ESC O B TAB ESC O B TAB ESC
> O B TAB ESC O B TAB ESC O A TAB ESC O A TAB ESC O A
> TAB ESC O A C-a TAB ESC O D C-@ C-a DEL ESC O B TAB
> ESC O D C-@ C-a DEL ESC O B TAB ESC O D C-@ C-a DEL
> ESC O B TAB ESC O D C-@ C-a DEL C-x C-s C-x C-c ESC
> [ > 0 ; 9 5 ; c C-x C-c ESC [ > 0 ; 9 5 ; c C-x C-c
> ESC [ > 0 ; 9 5 ; c ESC x r e p o r t - e m a c s -
> b u g RET
>
> Recent messages:
> Wrote /home/l3thal/projects/emacs-dev/lisp/erc/erc.el
> Mark set [4 times]
> Saving file /home/l3thal/projects/emacs-dev/lisp/erc/erc.el...
> Wrote /home/l3thal/projects/emacs-dev/lisp/erc/erc.el
> (No files need saving)
> When done with this frame, type C-x 5 0
> (No files need saving)
> When done with this frame, type C-x 5 0
> (No files need saving)
> When done with this frame, type C-x 5 0
>
> Load-path shadows:
> /usr/share/emacs/24.3/site-lisp/debian-startup hides
> /usr/share/emacs/site-lisp/debian-startup
> /usr/share/emacs24/site-lisp/dictionaries-common/flyspell hides
> /usr/share/emacs/24.3/lisp/textmodes/flyspell
> /usr/share/emacs24/site-lisp/dictionaries-common/ispell hides
> /usr/share/emacs/24.3/lisp/textmodes/ispell
>
> Features:
> (shadow sort mail-extr emacsbug message rfc822 mml mml-sec mm-decode
> mm-bodies mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader
> sendmail rfc2047 rfc2045 ietf-drums mail-utils tabify misearch
> multi-isearch vc-git gnutls network-stream starttls tls server
> magit-autoloads info git-rebase-mode-autoloads git-commit-mode-autoloads
> finder-inf package awesome untabify-file paredit erc-init erc-services
> erc-names ido recentf tree-widget paren erc-menu erc-join erc-ring
> erc-networks erc-pcomplete pcomplete erc-track erc-match erc-button
> wid-edit erc-fill erc-stamp erc-netsplit erc-goodies erc erc-backend
> erc-compat format-spec auth-source eieio gnus-util time-date mm-util
> mail-prsvr password-cache cus-start cus-load warnings slime-fancy
> slime-trace-dialog slime-fontifying-fu slime-package-fu slime-references
> slime-compiler-notes-tree slime-scratch slime-presentations bridge
> slime-fuzzy slime-fancy-trace slime-fancy-inspector slime-c-p-c
> slime-editing-commands slime-autodoc advice advice-preload eldoc
> slime-repl slime-parse slime byte-opt bytecomp byte-compile cconv
> derived help-fns edmacro kmacro gud compile tool-bar apropos etags
> arc-mode archive-mode noutline outline easy-mmode easymenu pp comint
> regexp-opt ansi-color ring hyperspec cl-macs gv thingatpt browse-url cl
> cl-lib slime-autoloads ediff-hook vc-hooks lisp-float-type
> tabulated-list newcomment lisp-mode register page menu-bar rfn-eshadow
> timer select mouse jit-lock font-lock syntax facemenu font-core frame
> cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao
> korean japanese hebrew greek romanian slovak czech european ethiopic
> indian cyrillic chinese case-table epa-hook jka-cmpr-hook help simple
> abbrev minibuffer loaddefs button faces cus-face macroexp files
> text-properties overlay sha1 md5 base64 format env code-pages mule
> custom widget hashtable-print-readable backquote make-network-process
> dbusbind multi-tty emacs)
>

[-- Attachment #1.2: Type: text/html, Size: 7098 bytes --]

[-- Attachment #2: erc.diff --]
[-- Type: text/plain, Size: 28182 bytes --]

diff --ignore-space-change -c '-F^[_a-zA-Z0-9$]+ *(' projects/emacs/lisp/erc/ChangeLog projects/emacs-dev/lisp/erc/ChangeLog
*** projects/emacs/lisp/erc/ChangeLog   2014-06-10 09:04:50.536885271 -0400
--- projects/emacs-dev/lisp/erc/ChangeLog       2014-06-11 07:30:02.422563635 -0400
***************
*** 1,3 ****
--- 1,15 ----
+ 2014-06-11  Kelvin White  <kelvin.white77@gmail.com>
+
+       * erc-backend.el Handle user modes in relevent server responses
+       * erc.el Better user mode support.
+       (erc-channel-user): Add members for new modes.
+       (erc-channel-member-halfop-p, erc-channel-user-admin-p, erc-channel-user-owner-p): Use new struct members.
+       (erc-format-nick, erc-format-@nick): Display user modes as nick prefix.
+       (erc-nick-prefix-face, erc-my-nick-prefix-face): Add new faces to separate colors if desired.
+       (erc-get-user-mode-prefix): Return symbol for mode prefix.
+       (erc-update-channel-member, erc-update-current-channel-member, erc-channel-receive-names): Update channel users.
+       (erc-nick-at-point): Return correct user info.
+
  2014-04-04  Stefan Monnier  <monnier@iro.umontreal.ca>

        * erc.el (erc-invite-only-mode, erc-toggle-channel-mode): Simplify.
***************
*** 615,618 ****
  ;; coding: utf-8
  ;; add-log-time-zone-rule: t
  ;; End:
-
--- 627,629 ----
diff --ignore-space-change -c '-F^[_a-zA-Z0-9$]+ *(' projects/emacs/lisp/erc/erc-backend.el projects/emacs-dev/lisp/erc/erc-backend.el
*** projects/emacs/lisp/erc/erc-backend.el      2014-06-11 06:53:48.176451824 -0400
--- projects/emacs-dev/lisp/erc/erc-backend.el  2014-06-11 06:55:57.682449183 -0400
***************
*** 1244,1250 ****
                         (erc-format-message
                          'JOIN ?n nick ?u login ?h host ?c chnl))))))
            (when buffer (set-buffer buffer))
!           (erc-update-channel-member chnl nick nick t nil nil host login)
            ;; on join, we want to stay in the new channel buffer
            ;;(set-buffer ob)
            (erc-display-message parsed nil buffer str))))))
--- 1244,1250 ----
                         (erc-format-message
                          'JOIN ?n nick ?u login ?h host ?c chnl))))))
            (when buffer (set-buffer buffer))
!           (erc-update-channel-member chnl nick nick t nil nil nil nil nil host login)
            ;; on join, we want to stay in the new channel buffer
            ;;(set-buffer ob)
            (erc-display-message parsed nil buffer str))))))
***************
*** 1413,1419 ****
              ;; message.  We will accumulate private identities indefinitely
              ;; at this point.
              (erc-update-channel-member (if privp nick tgt) nick nick
!                                        privp nil nil host login nil nil t)
              (let ((cdata (erc-get-channel-user nick)))
                (setq fnick (funcall erc-format-nick-function
                                     (car cdata) (cdr cdata))))))
--- 1413,1419 ----
              ;; message.  We will accumulate private identities indefinitely
              ;; at this point.
              (erc-update-channel-member (if privp nick tgt) nick nick
!                                        privp nil nil nil nil nil host login nil nil t)
              (let ((cdata (erc-get-channel-user nick)))
                (setq fnick (funcall erc-format-nick-function
                                     (car cdata) (cdr cdata))))))
***************
*** 1470,1476 ****
                                     (current-time))))
      (pcase-let ((`(,nick ,login ,host)
                   (erc-parse-user (erc-response.sender parsed))))
!       (erc-update-channel-member ch nick nick nil nil nil host login)
        (erc-update-channel-topic ch (format "%s\C-o (%s, %s)" topic nick time))
        (erc-display-message parsed 'notice (erc-get-buffer ch proc)
                             'TOPIC ?n nick ?u login ?h host
--- 1470,1476 ----
                                     (current-time))))
      (pcase-let ((`(,nick ,login ,host)
                   (erc-parse-user (erc-response.sender parsed))))
!       (erc-update-channel-member ch nick nick nil nil nil nil nil nil host login)
        (erc-update-channel-topic ch (format "%s\C-o (%s, %s)" topic nick time))
        (erc-display-message parsed 'notice (erc-get-buffer ch proc)
                             'TOPIC ?n nick ?u login ?h host
***************
*** 1800,1807 ****
        (when (string-match "\\(^[0-9]+ \\)\\(.*\\)$" full-name)
          (setq hopcount (match-string 1 full-name))
          (setq full-name (match-string 2 full-name)))
!       (erc-update-channel-member channel nick nick nil nil nil host
!                                  user full-name)
        (erc-display-message parsed 'notice 'active 's352
                             ?c channel ?n nick ?a away-flag
                             ?u user ?h host ?f full-name))))
--- 1800,1806 ----
        (when (string-match "\\(^[0-9]+ \\)\\(.*\\)$" full-name)
          (setq hopcount (match-string 1 full-name))
          (setq full-name (match-string 2 full-name)))
!       (erc-update-channel-member channel nick nick nil nil nil nil nil nil host user full-name)
        (erc-display-message parsed 'notice 'active 's352
                             ?c channel ?n nick ?a away-flag
                             ?u user ?h host ?f full-name))))
diff --ignore-space-change -c '-F^[_a-zA-Z0-9$]+ *(' projects/emacs/lisp/erc/erc.el projects/emacs-dev/lisp/erc/erc.el
*** projects/emacs/lisp/erc/erc.el      2014-06-11 06:53:48.176451824 -0400
--- projects/emacs-dev/lisp/erc/erc.el  2014-06-11 07:09:49.603393410 -0400
***************
*** 370,376 ****
    )

  (cl-defstruct (erc-channel-user (:type vector) :named)
!   op voice
    ;; Last message time (in the form of the return value of
    ;; (current-time)
    ;;
--- 370,376 ----
    )

  (cl-defstruct (erc-channel-user (:type vector) :named)
!   voice halfop op admin owner
    ;; Last message time (in the form of the return value of
    ;; (current-time)
    ;;
***************
*** 475,480 ****
--- 475,496 ----
               erc-channel-users)
      (clrhash erc-channel-users)))

+ (defsubst erc-channel-user-owner-p (nick)
+   "Return t if NICK is an owner of the current channel."
+   (and nick
+        (hash-table-p erc-channel-users)
+        (let ((cdata (erc-get-channel-user nick)))
+          (and cdata (cdr cdata)
+               (erc-channel-user-owner (cdr cdata))))))
+
+ (defsubst erc-channel-user-admin-p (nick)
+   "Return t if NICK is an admin in the current channel."
+   (and nick
+        (hash-table-p erc-channel-users)
+        (let ((cdata (erc-get-channel-user nick)))
+          (and cdata (cdr cdata)
+               (erc-channel-user-admin (cdr cdata))))))
+
  (defsubst erc-channel-user-op-p (nick)
    "Return t if NICK is an operator in the current channel."
    (and nick
***************
*** 483,488 ****
--- 499,512 ----
           (and cdata (cdr cdata)
                (erc-channel-user-op (cdr cdata))))))

+ (defsubst erc-channel-user-halfop-p (nick)
+   "Return t if NICK is a half-operator in the current channel."
+   (and nick
+        (hash-table-p erc-channel-users)
+        (let ((cdata (erc-get-channel-user nick)))
+          (and cdata (cdr cdata)
+               (erc-channel-user-halfop (cdr cdata))))))
+
  (defsubst erc-channel-user-voice-p (nick)
    "Return t if NICK has voice in the current channel."
    (and nick
***************
*** 1122,1127 ****
--- 1146,1159 ----
    "ERC default face."
    :group 'erc-faces)

+ (defface erc-nick-prefix-face '((t :weight bold))
+   "ERC face used for user mode prefix."
+   :group 'erc-faces)
+
+ (defface erc-my-nick-prefix-face '((t :weight bold))
+   "ERC face used for my user mode prefix."
+   :group 'erc-faces)
+
  (defface erc-direct-msg-face '((t :foreground "IndianRed"))
    "ERC face used for messages you receive in the main erc buffer."
    :group 'erc-faces)
***************
*** 4192,4215 ****
  See also `erc-format-nick-function'."
    (when user (erc-server-user-nickname user)))

  (defun erc-format-@nick (&optional user channel-data)
    "Format the nickname of USER showing if USER is an operator or has voice.
  Operators have \"@\" and users with voice have \"+\" as a prefix.
  Use CHANNEL-DATA to determine op and voice status.
  See also `erc-format-nick-function'."
    (when user
!     (let ((op (and channel-data (erc-channel-user-op channel-data) "@"))
!         (voice (and channel-data (erc-channel-user-voice channel-data) "+")))
!       (concat voice op (erc-server-user-nickname user)))))

  (defun erc-format-my-nick ()
    "Return the beginning of this user's message, correctly propertized."
    (if erc-show-my-nick
!       (let ((open "<")
            (close "> ")
!           (nick (erc-current-nick)))
        (concat
         (erc-propertize open 'face 'erc-default-face)
         (erc-propertize nick 'face 'erc-my-nick-face)
         (erc-propertize close 'face 'erc-default-face)))
      (let ((prefix "> "))
--- 4224,4257 ----
  See also `erc-format-nick-function'."
    (when user (erc-server-user-nickname user)))

+ (defun erc-get-user-mode-prefix (user)
+   (when user
+     (cond ((erc-channel-user-voice-p user) "+")
+           ((erc-channel-user-half-op-p user) "%")
+           ((erc-channel-user-op-p user) "@")
+           ((erc-channel-user-admin-p user) "&")
+           ((erc-channel-user-owner-p user) "~")
+           (t ""))))
+
  (defun erc-format-@nick (&optional user channel-data)
    "Format the nickname of USER showing if USER is an operator or has voice.
  Operators have \"@\" and users with voice have \"+\" as a prefix.
  Use CHANNEL-DATA to determine op and voice status.
  See also `erc-format-nick-function'."
    (when user
!     (let ((nick (erc-server-user-nickname user)))
!       (concat (erc-propertize (erc-get-user-mode-prefix nick) 'face 'erc-nick-prefix-face) nick))))

  (defun erc-format-my-nick ()
    "Return the beginning of this user's message, correctly propertized."
    (if erc-show-my-nick
!       (let* ((open "<")
               (close "> ")
!              (nick (erc-current-nick))
!              (mode (erc-get-user-mode-prefix nick)))
          (concat
           (erc-propertize open 'face 'erc-default-face)
+          (erc-propertize mode 'face 'erc-my-nick-prefix-face)
           (erc-propertize nick 'face 'erc-my-nick-face)
           (erc-propertize close 'face 'erc-default-face)))
      (let ((prefix "> "))
***************
*** 4685,4691 ****
    (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)
--- 4727,4733 ----
    (let ((str (or (cdr (assoc "PREFIX" (erc-with-server-buffer
                                          erc-server-parameters)))
                   ;; provide a sane default
!                  "(qaohv)~&@%+"))
          types chars)
      (when (string-match "^(\\([^)]+\\))\\(.+\\)$" str)
        (setq types (match-string 1 str)
***************
*** 4705,4714 ****
  Update `erc-channel-users' according to NAMES-STRING.
  NAMES-STRING is a string listing some of the names on the
  channel."
!   (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)))
--- 4747,4759 ----
  Update `erc-channel-users' according to NAMES-STRING.
  NAMES-STRING is a string listing some of the names on the
  channel."
!   (let (prefix voice-ch hop-ch op-ch adm-ch own-ch names name voice halfop op admin owner)
      (setq prefix (erc-parse-prefix))
!     (setq voice-ch (cdr (assq ?v prefix))
!           hop-ch (cdr (assq ?h prefix))
!           op-ch (cdr (assq ?o prefix))
!           adm-ch (cdr (assq ?a prefix))
!           own-ch (cdr (assq ?q prefix)))
      ;; We need to delete "" because in XEmacs, (split-string "a ")
      ;; returns ("a" "").
      (setq names (delete "" (split-string names-string)))
***************
*** 4718,4742 ****
          (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
--- 4763,4820 ----
            (if (rassq (elt item 0) prefix)
                (cond ((= (length item) 1)
                       (setq updatep nil))
+                     ((eq (elt item 0) voice-ch)
+                      (setq name (substring item 1)
+                            op 'off
+                            voice 'on
+                            halfop 'off
+                            admin 'off
+                            owner 'off))
+                     ((eq (elt item 0) hop-ch)
+                      (setq name (substring item 1)
+                            op 'off
+                            voice 'off
+                            halfop 'on
+                            admin 'off
+                            owner 'off))
                      ((eq (elt item 0) op-ch)
                       (setq name (substring item 1)
                             op 'on
!                            voice 'off
!                            halfop 'off
!                            admin 'off
!                            owner 'off))
!                     ((eq (elt item 0) adm-ch)
!                      (setq name (substring item 1)
!                            op 'off
!                            voice 'off
!                            halfop 'off
!                            admin 'on
!                            owner 'off))
!                     ((eq (elt item 0) own-ch)
                       (setq name (substring item 1)
                             op 'off
!                            voice 'off
!                            halfop 'off
!                            admin 'off
!                            owner 'on))
                      (t (setq name (substring item 1)
                               op 'off
!                              voice 'off
!                              halfop 'off
!                              admin 'off
!                              owner 'off)))
              (setq name item
                    op 'off
!                   voice 'off
!                   halfop 'off
!                   admin 'off
!                   owner 'off))
            (when updatep
              (puthash (erc-downcase name) t
                       erc-channel-new-member-names)
              (erc-update-current-channel-member
!              name name t voice halfop op admin owner)))))
      (run-hooks 'erc-channel-members-changed-hook)))

  (defcustom erc-channel-members-changed-hook nil
***************
*** 4795,4810 ****
      changed))

  (defun erc-update-current-channel-member
!   (nick new-nick &optional add op voice host login full-name info
        update-message-time)
    "Update the stored user information for the user with nickname NICK.
  `erc-update-user' is called to handle changes to nickname,
! HOST, LOGIN, FULL-NAME, and INFO.  If OP or VOICE are non-nil,
! they must be equal to either `on' or `off', in which case the
! operator or voice status of the user in the current channel is
! changed accordingly.  If UPDATE-MESSAGE-TIME is non-nil, the
! last-message-time of the user in the current channel is set
! to (current-time).

  If ADD is non-nil, the user will be added with the specified
  information if it is not already present in the user or channel
--- 4873,4887 ----
      changed))

  (defun erc-update-current-channel-member
!   (nick new-nick &optional add voice halfop op admin owner host login full-name info
          update-message-time)
    "Update the stored user information for the user with nickname NICK.
  `erc-update-user' is called to handle changes to nickname,
! HOST, LOGIN, FULL-NAME, and INFO.  If VOICE HALFOP OP ADMIN or OWNER
! are non-nil, they must be equal to either `on' or `off', in which
! case the status of the user in the current channel is changed accordingly.
! If UPDATE-MESSAGE-TIME is non-nil, the last-message-time of the user
!  in the current channel is set to (current-time).

  If ADD is non-nil, the user will be added with the specified
  information if it is not already present in the user or channel
***************
*** 4822,4827 ****
--- 4899,4918 ----
      (if cuser
          (progn
            (erc-log (format "update-member: user = %S, cuser = %S" user cuser))
+           (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))))
+           (when (and halfop
+                      (not (eq (erc-channel-user-halfop cuser) halfop)))
+             (setq changed t)
+             (setf (erc-channel-user-halfop cuser)
+                   (cond ((eq halfop 'on) t)
+                         ((eq halfop 'off) nil)
+                         (t halfop))))
            (when (and op
                       (not (eq (erc-channel-user-op cuser) op)))
              (setq changed t)
***************
*** 4829,4841 ****
                  (cond ((eq op 'on) t)
                        ((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))))
          (when update-message-time
            (setf (erc-channel-user-last-message-time cuser) (current-time)))
          (setq user-changed
--- 4920,4939 ----
                    (cond ((eq op 'on) t)
                          ((eq op 'off) nil)
                          (t op))))
!           (when (and admin
!                      (not (eq (erc-channel-user-admin cuser) admin)))
              (setq changed t)
!             (setf (erc-channel-user-admin cuser)
!                   (cond ((eq admin 'on) t)
!                         ((eq admin 'off) nil)
!                         (t admin))))
!           (when (and owner
!                      (not (eq (erc-channel-user-owner cuser) owner)))
!             (setq changed t)
!             (setf (erc-channel-user-owner cuser)
!                   (cond ((eq owner 'on) t)
!                         ((eq owner 'off) nil)
!                         (t owner))))
            (when update-message-time
              (setf (erc-channel-user-last-message-time cuser) (current-time)))
            (setq user-changed
***************
*** 4856,4867 ****
                (cons (current-buffer)
                      (erc-server-user-buffers user))))
        (setq cuser (make-erc-channel-user
-                    :op (cond ((eq op 'on) t)
-                              ((eq op 'off) nil)
-                              (t op))
                     :voice (cond ((eq voice 'on) t)
                                  ((eq voice 'off) nil)
                                  (t voice))
                     :last-message-time
                     (if update-message-time (current-time))))
        (puthash (erc-downcase nick) (cons user cuser)
--- 4954,4974 ----
                  (cons (current-buffer)
                        (erc-server-user-buffers user))))
          (setq cuser (make-erc-channel-user
                       :voice (cond ((eq voice 'on) t)
                                    ((eq voice 'off) nil)
                                    (t voice))
+                      :halfop (cond ((eq halfop 'on) t)
+                                 ((eq halfop 'off) nil)
+                                 (t halfop))
+                      :op (cond ((eq op 'on) t)
+                                ((eq op 'off) nil)
+                                (t op))
+                      :admin (cond ((eq admin 'on) t)
+                                   ((eq admin 'off) nil)
+                                   (t admin))
+                      :owner (cond ((eq owner 'on) t)
+                                   ((eq owner 'off) nil)
+                                   (t owner))
                       :last-message-time
                       (if update-message-time (current-time))))
          (puthash (erc-downcase nick) (cons user cuser)
***************
*** 4872,4878 ****
      (or changed user-changed add)))

  (defun erc-update-channel-member (channel nick new-nick
!                                 &optional add op voice host login
                                  full-name info update-message-time)
    "Update user and channel information for the user with
  nickname NICK in channel CHANNEL.
--- 4979,4985 ----
      (or changed user-changed add)))

  (defun erc-update-channel-member (channel nick new-nick
!                                           &optional add voice halfop op admin owner host login
                                            full-name info update-message-time)
    "Update user and channel information for the user with
  nickname NICK in channel CHANNEL.
***************
*** 4880,4886 ****
  See also: `erc-update-current-channel-member'."
    (erc-with-buffer
     (channel)
!    (erc-update-current-channel-member nick new-nick add op voice host
                                      login full-name info
                                      update-message-time)))

--- 4987,4993 ----
  See also: `erc-update-current-channel-member'."
    (erc-with-buffer
        (channel)
!     (erc-update-current-channel-member nick new-nick add voice halfop op admin owner host
                                         login full-name info
                                         update-message-time)))

***************
*** 4979,4985 ****
        (while chars
          (cond ((string= (car chars) "+") (setq add-p t))
                ((string= (car chars) "-") (setq add-p nil))
!               ((string-match "^[ovbOVB]" (car chars))
                 (setq arg-modes (cons (list (car chars)
                                             (if add-p 'on 'off)
                                             (if args (car args) nil))
--- 5086,5092 ----
          (while chars
            (cond ((string= (car chars) "+") (setq add-p t))
                  ((string= (car chars) "-") (setq add-p nil))
!                 ((string-match "^[qaovhbQAOVHB]" (car chars))
                   (setq arg-modes (cons (list (car chars)
                                               (if add-p 'on 'off)
                                               (if args (car args) nil))
***************
*** 5035,5045 ****
                 (let ((mode (nth 0 (car arg-modes)))
                       (onoff (nth 1 (car arg-modes)))
                       (arg (nth 2 (car arg-modes))))
!                  (cond ((string-match "^[oO]" mode)
                          (erc-update-channel-member tgt arg arg nil onoff))
!                        ((string-match "^[Vv]" mode)
!                         (erc-update-channel-member tgt arg arg nil nil
!                                                    onoff))
                         ((string-match "^[Ll]" mode)
                          (erc-update-channel-limit tgt onoff arg))
                         ((string-match "^[Kk]" mode)
--- 5142,5157 ----
                   (let ((mode (nth 0 (car arg-modes)))
                         (onoff (nth 1 (car arg-modes)))
                         (arg (nth 2 (car arg-modes))))
!                    (cond ((string-match "^[Vv]" mode)
                            (erc-update-channel-member tgt arg arg nil onoff))
!                          ((string-match "^[hH]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil onoff))
!                          ((string-match "^[oO]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil nil onoff))
!                          ((string-match "^[aA]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil nil nil onoff))
!                          ((string-match "^[qQ]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil nil nil nil onoff))
                           ((string-match "^[Ll]" mode)
                            (erc-update-channel-limit tgt onoff arg))
                           ((string-match "^[Kk]" mode)
***************
*** 5978,6003 ****
         (user (if channel-data
                   (car channel-data)
                 (erc-get-server-user word)))
!        host login full-name nick op voice)
      (when user
        (setq nick (erc-server-user-nickname user)
            host (erc-server-user-host user)
            login (erc-server-user-login user)
            full-name (erc-server-user-full-name user))
        (if cuser
!         (setq op (erc-channel-user-op cuser)
!               voice (erc-channel-user-voice cuser)))
        (if (called-interactively-p 'interactive)
          (message "%s is %s@%s%s%s"
                   nick login host
                   (if full-name (format " (%s)" full-name) "")
!                  (if (or op voice)
                               (format " and is +%s%s on %s"
-                              (if op "o" "")
                               (if voice "v" "")
                               (erc-default-target))
                             ""))
!       user))))

  (defun erc-away-time ()
    "Return non-nil if the current ERC process is set away.
--- 6090,6121 ----
           (user (if channel-data
                     (car channel-data)
                   (erc-get-server-user word)))
!          host login full-name nick voice halfop op admin owner)
      (when user
        (setq nick (erc-server-user-nickname user)
              host (erc-server-user-host user)
              login (erc-server-user-login user)
              full-name (erc-server-user-full-name user))
        (if cuser
!           (setq voice (erc-channel-user-voice cuser)
!                 halfop (erc-channel-user-halfop cuser)
!                 op (erc-channel-user-op cuser)
!                 admin (erc-channel-user-admin cuser)
!                 owner (erc-channel-user-owner cuser))))
      (if (called-interactively-p 'interactive)
          (message "%s is %s@%s%s%s"
                   nick login host
                   (if full-name (format " (%s)" full-name) "")
!                  (if (or voice halfop op admin owner)
                       (format " and is +%s%s on %s"
                               (if voice "v" "")
+                              (if halfop "h" "")
+                              (if op "o" "")
+                              (if admin "a" "")
+                              (if owner "q" "")
                               (erc-default-target))
                     ""))
!       user)))

  (defun erc-away-time ()
    "Return non-nil if the current ERC process is set away.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#17755: 24.3; ERC user mode support
  2014-06-11 11:45 ` Kelvin White
@ 2014-06-17 16:03   ` Stefan Monnier
  2014-06-18 14:40     ` Kelvin White
  0 siblings, 1 reply; 8+ messages in thread
From: Stefan Monnier @ 2014-06-17 16:03 UTC (permalink / raw)
  To: Kelvin White
  Cc: Lawrence Mitchell, Michael Olson, 17755, mlang, Diane Murray,
	Alex Schroeder, Julien Danjou, Francis Litterio, Jorgen Schaefer

> Here is the patch to add this feature

Thanks, here are some comments on it.  I wish someone who has worked on
ERC could say something.  I never use(d) IRC and have hence no clue what is
a "user mode prefix", for example.

> ***************
> *** 1244,1250 ****
>                          (erc-format-message
>                           'JOIN ?n nick ?u login ?h host ?c chnl))))))
>             (when buffer (set-buffer buffer))
> !           (erc-update-channel-member chnl nick nick t nil nil host login)
>             ;; on join, we want to stay in the new channel buffer
>             ;;(set-buffer ob)
>             (erc-display-message parsed nil buffer str))))))
> --- 1244,1250 ----
>                          (erc-format-message
>                           'JOIN ?n nick ?u login ?h host ?c chnl))))))
>             (when buffer (set-buffer buffer))
> !           (erc-update-channel-member chnl nick nick t nil nil nil nil nil host login)
>             ;; on join, we want to stay in the new channel buffer
>             ;;(set-buffer ob)
>             (erc-display-message parsed nil buffer str))))))

In my opinion, erc-update-channel-member had too many arguments already.
Maybe some of these args should be combined into an erc-channel-user object?

> + (defsubst erc-channel-user-owner-p (nick)
> +   "Return t if NICK is an owner of the current channel."

Usually we say "non-nil" rather than "t", unless the callers need to
rely on the return value being t rather than some other non-nil value.

> + (defface erc-nick-prefix-face '((t :weight bold))
> +   "ERC face used for user mode prefix."
> +   :group 'erc-faces)
> +
> + (defface erc-my-nick-prefix-face '((t :weight bold))
> +   "ERC face used for my user mode prefix."
> +   :group 'erc-faces)

Try to use the :inherit property at least to link those two (so users
who just want to change the two without making them different only need
to change one of the two) and ideally by inheriting from some other face.

> + (defun erc-get-user-mode-prefix (user)
> +   (when user
> +     (cond ((erc-channel-user-voice-p user) "+")
> +           ((erc-channel-user-half-op-p user) "%")
> +           ((erc-channel-user-op-p user) "@")
> +           ((erc-channel-user-admin-p user) "&")
> +           ((erc-channel-user-owner-p user) "~")
> +           (t ""))))

Here I assume there's some kind of logic or convention.  If not, maybe
it would be appropriate to do something like add some `help-echo'
property to those extra chars?

One more thing: the above suggests that maybe
voice/halfop/op/admin/owner are mutually exclusive.  Is that the case?
Could these be collapsed into a single element which could have values
`voice', `halfop', `op', `admin', or `owner' (or nil)?

>   (defun erc-format-@nick (&optional user channel-data)
>     "Format the nickname of USER showing if USER is an operator or has voice.
>   Operators have \"@\" and users with voice have \"+\" as a prefix.
>   Use CHANNEL-DATA to determine op and voice status.
>   See also `erc-format-nick-function'."
>     (when user
> !     (let ((nick (erc-server-user-nickname user)))
> !       (concat (erc-propertize (erc-get-user-mode-prefix nick) 'face 'erc-nick-prefix-face) nick))))

Please try to stay with 80 columns.

BTW, IIUC, ERC is not distributed separately from Emacs any more, so we
don't need to use compatibility crutches like erc-propertize any more
(tho it's fine to use it as well for now, and it could be removed "all at
once" in another patch).

> !                "(ov)@+"))
[...]
> !                  "(qaohv)~&@%+"))

Yay!  Magic!

> !   (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)))

this should have been

      (let* ((prefix (erc-parse-prefix))
             (op-ch (cdr (assq ?o prefix)))
             (voice-ch (cdr (assq ?v prefix)))
             names name op voice)

Which is both cleaner and faster.

So when you change such code, you can take advantage of the change to
try and reduce occurrences of those "let-without-init followed by setq".

> --- 4763,4820 ----
>             (if (rassq (elt item 0) prefix)
>                 (cond ((= (length item) 1)
>                        (setq updatep nil))
> +                     ((eq (elt item 0) voice-ch)
> +                      (setq name (substring item 1)
> +                            op 'off
> +                            voice 'on
> +                            halfop 'off
> +                            admin 'off
> +                            owner 'off))
> +                     ((eq (elt item 0) hop-ch)
> +                      (setq name (substring item 1)
> +                            op 'off
> +                            voice 'off
> +                            halfop 'on
> +                            admin 'off
> +                            owner 'off))
>                       ((eq (elt item 0) op-ch)
>                        (setq name (substring item 1)
>                              op 'on
> !                            voice 'off
> !                            halfop 'off
> !                            admin 'off
> !                            owner 'off))
> !                     ((eq (elt item 0) adm-ch)
> !                      (setq name (substring item 1)
> !                            op 'off
> !                            voice 'off
> !                            halfop 'off
> !                            admin 'on
> !                            owner 'off))
> !                     ((eq (elt item 0) own-ch)
>                        (setq name (substring item 1)
>                              op 'off
> !                            voice 'off
> !                            halfop 'off
> !                            admin 'off
> !                            owner 'on))
>                       (t (setq name (substring item 1)
>                                op 'off
> !                              voice 'off
> !                              halfop 'off
> !                              admin 'off
> !                              owner 'off)))

This also makes it sound like those op/voice/admin/owner are mutually
exclusive and should be combined into a single element.

Otherwise, please simplify the code with:

   (setq op 'off voice 'off halfop 'off admin 'off owner 'off)
   (cond
    ((eq (elt item 0) voice-ch)
     (setq name (substring item 1)
           voice 'on))
    [...])

> +           (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))))

Won't this cause `changed' to "always" be set to t, since
(erc-channel-user-voice cuser) will never be `on' or `off' and hence
never be equal to `voice'?

Also, instead of using on/off and converting them from&to nil/t, maybe
it would be simpler to use nil/t plus a special value
(e.g. `:unspecified') for the case where the value is simply
not provided.


        Stefan





^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#17755: 24.3; ERC user mode support
  2014-06-17 16:03   ` Stefan Monnier
@ 2014-06-18 14:40     ` Kelvin White
  2014-06-18 16:08       ` Kelvin White
  2014-06-18 18:32       ` Stefan Monnier
  0 siblings, 2 replies; 8+ messages in thread
From: Kelvin White @ 2014-06-18 14:40 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Lawrence Mitchell, Michael Olson, 17755, Mario Lang, Diane Murray,
	Alex Schroeder, Julien Danjou, Francis Litterio, Jorgen Schaefer


[-- Attachment #1.1: Type: text/plain, Size: 6814 bytes --]

> Thanks, here are some comments on it.  I wish someone who has worked on
> ERC could say something.  I never use(d) IRC and have hence no clue what
is
> a "user mode prefix", for example.

A user mode prefix is referring to a symbol prefixed to your nickname to
display to other users that you have a certain user mode.
Take "&nickname" for instance. The "&" is the user mode prefix showing you
have +a (admin) user mode.

> > ***************
> > *** 1244,1250 ****
> >                          (erc-format-message
> >                           'JOIN ?n nick ?u login ?h host ?c chnl))))))
> >             (when buffer (set-buffer buffer))
> > !           (erc-update-channel-member chnl nick nick t nil nil host
login)
> >             ;; on join, we want to stay in the new channel buffer
> >             ;;(set-buffer ob)
> >             (erc-display-message parsed nil buffer str))))))
> > --- 1244,1250 ----
> >                          (erc-format-message
> >                           'JOIN ?n nick ?u login ?h host ?c chnl))))))
> >             (when buffer (set-buffer buffer))
> > !           (erc-update-channel-member chnl nick nick t nil nil nil nil
nil host login)
> >             ;; on join, we want to stay in the new channel buffer
> >             ;;(set-buffer ob)
> >             (erc-display-message parsed nil buffer str))))))
>
> In my opinion, erc-update-channel-member had too many arguments already.
> Maybe some of these args should be combined into an erc-channel-user
object?

My first approach was to change the erc-channel-user struct to use a list
of modes,
eliminating some of the args, but it seemed to cause issues elsewhere.
 I'll revisit this again soon.

> > + (defsubst erc-channel-user-owner-p (nick)
> > +   "Return t if NICK is an owner of the current channel."
>
> Usually we say "non-nil" rather than "t", unless the callers need to
> rely on the return value being t rather than some other non-nil value.

Indeed, the callers do rely on the value being t in this case. rather than
just non-nil

> > + (defface erc-nick-prefix-face '((t :weight bold))
> > +   "ERC face used for user mode prefix."
> > +   :group 'erc-faces)
> > +
> > + (defface erc-my-nick-prefix-face '((t :weight bold))
> > +   "ERC face used for my user mode prefix."
> > +   :group 'erc-faces)
>
> Try to use the :inherit property at least to link those two (so users
> who just want to change the two without making them different only need
> to change one of the two) and ideally by inheriting from some other face.

Good idea. I have updated this so each of these two faces inherits from the
appropriate nick faces.
By default the prefix will be the same color unless these are changed
individually.

> > + (defun erc-get-user-mode-prefix (user)
> > +   (when user
> > +     (cond ((erc-channel-user-voice-p user) "+")
> > +           ((erc-channel-user-half-op-p user) "%")
> > +           ((erc-channel-user-op-p user) "@")
> > +           ((erc-channel-user-admin-p user) "&")
> > +           ((erc-channel-user-owner-p user) "~")
> > +           (t ""))))
>
> Here I assume there's some kind of logic or convention.  If not, maybe
> it would be appropriate to do something like add some `help-echo'
> property to those extra chars?

Sure, I've updated the patch to add help-echo props

> One more thing: the above suggests that maybe
> voice/halfop/op/admin/owner are mutually exclusive.  Is that the case?
> Could these be collapsed into a single element which could have values
> `voice', `halfop', `op', `admin', or `owner' (or nil)?

These are actually not mutually exclusive. A user could have all of these
modes enabled, but it isn't typical.
In that case we only want to display the most valuable. If a user has +vo
we want to display @.
If a user has +oa we display &. etc. Glad you noticed this though, this
should check in reverse order.

> >   (defun erc-format-@nick (&optional user channel-data)
> >     "Format the nickname of USER showing if USER is an operator or has
voice.
> >   Operators have \"@\" and users with voice have \"+\" as a prefix.
> >   Use CHANNEL-DATA to determine op and voice status.
> >   See also `erc-format-nick-function'."
> >     (when user
> > !     (let ((nick (erc-server-user-nickname user)))
> > !       (concat (erc-propertize (erc-get-user-mode-prefix nick) 'face
'erc-nick-prefix-face) nick))))

> Please try to stay with 80 columns.

Ok

> BTW, IIUC, ERC is not distributed separately from Emacs any more, so we
> don't need to use compatibility crutches like erc-propertize any more
> (tho it's fine to use it as well for now, and it could be removed "all at
> once" in another patch).

Good point, I'll clean that up in another patch.

> > !                "(ov)@+"))
> [...]
> > !                  "(qaohv)~&@%+"))

>Yay!  Magic!

;D these are the default user modes

> !   (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)))
>
> this should have been
>
>      (let* ((prefix (erc-parse-prefix))
>            (op-ch (cdr (assq ?o prefix)))
>             (voice-ch (cdr (assq ?v prefix)))
>             names name op voice)
>
> Which is both cleaner and faster.
>
> So when you change such code, you can take advantage of the change to
> try and reduce occurrences of those "let-without-init followed by setq".

This has been updated, thanks.

> This also makes it sound like those op/voice/admin/owner are mutually
> exclusive and should be combined into a single element.

> Otherwise, please simplify the code with:

>   (setq op 'off voice 'off halfop 'off admin 'off owner 'off)
>   (cond
>    ((eq (elt item 0) voice-ch)
>     (setq name (substring item 1)
>           voice 'on))
>    [...])

Yes, I agree. I have simplified it.

> > +           (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))))
>
> Won't this cause `changed' to "always" be set to t, since
> (erc-channel-user-voice cuser) will never be `on' or `off' and hence
> never be equal to `voice'?

> Also, instead of using on/off and converting them from&to nil/t, maybe
> it would be simpler to use nil/t plus a special value
> (e.g. `:unspecified') for the case where the value is simply
> not provided.

Sure, I will look at revising this in a separate patch. I tried to keep
this as simple
as possible but I have noticed things like this and others that could be
simplified
and cleaned up a bit.

Attached is the new patch cleaned up per your suggestions.

Thanks

[-- Attachment #1.2: Type: text/html, Size: 10358 bytes --]

[-- Attachment #2: erc-patch.diff --]
[-- Type: text/plain, Size: 21151 bytes --]

*** projects/emacs/lisp/erc/erc.el	2014-06-18 10:08:15.639519157 -0400
--- projects/emacs-dev/lisp/erc/erc.el	2014-06-18 10:15:41.395718554 -0400
***************
*** 370,376 ****
    )
  
  (cl-defstruct (erc-channel-user (:type vector) :named)
!   op voice
    ;; Last message time (in the form of the return value of
    ;; (current-time)
    ;;
--- 370,376 ----
    )
  
  (cl-defstruct (erc-channel-user (:type vector) :named)
!   voice halfop op admin owner
    ;; Last message time (in the form of the return value of
    ;; (current-time)
    ;;
***************
*** 475,480 ****
--- 475,496 ----
               erc-channel-users)
      (clrhash erc-channel-users)))
  
+ (defsubst erc-channel-user-owner-p (nick)
+   "Return t if NICK is an owner of the current channel."
+   (and nick
+        (hash-table-p erc-channel-users)
+        (let ((cdata (erc-get-channel-user nick)))
+          (and cdata (cdr cdata)
+               (erc-channel-user-owner (cdr cdata))))))
+ 
+ (defsubst erc-channel-user-admin-p (nick)
+   "Return t if NICK is an admin in the current channel."
+   (and nick
+        (hash-table-p erc-channel-users)
+        (let ((cdata (erc-get-channel-user nick)))
+          (and cdata (cdr cdata)
+               (erc-channel-user-admin (cdr cdata))))))
+ 
  (defsubst erc-channel-user-op-p (nick)
    "Return t if NICK is an operator in the current channel."
    (and nick
***************
*** 483,488 ****
--- 499,512 ----
           (and cdata (cdr cdata)
                (erc-channel-user-op (cdr cdata))))))
  
+ (defsubst erc-channel-user-halfop-p (nick)
+   "Return t if NICK is a half-operator in the current channel."
+   (and nick
+        (hash-table-p erc-channel-users)
+        (let ((cdata (erc-get-channel-user nick)))
+          (and cdata (cdr cdata)
+               (erc-channel-user-halfop (cdr cdata))))))
+ 
  (defsubst erc-channel-user-voice-p (nick)
    "Return t if NICK has voice in the current channel."
    (and nick
***************
*** 1122,1127 ****
--- 1146,1159 ----
    "ERC default face."
    :group 'erc-faces)
  
+ (defface erc-nick-prefix-face '((t :inherit erc-nick-default-face :weight bold))
+   "ERC face used for user mode prefix."
+   :group 'erc-faces)
+ 
+ (defface erc-my-nick-prefix-face '((t :inherit erc-my-nick-face :weight bold))
+   "ERC face used for my user mode prefix."
+   :group 'erc-faces)
+ 
  (defface erc-direct-msg-face '((t :foreground "IndianRed"))
    "ERC face used for messages you receive in the main erc buffer."
    :group 'erc-faces)
***************
*** 4190,4196 ****
  (defun erc-format-nick (&optional user _channel-data)
    "Return the nickname of USER.
  See also `erc-format-nick-function'."
!   (when user (erc-server-user-nickname user)))
  
  (defun erc-format-@nick (&optional user channel-data)
    "Format the nickname of USER showing if USER is an operator or has voice.
--- 4222,4245 ----
  (defun erc-format-nick (&optional user _channel-data)
    "Return the nickname of USER.
  See also `erc-format-nick-function'."
!   (let ((nick (erc-server-user-nickname user)))
!     (concat (erc-propertize
!              (erc-get-user-mode-prefix nick)
!              'face 'erc-nick-prefix-face) nick)))
! 
! (defun erc-get-user-mode-prefix (user)
!   (when user
!     (cond ((erc-channel-user-owner-p user)
!            (propertize "~" 'help-echo "owner"))
!           ((erc-channel-user-admin-p user)
!            (propertize "&" 'help-echo "admin"))
!           ((erc-channel-user-op-p user)
!            (propertize "@" 'help-echo "operator"))
!           ((erc-channel-user-halfop-p user)
!            (propertize "%" 'help-echo "half-op"))
!           ((erc-channel-user-voice-p user)
!            propertize "+" 'help-echo "voice")
!           (t ""))))
  
  (defun erc-format-@nick (&optional user channel-data)
    "Format the nickname of USER showing if USER is an operator or has voice.
***************
*** 4198,4215 ****
  Use CHANNEL-DATA to determine op and voice status.
  See also `erc-format-nick-function'."
    (when user
!     (let ((op (and channel-data (erc-channel-user-op channel-data) "@"))
! 	  (voice (and channel-data (erc-channel-user-voice channel-data) "+")))
!       (concat voice op (erc-server-user-nickname user)))))
  
  (defun erc-format-my-nick ()
    "Return the beginning of this user's message, correctly propertized."
    (if erc-show-my-nick
!       (let ((open "<")
  	    (close "> ")
! 	    (nick (erc-current-nick)))
  	(concat
  	 (erc-propertize open 'face 'erc-default-face)
  	 (erc-propertize nick 'face 'erc-my-nick-face)
  	 (erc-propertize close 'face 'erc-default-face)))
      (let ((prefix "> "))
--- 4247,4267 ----
  Use CHANNEL-DATA to determine op and voice status.
  See also `erc-format-nick-function'."
    (when user
!     (let ((nick (erc-server-user-nickname user)))
!       (concat (erc-propertize
!                (erc-get-user-mode-prefix nick)
!                'face 'erc-nick-prefix-face) nick nick))))
  
  (defun erc-format-my-nick ()
    "Return the beginning of this user's message, correctly propertized."
    (if erc-show-my-nick
!       (let* ((open "<")
               (close "> ")
!              (nick (erc-current-nick))
!              (mode (erc-get-user-mode-prefix nick)))
          (concat
           (erc-propertize open 'face 'erc-default-face)
+          (erc-propertize mode 'face 'erc-my-nick-prefix-face)
           (erc-propertize nick 'face 'erc-my-nick-face)
           (erc-propertize close 'face 'erc-default-face)))
      (let ((prefix "> "))
***************
*** 4685,4691 ****
    (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)
--- 4737,4743 ----
    (let ((str (or (cdr (assoc "PREFIX" (erc-with-server-buffer
                                          erc-server-parameters)))
                   ;; provide a sane default
!                  "(qaohv)~&@%+"))
          types chars)
      (when (string-match "^(\\([^)]+\\))\\(.+\\)$" str)
        (setq types (match-string 1 str)
***************
*** 4705,4744 ****
  Update `erc-channel-users' according to NAMES-STRING.
  NAMES-STRING is a string listing some of the names on the
  channel."
!   (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))
  	  (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
    "This hook is called every time the variable `channel-members' changes.
  The buffer where the change happened is current while this hook is called."
--- 4757,4800 ----
  Update `erc-channel-users' according to NAMES-STRING.
  NAMES-STRING is a string listing some of the names on the
  channel."
!   (let* ((prefix (erc-parse-prefix))
!          (op-ch (cdr (assq ?o prefix)))
!          (voice-ch (cdr (assq ?v prefix)))
!          (adm-ch (cdr (assq ?a prefix)))
!          (own-ch (cdr (assq ?q prefix)))
!          names name op voice halfop admin owner)
      (setq names (delete "" (split-string names-string)))
      (let ((erc-channel-members-changed-hook nil))
        (dolist (item names)
          (let ((updatep t))
+           (setq name item op 'off voice 'off halfop 'off admin 'off owner 'off)
            (if (rassq (elt item 0) prefix)
                (cond ((= (length item) 1)
                       (setq updatep nil))
                      ((eq (elt item 0) voice-ch)
                       (setq name (substring item 1)
                             voice 'on))
!                     ((eq (elt item 0) hop-ch)
!                      (setq name (substring item 1)
!                            halfop 'on))
!                     ((eq (elt item 0) op-ch)
!                      (setq name (substring item 1)
!                            op 'on))
!                     ((eq (elt item 0) adm-ch)
!                      (setq name (substring item 1)
!                            admin 'on))
!                     ((eq (elt item 0) own-ch)
!                      (setq name (substring item 1)
!                            owner 'on))
!                     (t (setq name (substring item 1)))))
            (when updatep
              (puthash (erc-downcase name) t
                       erc-channel-new-member-names)
              (erc-update-current-channel-member
!              name name t voice halfop op admin owner)))))
      (run-hooks 'erc-channel-members-changed-hook)))
  
+ 
  (defcustom erc-channel-members-changed-hook nil
    "This hook is called every time the variable `channel-members' changes.
  The buffer where the change happened is current while this hook is called."
***************
*** 4795,4810 ****
      changed))
  
  (defun erc-update-current-channel-member
!   (nick new-nick &optional add op voice host login full-name info
  	update-message-time)
    "Update the stored user information for the user with nickname NICK.
  `erc-update-user' is called to handle changes to nickname,
! HOST, LOGIN, FULL-NAME, and INFO.  If OP or VOICE are non-nil,
! they must be equal to either `on' or `off', in which case the
! operator or voice status of the user in the current channel is
! changed accordingly.  If UPDATE-MESSAGE-TIME is non-nil, the
! last-message-time of the user in the current channel is set
! to (current-time).
  
  If ADD is non-nil, the user will be added with the specified
  information if it is not already present in the user or channel
--- 4851,4865 ----
      changed))
  
  (defun erc-update-current-channel-member
!   (nick new-nick &optional add voice halfop op admin owner host login full-name info
          update-message-time)
    "Update the stored user information for the user with nickname NICK.
  `erc-update-user' is called to handle changes to nickname,
! HOST, LOGIN, FULL-NAME, and INFO.  If VOICE HALFOP OP ADMIN or OWNER
! are non-nil, they must be equal to either `on' or `off', in which
! case the status of the user in the current channel is changed accordingly.
! If UPDATE-MESSAGE-TIME is non-nil, the last-message-time of the user
!  in the current channel is set to (current-time).
  
  If ADD is non-nil, the user will be added with the specified
  information if it is not already present in the user or channel
***************
*** 4822,4827 ****
--- 4877,4896 ----
      (if cuser
          (progn
            (erc-log (format "update-member: user = %S, cuser = %S" user cuser))
+           (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))))
+           (when (and halfop
+                      (not (eq (erc-channel-user-halfop cuser) halfop)))
+             (setq changed t)
+             (setf (erc-channel-user-halfop cuser)
+                   (cond ((eq halfop 'on) t)
+                         ((eq halfop 'off) nil)
+                         (t halfop))))
            (when (and op
                       (not (eq (erc-channel-user-op cuser) op)))
              (setq changed t)
***************
*** 4829,4841 ****
  		  (cond ((eq op 'on) t)
  			((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))))
  	  (when update-message-time
  	    (setf (erc-channel-user-last-message-time cuser) (current-time)))
  	  (setq user-changed
--- 4898,4917 ----
                    (cond ((eq op 'on) t)
                          ((eq op 'off) nil)
                          (t op))))
!           (when (and admin
!                      (not (eq (erc-channel-user-admin cuser) admin)))
              (setq changed t)
!             (setf (erc-channel-user-admin cuser)
!                   (cond ((eq admin 'on) t)
!                         ((eq admin 'off) nil)
!                         (t admin))))
!           (when (and owner
!                      (not (eq (erc-channel-user-owner cuser) owner)))
!             (setq changed t)
!             (setf (erc-channel-user-owner cuser)
!                   (cond ((eq owner 'on) t)
!                         ((eq owner 'off) nil)
!                         (t owner))))
            (when update-message-time
              (setf (erc-channel-user-last-message-time cuser) (current-time)))
            (setq user-changed
***************
*** 4856,4867 ****
  		(cons (current-buffer)
  		      (erc-server-user-buffers user))))
  	(setq cuser (make-erc-channel-user
- 		     :op (cond ((eq op 'on) t)
- 			       ((eq op 'off) nil)
- 			       (t op))
  		     :voice (cond ((eq voice 'on) t)
  				  ((eq voice 'off) nil)
  				  (t voice))
  		     :last-message-time
  		     (if update-message-time (current-time))))
  	(puthash (erc-downcase nick) (cons user cuser)
--- 4932,4952 ----
                  (cons (current-buffer)
                        (erc-server-user-buffers user))))
          (setq cuser (make-erc-channel-user
                       :voice (cond ((eq voice 'on) t)
                                    ((eq voice 'off) nil)
                                    (t voice))
+                      :halfop (cond ((eq halfop 'on) t)
+                                 ((eq halfop 'off) nil)
+                                 (t halfop))
+                      :op (cond ((eq op 'on) t)
+                                ((eq op 'off) nil)
+                                (t op))
+                      :admin (cond ((eq admin 'on) t)
+                                   ((eq admin 'off) nil)
+                                   (t admin))
+                      :owner (cond ((eq owner 'on) t)
+                                   ((eq owner 'off) nil)
+                                   (t owner))
                       :last-message-time
                       (if update-message-time (current-time))))
          (puthash (erc-downcase nick) (cons user cuser)
***************
*** 4872,4878 ****
      (or changed user-changed add)))
  
  (defun erc-update-channel-member (channel nick new-nick
! 				  &optional add op voice host login
  				  full-name info update-message-time)
    "Update user and channel information for the user with
  nickname NICK in channel CHANNEL.
--- 4957,4963 ----
      (or changed user-changed add)))
  
  (defun erc-update-channel-member (channel nick new-nick
!                                           &optional add voice halfop op admin owner host login
                                            full-name info update-message-time)
    "Update user and channel information for the user with
  nickname NICK in channel CHANNEL.
***************
*** 4880,4886 ****
  See also: `erc-update-current-channel-member'."
    (erc-with-buffer
     (channel)
!    (erc-update-current-channel-member nick new-nick add op voice host
  				      login full-name info
  				      update-message-time)))
  
--- 4965,4971 ----
  See also: `erc-update-current-channel-member'."
    (erc-with-buffer
        (channel)
!     (erc-update-current-channel-member nick new-nick add voice halfop op admin owner host
                                         login full-name info
                                         update-message-time)))
  
***************
*** 4979,4985 ****
  	(while chars
  	  (cond ((string= (car chars) "+") (setq add-p t))
  		((string= (car chars) "-") (setq add-p nil))
! 		((string-match "^[ovbOVB]" (car chars))
  		 (setq arg-modes (cons (list (car chars)
  					     (if add-p 'on 'off)
  					     (if args (car args) nil))
--- 5064,5070 ----
          (while chars
            (cond ((string= (car chars) "+") (setq add-p t))
                  ((string= (car chars) "-") (setq add-p nil))
!                 ((string-match "^[qaovhbQAOVHB]" (car chars))
                   (setq arg-modes (cons (list (car chars)
                                               (if add-p 'on 'off)
                                               (if args (car args) nil))
***************
*** 5035,5045 ****
  		 (let ((mode (nth 0 (car arg-modes)))
  		       (onoff (nth 1 (car arg-modes)))
  		       (arg (nth 2 (car arg-modes))))
! 		   (cond ((string-match "^[oO]" mode)
  			  (erc-update-channel-member tgt arg arg nil onoff))
! 			 ((string-match "^[Vv]" mode)
! 			  (erc-update-channel-member tgt arg arg nil nil
! 						     onoff))
  			 ((string-match "^[Ll]" mode)
  			  (erc-update-channel-limit tgt onoff arg))
  			 ((string-match "^[Kk]" mode)
--- 5120,5135 ----
                   (let ((mode (nth 0 (car arg-modes)))
                         (onoff (nth 1 (car arg-modes)))
                         (arg (nth 2 (car arg-modes))))
!                    (cond ((string-match "^[Vv]" mode)
                            (erc-update-channel-member tgt arg arg nil onoff))
!                          ((string-match "^[hH]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil onoff))
!                          ((string-match "^[oO]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil nil onoff))
!                          ((string-match "^[aA]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil nil nil onoff))
!                          ((string-match "^[qQ]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil nil nil nil onoff))
                           ((string-match "^[Ll]" mode)
                            (erc-update-channel-limit tgt onoff arg))
                           ((string-match "^[Kk]" mode)
***************
*** 5978,6003 ****
  	 (user (if channel-data
  		   (car channel-data)
  		 (erc-get-server-user word)))
! 	 host login full-name nick op voice)
      (when user
        (setq nick (erc-server-user-nickname user)
  	    host (erc-server-user-host user)
  	    login (erc-server-user-login user)
  	    full-name (erc-server-user-full-name user))
        (if cuser
! 	  (setq op (erc-channel-user-op cuser)
! 		voice (erc-channel-user-voice cuser)))
        (if (called-interactively-p 'interactive)
  	  (message "%s is %s@%s%s%s"
  		   nick login host
  		   (if full-name (format " (%s)" full-name) "")
! 		   (if (or op voice)
  			       (format " and is +%s%s on %s"
- 			       (if op "o" "")
  			       (if voice "v" "")
  			       (erc-default-target))
  			     ""))
! 	user))))
  
  (defun erc-away-time ()
    "Return non-nil if the current ERC process is set away.
--- 6068,6099 ----
           (user (if channel-data
                     (car channel-data)
                   (erc-get-server-user word)))
!          host login full-name nick voice halfop op admin owner)
      (when user
        (setq nick (erc-server-user-nickname user)
              host (erc-server-user-host user)
              login (erc-server-user-login user)
              full-name (erc-server-user-full-name user))
        (if cuser
!           (setq voice (erc-channel-user-voice cuser)
!                 halfop (erc-channel-user-halfop cuser)
!                 op (erc-channel-user-op cuser)
!                 admin (erc-channel-user-admin cuser)
!                 owner (erc-channel-user-owner cuser))))
      (if (called-interactively-p 'interactive)
          (message "%s is %s@%s%s%s"
                   nick login host
                   (if full-name (format " (%s)" full-name) "")
!                  (if (or voice halfop op admin owner)
                       (format " and is +%s%s on %s"
                               (if voice "v" "")
+                              (if halfop "h" "")
+                              (if op "o" "")
+                              (if admin "a" "")
+                              (if owner "q" "")
                               (erc-default-target))
                     ""))
!       user)))
  
  (defun erc-away-time ()
    "Return non-nil if the current ERC process is set away.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#17755: 24.3; ERC user mode support
  2014-06-18 14:40     ` Kelvin White
@ 2014-06-18 16:08       ` Kelvin White
  2014-06-18 18:32       ` Stefan Monnier
  1 sibling, 0 replies; 8+ messages in thread
From: Kelvin White @ 2014-06-18 16:08 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Lawrence Mitchell, Michael Olson, 17755, Mario Lang, Diane Murray,
	Alex Schroeder, Julien Danjou, Francis Litterio, Jorgen Schaefer


[-- Attachment #1.1: Type: text/plain, Size: 7343 bytes --]

Apologies, I just realized I didn't include the whole patch in the last
submission.
Here is the entire diff.


On Wed, Jun 18, 2014 at 10:40 AM, Kelvin White <kelvin.white77@gmail.com>
wrote:

> > Thanks, here are some comments on it.  I wish someone who has worked on
> > ERC could say something.  I never use(d) IRC and have hence no clue what
> is
> > a "user mode prefix", for example.
>
> A user mode prefix is referring to a symbol prefixed to your nickname to
> display to other users that you have a certain user mode.
> Take "&nickname" for instance. The "&" is the user mode prefix showing you
> have +a (admin) user mode.
>
> > > ***************
> > > *** 1244,1250 ****
> > >                          (erc-format-message
> > >                           'JOIN ?n nick ?u login ?h host ?c chnl))))))
> > >             (when buffer (set-buffer buffer))
> > > !           (erc-update-channel-member chnl nick nick t nil nil host
> login)
> > >             ;; on join, we want to stay in the new channel buffer
> > >             ;;(set-buffer ob)
> > >             (erc-display-message parsed nil buffer str))))))
> > > --- 1244,1250 ----
> > >                          (erc-format-message
> > >                           'JOIN ?n nick ?u login ?h host ?c chnl))))))
> > >             (when buffer (set-buffer buffer))
> > > !           (erc-update-channel-member chnl nick nick t nil nil nil
> nil nil host login)
> > >             ;; on join, we want to stay in the new channel buffer
> > >             ;;(set-buffer ob)
> > >             (erc-display-message parsed nil buffer str))))))
> >
> > In my opinion, erc-update-channel-member had too many arguments already.
> > Maybe some of these args should be combined into an erc-channel-user
> object?
>
> My first approach was to change the erc-channel-user struct to use a list
> of modes,
> eliminating some of the args, but it seemed to cause issues elsewhere.
>  I'll revisit this again soon.
>
> > > + (defsubst erc-channel-user-owner-p (nick)
> > > +   "Return t if NICK is an owner of the current channel."
> >
> > Usually we say "non-nil" rather than "t", unless the callers need to
> > rely on the return value being t rather than some other non-nil value.
>
> Indeed, the callers do rely on the value being t in this case. rather than
> just non-nil
>
> > > + (defface erc-nick-prefix-face '((t :weight bold))
> > > +   "ERC face used for user mode prefix."
> > > +   :group 'erc-faces)
> > > +
> > > + (defface erc-my-nick-prefix-face '((t :weight bold))
> > > +   "ERC face used for my user mode prefix."
> > > +   :group 'erc-faces)
> >
> > Try to use the :inherit property at least to link those two (so users
> > who just want to change the two without making them different only need
> > to change one of the two) and ideally by inheriting from some other face.
>
> Good idea. I have updated this so each of these two faces inherits from
> the appropriate nick faces.
> By default the prefix will be the same color unless these are changed
> individually.
>
> > > + (defun erc-get-user-mode-prefix (user)
> > > +   (when user
> > > +     (cond ((erc-channel-user-voice-p user) "+")
> > > +           ((erc-channel-user-half-op-p user) "%")
> > > +           ((erc-channel-user-op-p user) "@")
> > > +           ((erc-channel-user-admin-p user) "&")
> > > +           ((erc-channel-user-owner-p user) "~")
> > > +           (t ""))))
> >
> > Here I assume there's some kind of logic or convention.  If not, maybe
> > it would be appropriate to do something like add some `help-echo'
> > property to those extra chars?
>
> Sure, I've updated the patch to add help-echo props
>
> > One more thing: the above suggests that maybe
> > voice/halfop/op/admin/owner are mutually exclusive.  Is that the case?
> > Could these be collapsed into a single element which could have values
> > `voice', `halfop', `op', `admin', or `owner' (or nil)?
>
> These are actually not mutually exclusive. A user could have all of these
> modes enabled, but it isn't typical.
> In that case we only want to display the most valuable. If a user has +vo
> we want to display @.
> If a user has +oa we display &. etc. Glad you noticed this though, this
> should check in reverse order.
>
> > >   (defun erc-format-@nick (&optional user channel-data)
> > >     "Format the nickname of USER showing if USER is an operator or has
> voice.
> > >   Operators have \"@\" and users with voice have \"+\" as a prefix.
> > >   Use CHANNEL-DATA to determine op and voice status.
> > >   See also `erc-format-nick-function'."
> > >     (when user
> > > !     (let ((nick (erc-server-user-nickname user)))
> > > !       (concat (erc-propertize (erc-get-user-mode-prefix nick) 'face
> 'erc-nick-prefix-face) nick))))
>
> > Please try to stay with 80 columns.
>
> Ok
>
> > BTW, IIUC, ERC is not distributed separately from Emacs any more, so we
> > don't need to use compatibility crutches like erc-propertize any more
> > (tho it's fine to use it as well for now, and it could be removed "all at
> > once" in another patch).
>
> Good point, I'll clean that up in another patch.
>
> > > !                "(ov)@+"))
> > [...]
> > > !                  "(qaohv)~&@%+"))
>
> >Yay!  Magic!
>
> ;D these are the default user modes
>
> > !   (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)))
> >
> > this should have been
> >
> >      (let* ((prefix (erc-parse-prefix))
> >            (op-ch (cdr (assq ?o prefix)))
> >             (voice-ch (cdr (assq ?v prefix)))
> >             names name op voice)
> >
> > Which is both cleaner and faster.
> >
> > So when you change such code, you can take advantage of the change to
> > try and reduce occurrences of those "let-without-init followed by setq".
>
> This has been updated, thanks.
>
> > This also makes it sound like those op/voice/admin/owner are mutually
> > exclusive and should be combined into a single element.
>
> > Otherwise, please simplify the code with:
>
> >   (setq op 'off voice 'off halfop 'off admin 'off owner 'off)
> >   (cond
> >    ((eq (elt item 0) voice-ch)
> >     (setq name (substring item 1)
> >           voice 'on))
> >    [...])
>
> Yes, I agree. I have simplified it.
>
> > > +           (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))))
> >
> > Won't this cause `changed' to "always" be set to t, since
> > (erc-channel-user-voice cuser) will never be `on' or `off' and hence
> > never be equal to `voice'?
>
> > Also, instead of using on/off and converting them from&to nil/t, maybe
> > it would be simpler to use nil/t plus a special value
> > (e.g. `:unspecified') for the case where the value is simply
> > not provided.
>
> Sure, I will look at revising this in a separate patch. I tried to keep
> this as simple
> as possible but I have noticed things like this and others that could be
> simplified
> and cleaned up a bit.
>
> Attached is the new patch cleaned up per your suggestions.
>
> Thanks
>
>

[-- Attachment #1.2: Type: text/html, Size: 11207 bytes --]

[-- Attachment #2: erc-patch.diff --]
[-- Type: text/plain, Size: 30179 bytes --]

diff --ignore-space-change -c '-F^[_a-zA-Z0-9$]+ *(' projects/emacs/lisp/erc/ChangeLog projects/emacs-dev/lisp/erc/ChangeLog
*** projects/emacs/lisp/erc/ChangeLog	2014-06-13 10:21:10.232494842 -0400
--- projects/emacs-dev/lisp/erc/ChangeLog	2014-06-18 12:06:37.222399565 -0400
***************
*** 1,3 ****
--- 1,15 ----
+ 2014-06-11  Kelvin White  <kelvin.white77@gmail.com>
+ 
+ 	* erc-backend.el: Handle user modes in relevent server responses
+ 	* erc.el: Better user mode support.
+ 	(erc-channel-user): Add members for new modes.
+ 	(erc-channel-member-halfop-p, erc-channel-user-admin-p, erc-channel-user-owner-p): Use new struct members.
+ 	(erc-format-nick, erc-format-@nick): Display user modes as nick prefix.
+ 	(erc-nick-prefix-face, erc-my-nick-prefix-face): Add new faces to separate colors if desired.
+ 	(erc-get-user-mode-prefix): Return symbol for mode prefix.
+ 	(erc-update-channel-member, erc-update-current-channel-member, erc-channel-receive-names): Update channel users.
+ 	(erc-nick-at-point): Return correct user info.
+ 
  2014-04-04  Stefan Monnier  <monnier@iro.umontreal.ca>
  
  	* erc.el (erc-invite-only-mode, erc-toggle-channel-mode): Simplify.
***************
*** 615,618 ****
  ;; coding: utf-8
  ;; add-log-time-zone-rule: t
  ;; End:
- 
--- 627,629 ----
diff --ignore-space-change -c '-F^[_a-zA-Z0-9$]+ *(' projects/emacs/lisp/erc/erc-backend.el projects/emacs-dev/lisp/erc/erc-backend.el
*** projects/emacs/lisp/erc/erc-backend.el	2014-06-13 10:21:10.235828074 -0400
--- projects/emacs-dev/lisp/erc/erc-backend.el	2014-06-18 12:04:21.716635854 -0400
***************
*** 5,11 ****
  ;; Filename: erc-backend.el
  ;; Author: Lawrence Mitchell <wence@gmx.li>
  ;; Maintainer: emacs-devel@gnu.org
! ;; Created: 2004-05-7
  ;; Keywords: IRC chat client internet
  
  ;; This file is part of GNU Emacs.
--- 5,13 ----
  ;; Filename: erc-backend.el
  ;; Author: Lawrence Mitchell <wence@gmx.li>
  ;; Maintainer: emacs-devel@gnu.org
! ;; Hacker: l3thal@smashthestack.org
! ;; Created: 2004-05-07
! ;; Hacked: 2014-06-08
  ;; Keywords: IRC chat client internet
  
  ;; This file is part of GNU Emacs.
***************
*** 1208,1216 ****
           parsed 'notice 'active
           'INVITE ?n nick ?u login ?h host ?c chnl)))))
  
! 
  (define-erc-response-handler (JOIN)
!   "Handle join messages."
    nil
    (let ((chnl (erc-response.contents parsed))
          (buffer nil))
--- 1210,1218 ----
           parsed 'notice 'active
           'INVITE ?n nick ?u login ?h host ?c chnl)))))
  
! ;;; hacked
  (define-erc-response-handler (JOIN)
!   "HACKED: Handle join messages."
    nil
    (let ((chnl (erc-response.contents parsed))
          (buffer nil))
***************
*** 1244,1250 ****
                         (erc-format-message
                          'JOIN ?n nick ?u login ?h host ?c chnl))))))
            (when buffer (set-buffer buffer))
!           (erc-update-channel-member chnl nick nick t nil nil host login)
            ;; on join, we want to stay in the new channel buffer
            ;;(set-buffer ob)
            (erc-display-message parsed nil buffer str))))))
--- 1246,1252 ----
                         (erc-format-message
                          'JOIN ?n nick ?u login ?h host ?c chnl))))))
            (when buffer (set-buffer buffer))
!           (erc-update-channel-member chnl nick nick t nil nil nil nil nil host login)
            ;; on join, we want to stay in the new channel buffer
            ;;(set-buffer ob)
            (erc-display-message parsed nil buffer str))))))
***************
*** 1385,1392 ****
           ?s (if (/= erc-server-lag 1) "s" "")))
        (erc-update-mode-line))))
  
  (define-erc-response-handler (PRIVMSG NOTICE)
!   "Handle private messages, including messages in channels." nil
    (let ((sender-spec (erc-response.sender parsed))
          (cmd (erc-response.command parsed))
          (tgt (car (erc-response.command-args parsed)))
--- 1387,1395 ----
           ?s (if (/= erc-server-lag 1) "s" "")))
        (erc-update-mode-line))))
  
+ ;;; hacked
  (define-erc-response-handler (PRIVMSG NOTICE)
!   "HACKED: Handle private messages, including messages in channels." nil
    (let ((sender-spec (erc-response.sender parsed))
          (cmd (erc-response.command parsed))
          (tgt (car (erc-response.command-args parsed)))
***************
*** 1413,1419 ****
              ;; message.  We will accumulate private identities indefinitely
              ;; at this point.
              (erc-update-channel-member (if privp nick tgt) nick nick
!                                        privp nil nil host login nil nil t)
              (let ((cdata (erc-get-channel-user nick)))
                (setq fnick (funcall erc-format-nick-function
                                     (car cdata) (cdr cdata))))))
--- 1416,1422 ----
              ;; message.  We will accumulate private identities indefinitely
              ;; at this point.
              (erc-update-channel-member (if privp nick tgt) nick nick
!                                        privp nil nil nil nil nil host login nil nil t)
              (let ((cdata (erc-get-channel-user nick)))
                (setq fnick (funcall erc-format-nick-function
                                     (car cdata) (cdr cdata))))))
***************
*** 1461,1476 ****
        (erc-display-message parsed 'notice bufs
                             'QUIT ?n nick ?u login
                             ?h host ?r reason))))
! 
  (define-erc-response-handler (TOPIC)
!   "The channel topic has changed." nil
    (let* ((ch (car (erc-response.command-args parsed)))
           (topic (erc-trim-string (erc-response.contents parsed)))
           (time (format-time-string erc-server-timestamp-format
                                     (current-time))))
      (pcase-let ((`(,nick ,login ,host)
                   (erc-parse-user (erc-response.sender parsed))))
!       (erc-update-channel-member ch nick nick nil nil nil host login)
        (erc-update-channel-topic ch (format "%s\C-o (%s, %s)" topic nick time))
        (erc-display-message parsed 'notice (erc-get-buffer ch proc)
                             'TOPIC ?n nick ?u login ?h host
--- 1464,1479 ----
        (erc-display-message parsed 'notice bufs
                             'QUIT ?n nick ?u login
                             ?h host ?r reason))))
! ;;; hacked
  (define-erc-response-handler (TOPIC)
!   "HACKED: The channel topic has changed." nil
    (let* ((ch (car (erc-response.command-args parsed)))
           (topic (erc-trim-string (erc-response.contents parsed)))
           (time (format-time-string erc-server-timestamp-format
                                     (current-time))))
      (pcase-let ((`(,nick ,login ,host)
                   (erc-parse-user (erc-response.sender parsed))))
!       (erc-update-channel-member ch nick nick nil nil nil nil nil nil host login)
        (erc-update-channel-topic ch (format "%s\C-o (%s, %s)" topic nick time))
        (erc-display-message parsed 'notice (erc-get-buffer ch proc)
                             'TOPIC ?n nick ?u login ?h host
***************
*** 1791,1798 ****
      (erc-display-message parsed 'notice (erc-get-buffer channel proc)
                           's341 ?n nick ?c channel)))
  
  (define-erc-response-handler (352)
!   "WHO notice." nil
    (pcase-let ((`(,channel ,user ,host ,server ,nick ,away-flag)
                 (cdr (erc-response.command-args parsed))))
      (let ((full-name (erc-response.contents parsed))
--- 1794,1802 ----
      (erc-display-message parsed 'notice (erc-get-buffer channel proc)
                           's341 ?n nick ?c channel)))
  
+ ;;; hacked
  (define-erc-response-handler (352)
!   "HACKED: WHO notice." nil
    (pcase-let ((`(,channel ,user ,host ,server ,nick ,away-flag)
                 (cdr (erc-response.command-args parsed))))
      (let ((full-name (erc-response.contents parsed))
***************
*** 1800,1807 ****
        (when (string-match "\\(^[0-9]+ \\)\\(.*\\)$" full-name)
          (setq hopcount (match-string 1 full-name))
          (setq full-name (match-string 2 full-name)))
!       (erc-update-channel-member channel nick nick nil nil nil host
!                                  user full-name)
        (erc-display-message parsed 'notice 'active 's352
                             ?c channel ?n nick ?a away-flag
                             ?u user ?h host ?f full-name))))
--- 1804,1810 ----
        (when (string-match "\\(^[0-9]+ \\)\\(.*\\)$" full-name)
          (setq hopcount (match-string 1 full-name))
          (setq full-name (match-string 2 full-name)))
!       (erc-update-channel-member channel nick nick nil nil nil nil nil nil host user full-name)
        (erc-display-message parsed 'notice 'active 's352
                             ?c channel ?n nick ?a away-flag
                             ?u user ?h host ?f full-name))))
diff --ignore-space-change -c '-F^[_a-zA-Z0-9$]+ *(' projects/emacs/lisp/erc/erc.el projects/emacs-dev/lisp/erc/erc.el
*** projects/emacs/lisp/erc/erc.el	2014-06-18 10:08:15.639519157 -0400
--- projects/emacs-dev/lisp/erc/erc.el	2014-06-18 10:15:41.395718554 -0400
***************
*** 370,376 ****
    )
  
  (cl-defstruct (erc-channel-user (:type vector) :named)
!   op voice
    ;; Last message time (in the form of the return value of
    ;; (current-time)
    ;;
--- 370,376 ----
    )
  
  (cl-defstruct (erc-channel-user (:type vector) :named)
!   voice halfop op admin owner
    ;; Last message time (in the form of the return value of
    ;; (current-time)
    ;;
***************
*** 475,480 ****
--- 475,496 ----
               erc-channel-users)
      (clrhash erc-channel-users)))
  
+ (defsubst erc-channel-user-owner-p (nick)
+   "Return t if NICK is an owner of the current channel."
+   (and nick
+        (hash-table-p erc-channel-users)
+        (let ((cdata (erc-get-channel-user nick)))
+          (and cdata (cdr cdata)
+               (erc-channel-user-owner (cdr cdata))))))
+ 
+ (defsubst erc-channel-user-admin-p (nick)
+   "Return t if NICK is an admin in the current channel."
+   (and nick
+        (hash-table-p erc-channel-users)
+        (let ((cdata (erc-get-channel-user nick)))
+          (and cdata (cdr cdata)
+               (erc-channel-user-admin (cdr cdata))))))
+ 
  (defsubst erc-channel-user-op-p (nick)
    "Return t if NICK is an operator in the current channel."
    (and nick
***************
*** 483,488 ****
--- 499,512 ----
           (and cdata (cdr cdata)
                (erc-channel-user-op (cdr cdata))))))
  
+ (defsubst erc-channel-user-halfop-p (nick)
+   "Return t if NICK is a half-operator in the current channel."
+   (and nick
+        (hash-table-p erc-channel-users)
+        (let ((cdata (erc-get-channel-user nick)))
+          (and cdata (cdr cdata)
+               (erc-channel-user-halfop (cdr cdata))))))
+ 
  (defsubst erc-channel-user-voice-p (nick)
    "Return t if NICK has voice in the current channel."
    (and nick
***************
*** 1122,1127 ****
--- 1146,1159 ----
    "ERC default face."
    :group 'erc-faces)
  
+ (defface erc-nick-prefix-face '((t :inherit erc-nick-default-face :weight bold))
+   "ERC face used for user mode prefix."
+   :group 'erc-faces)
+ 
+ (defface erc-my-nick-prefix-face '((t :inherit erc-my-nick-face :weight bold))
+   "ERC face used for my user mode prefix."
+   :group 'erc-faces)
+ 
  (defface erc-direct-msg-face '((t :foreground "IndianRed"))
    "ERC face used for messages you receive in the main erc buffer."
    :group 'erc-faces)
***************
*** 4190,4196 ****
  (defun erc-format-nick (&optional user _channel-data)
    "Return the nickname of USER.
  See also `erc-format-nick-function'."
!   (when user (erc-server-user-nickname user)))
  
  (defun erc-format-@nick (&optional user channel-data)
    "Format the nickname of USER showing if USER is an operator or has voice.
--- 4222,4245 ----
  (defun erc-format-nick (&optional user _channel-data)
    "Return the nickname of USER.
  See also `erc-format-nick-function'."
!   (let ((nick (erc-server-user-nickname user)))
!     (concat (erc-propertize
!              (erc-get-user-mode-prefix nick)
!              'face 'erc-nick-prefix-face) nick)))
! 
! (defun erc-get-user-mode-prefix (user)
!   (when user
!     (cond ((erc-channel-user-owner-p user)
!            (propertize "~" 'help-echo "owner"))
!           ((erc-channel-user-admin-p user)
!            (propertize "&" 'help-echo "admin"))
!           ((erc-channel-user-op-p user)
!            (propertize "@" 'help-echo "operator"))
!           ((erc-channel-user-halfop-p user)
!            (propertize "%" 'help-echo "half-op"))
!           ((erc-channel-user-voice-p user)
!            propertize "+" 'help-echo "voice")
!           (t ""))))
  
  (defun erc-format-@nick (&optional user channel-data)
    "Format the nickname of USER showing if USER is an operator or has voice.
***************
*** 4198,4215 ****
  Use CHANNEL-DATA to determine op and voice status.
  See also `erc-format-nick-function'."
    (when user
!     (let ((op (and channel-data (erc-channel-user-op channel-data) "@"))
! 	  (voice (and channel-data (erc-channel-user-voice channel-data) "+")))
!       (concat voice op (erc-server-user-nickname user)))))
  
  (defun erc-format-my-nick ()
    "Return the beginning of this user's message, correctly propertized."
    (if erc-show-my-nick
!       (let ((open "<")
  	    (close "> ")
! 	    (nick (erc-current-nick)))
  	(concat
  	 (erc-propertize open 'face 'erc-default-face)
  	 (erc-propertize nick 'face 'erc-my-nick-face)
  	 (erc-propertize close 'face 'erc-default-face)))
      (let ((prefix "> "))
--- 4247,4267 ----
  Use CHANNEL-DATA to determine op and voice status.
  See also `erc-format-nick-function'."
    (when user
!     (let ((nick (erc-server-user-nickname user)))
!       (concat (erc-propertize
!                (erc-get-user-mode-prefix nick)
!                'face 'erc-nick-prefix-face) nick nick))))
  
  (defun erc-format-my-nick ()
    "Return the beginning of this user's message, correctly propertized."
    (if erc-show-my-nick
!       (let* ((open "<")
               (close "> ")
!              (nick (erc-current-nick))
!              (mode (erc-get-user-mode-prefix nick)))
          (concat
           (erc-propertize open 'face 'erc-default-face)
+          (erc-propertize mode 'face 'erc-my-nick-prefix-face)
           (erc-propertize nick 'face 'erc-my-nick-face)
           (erc-propertize close 'face 'erc-default-face)))
      (let ((prefix "> "))
***************
*** 4685,4691 ****
    (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)
--- 4737,4743 ----
    (let ((str (or (cdr (assoc "PREFIX" (erc-with-server-buffer
                                          erc-server-parameters)))
                   ;; provide a sane default
!                  "(qaohv)~&@%+"))
          types chars)
      (when (string-match "^(\\([^)]+\\))\\(.+\\)$" str)
        (setq types (match-string 1 str)
***************
*** 4705,4744 ****
  Update `erc-channel-users' according to NAMES-STRING.
  NAMES-STRING is a string listing some of the names on the
  channel."
!   (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))
  	  (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
    "This hook is called every time the variable `channel-members' changes.
  The buffer where the change happened is current while this hook is called."
--- 4757,4800 ----
  Update `erc-channel-users' according to NAMES-STRING.
  NAMES-STRING is a string listing some of the names on the
  channel."
!   (let* ((prefix (erc-parse-prefix))
!          (op-ch (cdr (assq ?o prefix)))
!          (voice-ch (cdr (assq ?v prefix)))
!          (adm-ch (cdr (assq ?a prefix)))
!          (own-ch (cdr (assq ?q prefix)))
!          names name op voice halfop admin owner)
      (setq names (delete "" (split-string names-string)))
      (let ((erc-channel-members-changed-hook nil))
        (dolist (item names)
          (let ((updatep t))
+           (setq name item op 'off voice 'off halfop 'off admin 'off owner 'off)
            (if (rassq (elt item 0) prefix)
                (cond ((= (length item) 1)
                       (setq updatep nil))
                      ((eq (elt item 0) voice-ch)
                       (setq name (substring item 1)
                             voice 'on))
!                     ((eq (elt item 0) hop-ch)
!                      (setq name (substring item 1)
!                            halfop 'on))
!                     ((eq (elt item 0) op-ch)
!                      (setq name (substring item 1)
!                            op 'on))
!                     ((eq (elt item 0) adm-ch)
!                      (setq name (substring item 1)
!                            admin 'on))
!                     ((eq (elt item 0) own-ch)
!                      (setq name (substring item 1)
!                            owner 'on))
!                     (t (setq name (substring item 1)))))
            (when updatep
              (puthash (erc-downcase name) t
                       erc-channel-new-member-names)
              (erc-update-current-channel-member
!              name name t voice halfop op admin owner)))))
      (run-hooks 'erc-channel-members-changed-hook)))
  
+ 
  (defcustom erc-channel-members-changed-hook nil
    "This hook is called every time the variable `channel-members' changes.
  The buffer where the change happened is current while this hook is called."
***************
*** 4795,4810 ****
      changed))
  
  (defun erc-update-current-channel-member
!   (nick new-nick &optional add op voice host login full-name info
  	update-message-time)
    "Update the stored user information for the user with nickname NICK.
  `erc-update-user' is called to handle changes to nickname,
! HOST, LOGIN, FULL-NAME, and INFO.  If OP or VOICE are non-nil,
! they must be equal to either `on' or `off', in which case the
! operator or voice status of the user in the current channel is
! changed accordingly.  If UPDATE-MESSAGE-TIME is non-nil, the
! last-message-time of the user in the current channel is set
! to (current-time).
  
  If ADD is non-nil, the user will be added with the specified
  information if it is not already present in the user or channel
--- 4851,4865 ----
      changed))
  
  (defun erc-update-current-channel-member
!   (nick new-nick &optional add voice halfop op admin owner host login full-name info
          update-message-time)
    "Update the stored user information for the user with nickname NICK.
  `erc-update-user' is called to handle changes to nickname,
! HOST, LOGIN, FULL-NAME, and INFO.  If VOICE HALFOP OP ADMIN or OWNER
! are non-nil, they must be equal to either `on' or `off', in which
! case the status of the user in the current channel is changed accordingly.
! If UPDATE-MESSAGE-TIME is non-nil, the last-message-time of the user
!  in the current channel is set to (current-time).
  
  If ADD is non-nil, the user will be added with the specified
  information if it is not already present in the user or channel
***************
*** 4822,4827 ****
--- 4877,4896 ----
      (if cuser
          (progn
            (erc-log (format "update-member: user = %S, cuser = %S" user cuser))
+           (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))))
+           (when (and halfop
+                      (not (eq (erc-channel-user-halfop cuser) halfop)))
+             (setq changed t)
+             (setf (erc-channel-user-halfop cuser)
+                   (cond ((eq halfop 'on) t)
+                         ((eq halfop 'off) nil)
+                         (t halfop))))
            (when (and op
                       (not (eq (erc-channel-user-op cuser) op)))
              (setq changed t)
***************
*** 4829,4841 ****
  		  (cond ((eq op 'on) t)
  			((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))))
  	  (when update-message-time
  	    (setf (erc-channel-user-last-message-time cuser) (current-time)))
  	  (setq user-changed
--- 4898,4917 ----
                    (cond ((eq op 'on) t)
                          ((eq op 'off) nil)
                          (t op))))
!           (when (and admin
!                      (not (eq (erc-channel-user-admin cuser) admin)))
              (setq changed t)
!             (setf (erc-channel-user-admin cuser)
!                   (cond ((eq admin 'on) t)
!                         ((eq admin 'off) nil)
!                         (t admin))))
!           (when (and owner
!                      (not (eq (erc-channel-user-owner cuser) owner)))
!             (setq changed t)
!             (setf (erc-channel-user-owner cuser)
!                   (cond ((eq owner 'on) t)
!                         ((eq owner 'off) nil)
!                         (t owner))))
            (when update-message-time
              (setf (erc-channel-user-last-message-time cuser) (current-time)))
            (setq user-changed
***************
*** 4856,4867 ****
  		(cons (current-buffer)
  		      (erc-server-user-buffers user))))
  	(setq cuser (make-erc-channel-user
- 		     :op (cond ((eq op 'on) t)
- 			       ((eq op 'off) nil)
- 			       (t op))
  		     :voice (cond ((eq voice 'on) t)
  				  ((eq voice 'off) nil)
  				  (t voice))
  		     :last-message-time
  		     (if update-message-time (current-time))))
  	(puthash (erc-downcase nick) (cons user cuser)
--- 4932,4952 ----
                  (cons (current-buffer)
                        (erc-server-user-buffers user))))
          (setq cuser (make-erc-channel-user
                       :voice (cond ((eq voice 'on) t)
                                    ((eq voice 'off) nil)
                                    (t voice))
+                      :halfop (cond ((eq halfop 'on) t)
+                                 ((eq halfop 'off) nil)
+                                 (t halfop))
+                      :op (cond ((eq op 'on) t)
+                                ((eq op 'off) nil)
+                                (t op))
+                      :admin (cond ((eq admin 'on) t)
+                                   ((eq admin 'off) nil)
+                                   (t admin))
+                      :owner (cond ((eq owner 'on) t)
+                                   ((eq owner 'off) nil)
+                                   (t owner))
                       :last-message-time
                       (if update-message-time (current-time))))
          (puthash (erc-downcase nick) (cons user cuser)
***************
*** 4872,4878 ****
      (or changed user-changed add)))
  
  (defun erc-update-channel-member (channel nick new-nick
! 				  &optional add op voice host login
  				  full-name info update-message-time)
    "Update user and channel information for the user with
  nickname NICK in channel CHANNEL.
--- 4957,4963 ----
      (or changed user-changed add)))
  
  (defun erc-update-channel-member (channel nick new-nick
!                                           &optional add voice halfop op admin owner host login
                                            full-name info update-message-time)
    "Update user and channel information for the user with
  nickname NICK in channel CHANNEL.
***************
*** 4880,4886 ****
  See also: `erc-update-current-channel-member'."
    (erc-with-buffer
     (channel)
!    (erc-update-current-channel-member nick new-nick add op voice host
  				      login full-name info
  				      update-message-time)))
  
--- 4965,4971 ----
  See also: `erc-update-current-channel-member'."
    (erc-with-buffer
        (channel)
!     (erc-update-current-channel-member nick new-nick add voice halfop op admin owner host
                                         login full-name info
                                         update-message-time)))
  
***************
*** 4979,4985 ****
  	(while chars
  	  (cond ((string= (car chars) "+") (setq add-p t))
  		((string= (car chars) "-") (setq add-p nil))
! 		((string-match "^[ovbOVB]" (car chars))
  		 (setq arg-modes (cons (list (car chars)
  					     (if add-p 'on 'off)
  					     (if args (car args) nil))
--- 5064,5070 ----
          (while chars
            (cond ((string= (car chars) "+") (setq add-p t))
                  ((string= (car chars) "-") (setq add-p nil))
!                 ((string-match "^[qaovhbQAOVHB]" (car chars))
                   (setq arg-modes (cons (list (car chars)
                                               (if add-p 'on 'off)
                                               (if args (car args) nil))
***************
*** 5035,5045 ****
  		 (let ((mode (nth 0 (car arg-modes)))
  		       (onoff (nth 1 (car arg-modes)))
  		       (arg (nth 2 (car arg-modes))))
! 		   (cond ((string-match "^[oO]" mode)
  			  (erc-update-channel-member tgt arg arg nil onoff))
! 			 ((string-match "^[Vv]" mode)
! 			  (erc-update-channel-member tgt arg arg nil nil
! 						     onoff))
  			 ((string-match "^[Ll]" mode)
  			  (erc-update-channel-limit tgt onoff arg))
  			 ((string-match "^[Kk]" mode)
--- 5120,5135 ----
                   (let ((mode (nth 0 (car arg-modes)))
                         (onoff (nth 1 (car arg-modes)))
                         (arg (nth 2 (car arg-modes))))
!                    (cond ((string-match "^[Vv]" mode)
                            (erc-update-channel-member tgt arg arg nil onoff))
!                          ((string-match "^[hH]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil onoff))
!                          ((string-match "^[oO]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil nil onoff))
!                          ((string-match "^[aA]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil nil nil onoff))
!                          ((string-match "^[qQ]" mode)
!                           (erc-update-channel-member tgt arg arg nil nil nil nil nil onoff))
                           ((string-match "^[Ll]" mode)
                            (erc-update-channel-limit tgt onoff arg))
                           ((string-match "^[Kk]" mode)
***************
*** 5978,6003 ****
  	 (user (if channel-data
  		   (car channel-data)
  		 (erc-get-server-user word)))
! 	 host login full-name nick op voice)
      (when user
        (setq nick (erc-server-user-nickname user)
  	    host (erc-server-user-host user)
  	    login (erc-server-user-login user)
  	    full-name (erc-server-user-full-name user))
        (if cuser
! 	  (setq op (erc-channel-user-op cuser)
! 		voice (erc-channel-user-voice cuser)))
        (if (called-interactively-p 'interactive)
  	  (message "%s is %s@%s%s%s"
  		   nick login host
  		   (if full-name (format " (%s)" full-name) "")
! 		   (if (or op voice)
  			       (format " and is +%s%s on %s"
- 			       (if op "o" "")
  			       (if voice "v" "")
  			       (erc-default-target))
  			     ""))
! 	user))))
  
  (defun erc-away-time ()
    "Return non-nil if the current ERC process is set away.
--- 6068,6099 ----
           (user (if channel-data
                     (car channel-data)
                   (erc-get-server-user word)))
!          host login full-name nick voice halfop op admin owner)
      (when user
        (setq nick (erc-server-user-nickname user)
              host (erc-server-user-host user)
              login (erc-server-user-login user)
              full-name (erc-server-user-full-name user))
        (if cuser
!           (setq voice (erc-channel-user-voice cuser)
!                 halfop (erc-channel-user-halfop cuser)
!                 op (erc-channel-user-op cuser)
!                 admin (erc-channel-user-admin cuser)
!                 owner (erc-channel-user-owner cuser))))
      (if (called-interactively-p 'interactive)
          (message "%s is %s@%s%s%s"
                   nick login host
                   (if full-name (format " (%s)" full-name) "")
!                  (if (or voice halfop op admin owner)
                       (format " and is +%s%s on %s"
                               (if voice "v" "")
+                              (if halfop "h" "")
+                              (if op "o" "")
+                              (if admin "a" "")
+                              (if owner "q" "")
                               (erc-default-target))
                     ""))
!       user)))
  
  (defun erc-away-time ()
    "Return non-nil if the current ERC process is set away.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#17755: 24.3; ERC user mode support
  2014-06-18 14:40     ` Kelvin White
  2014-06-18 16:08       ` Kelvin White
@ 2014-06-18 18:32       ` Stefan Monnier
  2014-06-18 18:51         ` Kelvin White
  1 sibling, 1 reply; 8+ messages in thread
From: Stefan Monnier @ 2014-06-18 18:32 UTC (permalink / raw)
  To: Kelvin White
  Cc: Lawrence Mitchell, Michael Olson, 17755, Mario Lang, Diane Murray,
	Alex Schroeder, Julien Danjou, Francis Litterio, Jorgen Schaefer

>> > + (defsubst erc-channel-user-owner-p (nick)
>> > +   "Return t if NICK is an owner of the current channel."
>> Usually we say "non-nil" rather than "t", unless the callers need to
>> rely on the return value being t rather than some other non-nil value.
> Indeed, the callers do rely on the value being t in this case. rather than
> just non-nil

Hmm?  I see only one call to erc-channel-user-owner-p and the result is
passed to `cond' so any non-nil value will work as well (which is the
way it should be for functions named `<foo>-p').

> + 2014-06-11  Kelvin White  <kelvin.white77@gmail.com>
> + 
> + 	* erc-backend.el: Handle user modes in relevent server responses
> + 	* erc.el: Better user mode support.
> + 	(erc-channel-user): Add members for new modes.
> + 	(erc-channel-member-halfop-p, erc-channel-user-admin-p, erc-channel-user-owner-p): Use new struct members.
> + 	(erc-format-nick, erc-format-@nick): Display user modes as nick prefix.
> + 	(erc-nick-prefix-face, erc-my-nick-prefix-face): Add new faces to separate colors if desired.
> + 	(erc-get-user-mode-prefix): Return symbol for mode prefix.
> + 	(erc-update-channel-member, erc-update-current-channel-member, erc-channel-receive-names): Update channel users.
> + 	(erc-nick-at-point): Return correct user info.
> + 

Please try a bit harder to stay within 80 columns.  M-q is your friend.

> ! ;; Hacker: l3thal@smashthestack.org
> ! ;; Created: 2004-05-07
> ! ;; Hacked: 2014-06-08

If you want to add your name, add it to the "Author:" part (one per
line, see in erc.el for an example).  And don't add entries like
timestamps of when it was last changed.  This just causes spurious
conflicts when merging branches.  This info is readily available via
"bzr log".  I tolerate things like "Created" (tho find it a waste of
perfectly good bits and screen real estate) because, by nature these
should never change and hence don't cause such spurious conflicts.

> ! ;;; hacked
>   (define-erc-response-handler (JOIN)
> !   "HACKED: Handle join messages."

What does this "hacked" mean here?  Looks like left-over annotations you
used temporarily to keep track of what you changed.

Anyway, the patch looks OK to me.  As soon as your copyright paperwork
comes through I can give you write access and you can install it.


        Stefan





^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#17755: 24.3; ERC user mode support
  2014-06-18 18:32       ` Stefan Monnier
@ 2014-06-18 18:51         ` Kelvin White
  0 siblings, 0 replies; 8+ messages in thread
From: Kelvin White @ 2014-06-18 18:51 UTC (permalink / raw)
  To: Stefan Monnier
  Cc: Lawrence Mitchell, Michael Olson, 17755, Mario Lang, Diane Murray,
	Alex Schroeder, Kelvin White, Julien Danjou, Francis Litterio,
	Jorgen Schaefer

At Wed, 18 Jun 2014 14:32:09 -0400,
Stefan Monnier wrote:
> 
> >> > + (defsubst erc-channel-user-owner-p (nick)
> >> > +   "Return t if NICK is an owner of the current channel."
> >> Usually we say "non-nil" rather than "t", unless the callers need to
> >> rely on the return value being t rather than some other non-nil value.
> > Indeed, the callers do rely on the value being t in this case. rather than
> > just non-nil
> 
> Hmm?  I see only one call to erc-channel-user-owner-p and the result is
> passed to `cond' so any non-nil value will work as well (which is the
> way it should be for functions named `<foo>-p').
> 
You are right, this could be non-nil. I was looking at
`erc-channel-user-owner' not the predicate form
`erc-channel-user-owner-p'.
> > + 2014-06-11  Kelvin White  <kelvin.white77@gmail.com>
> > + 
> > + 	* erc-backend.el: Handle user modes in relevent server responses
> > + 	* erc.el: Better user mode support.
> > + 	(erc-channel-user): Add members for new modes.
> > + 	(erc-channel-member-halfop-p, erc-channel-user-admin-p, erc-channel-user-owner-p): Use new struct members.
> > + 	(erc-format-nick, erc-format-@nick): Display user modes as nick prefix.
> > + 	(erc-nick-prefix-face, erc-my-nick-prefix-face): Add new faces to separate colors if desired.
> > + 	(erc-get-user-mode-prefix): Return symbol for mode prefix.
> > + 	(erc-update-channel-member, erc-update-current-channel-member, erc-channel-receive-names): Update channel users.
> > + 	(erc-nick-at-point): Return correct user info.
> > + 
> 
Ah yes, I did change the rest of the code to under 80 columns, but it
looks like I missed the changelog. Sorry, it's been one of those days.
> Please try a bit harder to stay within 80 columns.  M-q is your friend.
> 
> > ! ;; Hacker: l3thal@smashthestack.org
> > ! ;; Created: 2004-05-07
> > ! ;; Hacked: 2014-06-08
> 
This and the next comment slipped my me on mistake. 
This was for my own use to track revisions as It wasn't in version control.
It should not have been included in the patch 
> If you want to add your name, add it to the "Author:" part (one per
> line, see in erc.el for an example).  And don't add entries like
> timestamps of when it was last changed.  This just causes spurious
> conflicts when merging branches.  This info is readily available via
> "bzr log".  I tolerate things like "Created" (tho find it a waste of
> perfectly good bits and screen real estate) because, by nature these
> should never change and hence don't cause such spurious conflicts.
> 
> > ! ;;; hacked
> >   (define-erc-response-handler (JOIN)
> > !   "HACKED: Handle join messages."
> 
> What does this "hacked" mean here?  Looks like left-over annotations you
> used temporarily to keep track of what you changed.
This was a mistake, please see above.
> 
> Anyway, the patch looks OK to me.  As soon as your copyright paperwork
> comes through I can give you write access and you can install it.
> 
> 
>         Stefan





^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#17755: 24.3; ERC user mode support
  2014-06-11 10:34 bug#17755: 24.3; ERC user mode support kelvin.white77
  2014-06-11 11:45 ` Kelvin White
@ 2014-10-02 19:31 ` Paul Eggert
  1 sibling, 0 replies; 8+ messages in thread
From: Paul Eggert @ 2014-10-02 19:31 UTC (permalink / raw)
  To: Kelvin White; +Cc: 17755

[-- Attachment #1: Type: text/plain, Size: 109 bytes --]

I found a typo in that patch and installed the attached further minor 
patch to fix it, as trunk bzr 118017.

[-- Attachment #2: erc.diff --]
[-- Type: text/x-patch, Size: 938 bytes --]

=== modified file 'lisp/erc/ChangeLog'
--- lisp/erc/ChangeLog	2014-10-02 11:55:22 +0000
+++ lisp/erc/ChangeLog	2014-10-02 19:27:33 +0000
@@ -1,3 +1,7 @@
+2014-10-02  Paul Eggert  <eggert@cs.ucla.edu>
+
+	* erc.el (erc-nick-at-point): Fix format-string typo (Bug#17755).
+
 2014-10-02  Kelvin White  <kwhite@gnu.org>
 
 	* erc.el (erc-rename-buffer-p): When set to t buffers will be

=== modified file 'lisp/erc/erc.el'
--- lisp/erc/erc.el	2014-10-02 11:55:22 +0000
+++ lisp/erc/erc.el	2014-10-02 19:27:04 +0000
@@ -6082,7 +6082,7 @@
                  nick login host
                  (if full-name (format " (%s)" full-name) "")
                  (if (or voice halfop op admin owner)
-                     (format " and is +%s%s on %s"
+                     (format " and is +%s%s%s%s%s on %s"
                              (if voice "v" "")
                              (if halfop "h" "")
                              (if op "o" "")


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-10-02 19:31 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-11 10:34 bug#17755: 24.3; ERC user mode support kelvin.white77
2014-06-11 11:45 ` Kelvin White
2014-06-17 16:03   ` Stefan Monnier
2014-06-18 14:40     ` Kelvin White
2014-06-18 16:08       ` Kelvin White
2014-06-18 18:32       ` Stefan Monnier
2014-06-18 18:51         ` Kelvin White
2014-10-02 19:31 ` Paul Eggert

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).