ErcNickColors

The easiest (and highly satisfactory) option is to use ErcHighlightNicknames.

But if you must, below is a variety of elisp to color IRC nicks according to a list of usable colors:

Option 1

The colors are determined by the MD5 sum of a nick string, and if the nick-colors-list changes, so will the color indexes. Enjoy! Put this in your emacs load path and add (require 'erc-nick-colors) to your .emacs. If you have any improvements or suggestions, contact me at cygnus at cprogrammer dot org.

(setq nick-face-list '())

;; Define the list of colors to use when coloring IRC nicks.                                                                     
(setq-default erc-colors-list '("blue" "green" "yellow"
                                "gray" "brown" "red"
                                "purple" "white" "cyan"))

(defun build-nick-face-list ()
  "build-nick-face-list builds a list of new faces using the                                                                     
foreground colors specified in erc-colors-list.  The nick faces                                                                  
created here will be used to format IRC nicks."
  (setq i -1)
  (setq nick-face-list
        (mapcar
         (lambda (COLOR)
           (setq i (1+ i))
           (list (custom-declare-face
                  (make-symbol (format "erc-nick-face-%d" i))
                  (list (list t (list :foreground COLOR)))
                  (format "Nick face %d" i))))
         erc-colors-list)))

(defun my-insert-modify-hook ()
  "This insert-modify hook looks for nicks in new messages and                                                                   
computes md5(nick) and uses substring(md5_value, 0, 4) mod (length                                                               
nick-face-list) to index the face list and produce the same face for a                                                           
given nick each time it is seen.  We get a lot of collisions this way,                                                           
unfortunately, but it's better than some other methods I tried.                                                                  
Additionally, if you change the order or size of the erc-colors-list,                                                            
you'll change the colors used for nicks."
  (if (null nick-face-list) (build-nick-face-list))
  (save-excursion
    (goto-char (point-min))
    (if (looking-at "<\\([^>]*\\)>")
        (let ((nick (match-string 1)))
          (put-text-property (match-beginning 1) (match-end 1)
                             'face (nth
                                    (mod (string-to-number
                                          (substring (md5 nick) 0 4) 16)
                                         (length nick-face-list))
                                    nick-face-list))))))

;; This adds the ERC message insert hook.                                                                                        
(add-hook 'erc-insert-modify-hook 'my-insert-modify-hook)

(provide 'erc-nick-colors)

Option 2

Here is a reformulation of the above. It is simpler to hack, and allows you to specify colors for some people (in case you’re tired of their usual color, if you want to avoid collision, or whatever). Contact at antoine d0t levitt, at gmail.

;; Pool of colors to use when coloring IRC nicks.
(setq erc-colors-list '("green" "blue" "red"
			"dark gray" "dark orange"
			"dark magenta" "maroon"
			"indian red" "black" "forest green"
			"midnight blue" "dark violet"))
;; special colors for some people
(setq erc-nick-color-alist '(("John" . "blue")
			     ("Bob" . "red")
			     ))

(defun erc-get-color-for-nick (nick)
  "Gets a color for NICK. If NICK is in erc-nick-color-alist, use that color, else hash the nick and use a random color from the pool"
  (or (cdr (assoc nick erc-nick-color-alist))
      (nth
       (mod (string-to-number
	     (substring (md5 (downcase nick)) 0 6) 16)
	    (length erc-colors-list))
       erc-colors-list)))

(defun erc-put-color-on-nick ()
  "Modifies the color of nicks according to erc-get-color-for-nick"
  (save-excursion
    (goto-char (point-min))
    (if (looking-at "<\\([^>]*\\)>")
	(let ((nick (match-string 1)))
	  (put-text-property (match-beginning 1) (match-end 1) 'face
			     (cons 'foreground-color
				   (erc-get-color-for-nick nick)))))))

(add-hook 'erc-insert-modify-hook 'erc-put-color-on-nick)

Option 3

Same as the above, but highlight nicks no matter where they appear, using code copied from erc-button-add-nickname-buttons. Take Option 2 code but replace erc-put-color-on-nick:

