commit fa8503a6d7268999154d4b4ce8fd5599cf24facd Author: pi-bot-01 Date: Thu Mar 26 01:01:07 2026 -0700 Initial commit diff --git a/rtf-mode-el.el b/rtf-mode-el.el new file mode 100644 index 0000000..7c07f1c --- /dev/null +++ b/rtf-mode-el.el @@ -0,0 +1,199 @@ +;;; rtf-mode.el --- Emacs major mode for viewing/editing raw RTF source + +;; Copyright (C) 2006 Sean M. Burke (but released under GPL) + +;; Time-stamp: <2008-01-05 19:12:08 AKST sburke@cpan.org> +;; Author: Sean M. Burke +;; Maintainer: Sean M. Burke +;; Keywords: wp, rtf, languages +;; Version: 1.1 +;; X-URL: http://interglacial.com/rtf/emacs/ + +;;; Commentary: + +;; Major mode for viewing/editing RTF source. I wrote this mostly for +;; the sake of syntax-highlighting, and for the {}-matching. It offers +;; little else in the way of conveniences (like key shortcuts.) +;; (If are interested in such conveniences, email me.) +;; +;; I maintain a homepage for this mode, at http://interglacial.com/rtf/emacs/ +;; +;; Note that this mode doesn't (yet?) specially handle Help-RTF constructs. +;; +;; Also note that at time of writing (Oct 2006), Xemacs doesn't seem to +;; support some of the functions that this mode requires. Sorry, Xemacs users! +;; +;; As with many programming modes, the default wrapping mechinisms +;; (whether via auto-fill-mode, or via fill-paragraph etc commands) do +;; not behave at all well. So I've disabled wrapping as best I can, +;; so you don't end up corrupting documents. Moreover, implementing +;; wrapping in RTF seems fairly difficult because of how spaces are +;; sometimes a significant token in RTF whereas newlines are not. +;; +;; For more on RTF, see http://interglacial.com/rtf/ and also be a chum and +;; go get this little book I wrote: http://www.amazon.com/dp/0596004753 +;; + +;;; Boilerplate + +;; This file is not part of GNU Emacs. +;; +;; This 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, version 2. +;; +;; This 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;;; Change log: + +;; 2006-10-23 version 1.1 +;; Public release. Just a minor internal optimization. +;; (We new use regexp-opt to build our regexp from rtf-loudcmds.) + +;; 2006-10-22 version 1.0 +;; Public release. + +;;; Code: + +(require 'generic) + +(defmacro rtf-mkface (name basis desc) + `(defface + ,name + (list (list t :inherit ,basis)) + ,(concat "Face used to highlight rtf-mode " desc ".") + :group 'rtf)) + +(rtf-mkface rtf-brace-face 'font-lock-string-face "braces") +(rtf-mkface rtf-charescape-face 'font-lock-function-name-face "numeric escapes") +(rtf-mkface rtf-loud-cword-face 'font-lock-warning-face "important commands") +(rtf-mkface rtf-cword-face 'font-lock-keyword-face "commands") +(rtf-mkface rtf-cword-param-face 'font-lock-builtin-face "command-parameters") +(rtf-mkface rtf-cword-endingspace-face 'font-lock-comment-face "command-ending spaces") +(rtf-mkface rtf-star-face 'font-lock-doc-face "\\* commands") +(rtf-mkface rtf-escnewline-face 'font-lock-constant-face "\\ [Newline] sequences") +(rtf-mkface rtf-esctab-face 'font-lock-warning-face "\\ [Tab] sequences") +(rtf-mkface rtf-escother-face 'font-lock-type-face "\\ [other] sequences") +(rtf-mkface rtf-trailing-whitespace-face 'highlight "trailing space") + +(defvar rtf-loudcmds + '( + rtf1 page pard par line sectd sect footnote + cell row trowd + fonttbl info colortbl stylesheet + ) + "A few structurally super-important (and parameterless) RTF commands.") + +;====================================================================== + +(defun rtf-make-loudcmd-re (cmdlist) + (concat "\\(\\\\\\)\\(" + (regexp-opt (mapcar 'symbol-name cmdlist)) + "\\)\\b\\( ?\\)")) + +(define-generic-mode 'rtf-mode + nil ; the comment syntax list -- nil because RTF has no comments! + nil ; keyword-list -- nil because we do everything below + + (list ; the font lock list... + + ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ; * Control words, \foo123, \foo-123, \foo + + ; A few structurally super-important (and parameterless) control words: + (list (rtf-make-loudcmd-re rtf-loudcmds) + '(1 'rtf-cword-face) + '(2 'rtf-loud-cword-face) + '(3 'rtf-cword-endingspace-face) + ) + + '("\\(\\\\u-?[0-9]+ ?\\)" ; a unicodey escape + 1 'rtf-charescape-face) + + '("\\(\\\\[a-zA-Z]+\\)\\(-?[0-9]+\\)\\( ?\\)" ; with a num-param + (1 'rtf-cword-face) + (2 'rtf-cword-param-face) + (3 'rtf-cword-endingspace-face) + ) + + '("\\(\\\\[a-zA-Z]+\\)\\( ?\\)" ; no param + (1 'rtf-cword-face) + (2 'rtf-cword-endingspace-face) + ) + ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ; * Control symbols + ; ~ the fancy \* thing... + '("\\(\\\\\\*\\)" 1 'rtf-star-face) + + ; ~ \'xx escape + '("\\(\\\\'[a-fA-F0-9][a-fA-F0-9]\\)" 1 'rtf-charescape-face) + + ; ~ \[NEWLINE] which means \par + '("\\(\\\\\012\\)" 1 'rtf-escnewline-face) + + ; ~ \[TAB] which means \tab + '("\\(\\\\\011\\)" 1 'rtf-esctab-face) + + ; ~ \_ where _ is anything else, but probably one of ' - : \ _ { | } ~ + '("\\(\\\\[^a-zA-Z'\011\012]\\)" 1 'rtf-escother-face) + + ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ; * '{' and '}' (unescaped, that is) + '("\\({\\|}\\)" 1 'rtf-brace-face) + + ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ; And, incidentally: + ; ~ trailing whitespace -- not an error, but which is /significant/! + '("\\([ \011]+\\)$" 1 'rtf-trailing-whitespace-face) + + ;; You COULD highlight /all/ significant spaces in the document with this: + ;("\\([ \011]+\\)" 1 'rtf-trailing-whitespace-face) + ;; but that would probably be more confusing than useful. + + ) + + (list ".rtf\\'" ) ; auto-mode list -- our extensions + + (list 'rtf-mode-setup-function) + "A major mode for editing/viewing RTF source.") + +; TODO: support for blobs? Seems tricky. +;====================================================================== + +(defun rtf-mode-stultify-character (str) + "Mark this one-character string as nonmagical in the syntax table." + (modify-syntax-entry (string-to-char str) ".")) + +(defun rtf-mode-fill-paragraph (arg) + (message "rtf-mode doesn't currently support filling paragraphs") + ; This is just to inhibit the actual normal filler, because + ; that's usually a really bad idea for RTF. (I will have + ; to write a replacement for it eventually, but it'll be + ; quite tricky.) + t) + +(defun rtf-mode-setup-function () + (dolist (s (split-string "\"()[]\\" "")) + (rtf-mode-stultify-character s)) + + (set (make-local-variable 'require-final-newline) nil) + ; Many RTF files end on a "}" without a newline after it + + (set (make-local-variable 'fill-paragraph-function) 'rtf-mode-fill-paragraph) + + ;(set (make-local-variable 'fill-prefix) " ") + ; ^^ That'd be good for entering text content, but it inserts + ; significant spaces when you're entering commands! + + t +) + +(provide 'rtf-mode) + +;;; rtf-mode.el ends here