.emacs.d/lisp/erc-speak.el

231 lines
7.6 KiB
EmacsLisp

;;; erc-speak.el --- Speech-enable the ERC chat client
;; Copyright 2001, 2002, 2003, 2004, 2007,
;; 2008 Free Software Foundation, Inc.
;; This file is part of GNU Emacs.
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;; This file contains code to speech enable ERC using Emacspeak's functionality
;; to access a speech synthesizer.
;;
;; It tries to be intelligent and produce actually understandable
;; audio streams :). Hopefully it does. I use it on #debian at irc.debian.org
;; with about 200 users, and I am amazed how easy it works.
;;
;; Currently, erc-speak is only written to listen to channels.
;; There is no special functionality for interaction in the erc buffers.
;; Although this shouldn't be hard. Look at the Todo list, there are
;; definitely many things this script could do nicely to make a better
;; IRC experience for anyone.
;;
;; More info? Read the code. It isn't that complicated.
;;
;;; Installation:
;; Put erc.el and erc-speak.el somewhere in your load-path and
;; (require 'erc-speak) in your .emacs. Remember to require only erc-speak
;; because otherwise you get conflicts with emacspeak.
;;; Bugs:
;; erc-speak-rate doesn't seem to work here on outloud. Can anyone enlighten
;; me on the use of dtk-interp-queue-set-rate or equivalent?
;;; Code:
(require 'emacspeak)
(provide 'emacspeak-erc)
(require 'erc)
(require 'erc-button)
(defgroup erc-speak nil
"Enable speech synthesis with the ERC chat client using Emacspeak"
:group 'erc)
(defcustom erc-speak-personalities '((erc-default-face paul)
(erc-direct-msg-face paul-animated)
(erc-input-face paul-smooth)
(erc-bold-face paul-bold)
(erc-inverse-face betty)
(erc-underline-face ursula)
(erc-prompt-face harry)
(erc-notice-face paul-italic)
(erc-action-face paul-monotone)
(erc-error-face kid)
(erc-dangerous-host-face paul-surprized)
(erc-pal-face paul-animated)
(erc-fool-face paul-angry)
(erc-keyword-face paul-animated))
"Maps faces used in erc to speaker personalities in emacspeak."
:group 'erc-speak
:type '(repeat
(list :tag "mapping"
(symbol :tag "face")
(symbol :tag "personality"))))
(add-hook 'erc-mode-hook (lambda () (setq voice-lock-mode t)))
;; Override the definition in erc.el
(defun erc-put-text-property (start end property value &optional object)
"This function sets the appropriate personality on the specified
region in addition to setting the requested face."
(put-text-property start end property value object)
(when (eq property 'face)
(put-text-property start end
'personality
(cadr (assq value erc-speak-personalities))
object)))
(add-hook 'erc-insert-post-hook 'erc-speak-region)
(add-hook 'erc-send-post-hook 'erc-speak-region)
(defcustom erc-speak-filter-host t
"Set to t if you want to filter out user@host constructs."
:group 'erc-speak
:type 'bool)
(defcustom erc-speak-filter-timestamp t
"If non-nil, try to filter out the timestamp when speaking arriving messages.
Note, your erc-timestamp-format variable needs to start with a [
and end with ]."
:group 'erc-speak
:type 'bool)
(defcustom erc-speak-acronyms '(("brb" "be right back")
("btw" "by the way")
("wtf" "what the fuck")
("rotfl" "rolling on the floor and laughing")
("afaik" "as far as I know")
("afaics" "as far as I can see")
("iirc" "if I remember correctly"))
"List of acronyms to expand."
:group 'erc-speak
:type '(repeat sexp))
(defun erc-speak-acronym-replace (string)
"Replace acronyms in the current buffer."
(let ((case-fold-search nil))
(dolist (ac erc-speak-acronyms string)
(while (string-match (car ac) string)
(setq string (replace-match (cadr ac) nil t string))))))
(defcustom erc-speak-smileys '((":-)" "smiling face")
(":)" "smiling face")
(":-(" "sad face")
(":(" "sad face"))
;; please add more, send me patches, mlang@home.delysid.org tnx
"List of smileys and their textual description."
:group 'erc-speak
:type '(repeat (list 'symbol 'symbol)))
(defcustom erc-speak-smiley-personality 'harry
"Personality used for smiley announcements."
:group 'erc-speak
:type 'symbol)
(defun erc-speak-smiley-replace (string)
"Replace smileys with textual description."
(let ((case-fold-search nil))
(dolist (smiley erc-speak-smileys string)
(while (string-match (car smiley) string)
(let ((repl (cadr smiley)))
(put-text-property 0 (length repl) 'personality
erc-speak-smiley-personality repl)
(setq string (replace-match repl nil t string)))))))
(defcustom erc-speak-channel-personality 'harry
"*Personality to announce channel names with."
:group 'erc-speak
:type 'symbol)
(defun erc-speak-region ()
"Speak a region containing one IRC message using Emacspeak.
This function tries to translate common IRC forms into
intelligent speech."
(let ((target (if (erc-channel-p (erc-default-target))
(erc-propertize
(erc-default-target)
'personality erc-speak-channel-personality)
""))
(dtk-stop-immediately nil))
(emacspeak-auditory-icon 'progress)
(when erc-speak-filter-timestamp
(save-excursion
(goto-char (point-min))
(when (re-search-forward "^\\[[a-zA-Z:,;.0-9 \t-]+\\]" nil t)
(narrow-to-region (point) (point-max)))))
(save-excursion
(goto-char (point-min))
(cond ((re-search-forward (concat "^<\\([^>]+\\)> "
(concat "\\("
erc-valid-nick-regexp
"\\)[;,:]")) nil t)
(let ((from (match-string 1))
(to (match-string 2))
(text (buffer-substring (match-end 2) (point-max))))
(tts-with-punctuations
"some"
(dtk-speak (concat (erc-propertize
(concat target " " from " to " to)
'personality erc-speak-channel-personality)
(erc-speak-smiley-replace
(erc-speak-acronym-replace text)))))))
((re-search-forward "^<\\([^>]+\\)> " nil t)
(let ((from (match-string 1))
(msg (buffer-substring (match-end 0) (point-max))))
(tts-with-punctuations
"some"
(dtk-speak (concat target " " from " "
(erc-speak-smiley-replace
(erc-speak-acronym-replace msg)))))))
((re-search-forward (concat "^" (regexp-quote erc-notice-prefix)
"\\(.+\\)")
(point-max) t)
(let ((notice (buffer-substring (match-beginning 1) (point-max))))
(tts-with-punctuations
"all"
(dtk-speak
(with-temp-buffer
(insert notice)
(when erc-speak-filter-host
(goto-char (point-min))
(when (re-search-forward "([^)@]+@[^)@]+)" nil t)
(replace-match "")))
(buffer-string))))))
(t (let ((msg (buffer-substring (point-min) (point-max))))
(tts-with-punctuations
"some"
(dtk-speak (concat target " "
(erc-speak-smiley-replace
(erc-speak-acronym-replace msg)))))))))))
(provide 'erc-speak)
;;; erc-speak.el ends here
;;
;; Local Variables:
;; indent-tabs-mode: t
;; tab-width: 8
;; End:
;; arch-tag: 4499cd13-2829-43b8-83de-d313481531c4