(defun erc-put-color-on-nick ()
  "Modifies the color of nicks according to erc-get-color-for-nick"
  (save-excursion
    (goto-char (point-min))
    (while (forward-word 1)
      (setq bounds (bounds-of-thing-at-point 'word))
      (setq word (buffer-substring-no-properties
                  (car bounds) (cdr bounds)))
      (when (or (and (erc-server-buffer-p) (erc-get-server-user word))
                (and erc-channel-users (erc-get-channel-user word)))
        (put-text-property (car bounds) (cdr bounds) 
                           'face (cons 'foreground-color
                                       (erc-get-color-for-nick word)))))))

You may also want to modify the syntax table for characters which are commonly in nicks, e.g.::

(add-hook 'erc-mode-hook (lambda () 
                           (modify-syntax-entry ?\_ "w" nil)
                           (modify-syntax-entry ?\- "w" nil)))

Option 4

To get a bit more variety:

(defun erc-set-colors-list ()
  (unless (frame-parameter nil 'erc-nick-colors-list)
    (let ((v nil))
      (dolist (color (defined-colors))
        (or (string-match-p "black" color)
            (add-to-list 'v color)))
      (set-frame-parameter nil 'erc-nick-colors-list v))))

(defun erc-get-color-for-nick (nick)
  "Gets a color for NICK. If NICK is in erc-nick-color-alist, use that color, else hash the nick and use a random color from the pool"
  (let ((colors (frame-parameter nil 'erc-nick-colors-list)))
    (or (cdr (assoc nick erc-nick-color-alist))
        (nth
         (mod (string-to-number
               (substring (md5 nick) 0 6) 16)
              (length colors))
         colors))))

Add extra substrings to exclude as needed, and, if you’re like me and run one emacs daemon to rule them all (including both terminal and X clients):

(add-hook 'after-make-frame-functions '(lambda (frame) (erc-set-colors-list)))

Option 5

Similar to 1 and 2, but generates the colors automatically. The idea for the luminance is stolen from the nick highlighting package.

(defmacro unpack-color (color red green blue &rest body)
  `(let ((,red   (car ,color))
         (,green (car (cdr ,color)))
         (,blue  (car (cdr (cdr ,color)))))
     ,@body))

(defun rgb-to-html (color)
  (unpack-color color red green blue
   (concat "#" (format "%02x%02x%02x" red green blue))))

(defun hexcolor-luminance (color)
  (unpack-color color red green blue
   (floor (+ (* 0.299 red) (* 0.587 green) (* 0.114 blue)))))

(defun invert-color (color)
  (unpack-color color red green blue
   `(,(- 255 red) ,(- 255 green) ,(- 255 blue))))

(defun erc-get-color-for-nick (nick dark)
  (let* ((hash     (md5 (downcase nick)))
         (red      (mod (string-to-number (substring hash 0 10) 16) 256))
         (blue     (mod (string-to-number (substring hash 10 20) 16) 256))
         (green    (mod (string-to-number (substring hash 20 30) 16) 256))
         (color    `(,red ,green ,blue)))
    (rgb-to-html (if (if dark (< (hexcolor-luminance color) 85)
                       (> (hexcolor-luminance color) 170))
                     (invert-color color)
                   color))))

(defun erc-highlight-nicknames ()
  (save-excursion
    (goto-char (point-min))
    (while (re-search-forward "\\w+" nil t)
      (let* ((bounds (bounds-of-thing-at-point 'symbol))
             (nick   (buffer-substring-no-properties (car bounds) (cdr bounds))))
        (when (erc-get-server-user nick)
          (put-text-property
           (car bounds) (cdr bounds) 'face
           (cons 'foreground-color (erc-get-color-for-nick nick 't))))))))

(add-hook 'erc-insert-modify-hook 'erc-highlight-nicknames)

Comments

I use Option 5, but I’m an emacs n00b. I’ve found that it seems to take issue with nicknames containing underscores (_), dashes (-), and pipes (|). Could this be fixed? I have no idea how to do it myself. EDIT: Have to change (bounds-of-thing-at-point ‘word) to (bounds-of-thing-at-point ‘symbol). I’ll change it above.