1 ;;;; xslide.el --- XSL Integrated Development Environment
2 ;; $Id: xslide.el,v 1.11 2003/07/18 23:27:13 tonygraham Exp $
4 ;; Copyright (C) 1998, 1999, 2000, 2001, 2003 Tony Graham
6 ;; Author: Tony Graham <tkg@menteith.com>
7 ;; Contributors: Simon Brooke, Girard Milmeister, Norman Walsh,
8 ;; Moritz Maass, Lassi Tuura, Simon Wright, KURODA Akira,
9 ;; Ville Skyttä, Glen Peterson
10 ;; Created: 21 August 1998
11 ;; Version: $Revision: 1.11 $
12 ;; Keywords: languages, xsl, xml
14 ;;; This file is not part of GNU Emacs.
16 ;; This program is free software; you can redistribute it and/or
17 ;; modify it under the terms of the GNU General Public License
18 ;; as published by the Free Software Foundation; either version 2
19 ;; of the License, or (at your option) any later version.
21 ;; This program is distributed in the hope that it will be useful,
22 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 ;; GNU General Public License for more details.
26 ;; You should have received a copy of the GNU General Public License
27 ;; along with this program; if not, write to the Free Software
28 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 ;; Functions for editing XSL stylesheets
35 ;; Requires xslide-font.el, xslide-data.el, xslide-abbrev.el, xslide-process.el
36 ;; Requires 'etags for `find-tag-default'
37 ;; Requires 'reporter for `xsl-submit-bug-report'
38 ;; Requires 'imenu for "Goto" menu
40 ;; Send bugs to xslide-bug@menteith.com
41 ;; Use `xsl-submit-bug-report' for bug reports
49 ;; XEmacs users don't always have imenu.el installed, so use
50 ;; condition-case to cope if xslide causes an error by requiring imenu.
55 ;; Need etags for `find-tag-default'
58 (require 'xslide-data "xslide-data")
59 (require 'xslide-abbrev "xslide-abbrev")
60 (require 'xslide-font "xslide-font")
61 (require 'xslide-process "xslide-process")
63 ;; Work out if using XEmacs or Emacs
65 (defconst xsl-xemacs-p nil)
66 (defconst xsl-fsfemacs-p nil)
67 (defun xsl-xemacs-p () xsl-xemacs-p)
68 (defun xsl-fsfemacs-p () xsl-fsfemacs-p)
69 (defun xsl-note-emacs-version ()
70 (setq xsl-xemacs-p (string-match "XEmacs" emacs-version)
71 xsl-fsfemacs-p (not xsl-xemacs-p)))
72 (xsl-note-emacs-version)
74 ;; Define core `xsl' group.
76 "Major mode for editing XSL."
80 (defgroup xsl-faces nil
81 "Font faces used in XSL mode."
85 (defgroup xsl-process nil
86 "Running XSL processors from XSL mode."
89 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
90 ;; Version information
92 (defconst xslide-version "0.2.2"
93 "Version number of xslide XSL mode.")
95 (defun xslide-version ()
96 "Return the value of the variable `xslide-version'."
99 (defconst xslide-maintainer-address "xslide-bug@menteith.com")
101 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
104 (defvar xsl-indent-tabs-mode nil
105 "*Initial value of `indent-tabs-mode' on entering `xsl-mode'.")
107 (defvar xsl-default-filespec "*.xsl"
108 "*Initial prompt value for `xsl-etags''s FILESPEC argument.")
110 (defvar xsl-filespec-history (list xsl-default-filespec)
111 "Minibuffer history list for `xsl-etags' and `xsl-grep''s FILESPEC argument.")
113 (defvar xsl-grep-pattern-history nil
114 "Minibuffer history list for `xsl-grep''s PATTERN argument.")
116 (defvar xsl-grep-case-sensitive-flag nil
117 "*Non-nil disables case insensitive searches by `xsl-grep'.")
119 (defvar xsl-comment-start "<!--"
120 "*Comment start character sequence.")
122 (defvar xsl-comment-end "-->"
123 "*Comment end character sequence.")
125 (defvar xsl-comment-max-column 70
126 "*Maximum column number for text in a comment.")
128 (defcustom xsl-initial-stylesheet-file (locate-library "xslide-initial.xsl" t)
129 "*File containing initial stylesheet inserted into empty XSL buffers."
130 :type '(choice (file :must-match t) (const :tag "No initial stylesheet" nil))
133 (defcustom xsl-initial-stylesheet-initial-point 0
134 "*Initial position of point in initial stylesheet."
138 (defcustom xsl-initial-fo-file (locate-library "xslide-initial.fo" t)
139 "*File containing initial FO stylesheet inserted into empty XSL buffers."
140 :type '(choice (file :must-match t) (const :tag "No initial FO file" nil))
143 (defcustom xsl-initial-fo-initial-point 0
144 "*Initial position of point in initial FO stylesheet."
148 (defcustom xsl-indent-attributes nil
149 "*Whether to indent attributes on lines following an open tag.
150 If non-nil, attributes will be aligned with the space after the
151 element name, otherwise by two spaces."
152 :type '(choice (const :tag "Yes" t) (const :tag "No" nil))
155 (defcustom xsl-element-indent-step 2
156 "*Amount by which to indent success levels of nested elements."
160 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
163 (defun xsl-read-from-minibuffer (prompt default history)
164 "Read from minibuffer with default and command history."
169 (read-from-minibuffer (if default
173 (format "%s" prompt))
179 ;; XSLIDE house style puts all comments starting on a favourite column
180 (defun xsl-comment (comment)
181 "Insert COMMENT starting at the usual column.
183 With a prefix argument, e.g. \\[universal-argument] \\[xsl-comment], insert separator comment
184 lines above and below COMMENT in the manner of `xsl-big-comment'."
185 (interactive "sComment: ")
189 (let ((fill-column (1- xsl-comment-max-column))
190 (fill-prefix (make-string (1+ (length xsl-comment-start)) ?\ ))
191 ;; (comment-start xsl-init-comment-fill-prefix)
192 (saved-auto-fill-function auto-fill-function))
194 (insert xsl-comment-start)
196 (indent-to (length fill-prefix))
197 (fill-region (point) (save-excursion
203 ;; The fill does the right thing, but it always ends with
204 ;; an extra newline, so delete the newline.
205 (delete-backward-char 1)
206 (if (not saved-auto-fill-function)
209 (insert xsl-comment-end)
213 (font-lock-fontify-keywords-region
214 (xsl-font-lock-region-point-min)
215 (xsl-font-lock-region-point-max))))))
217 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
220 (defvar xsl-mode-map nil
221 "Keymap for XSL mode.")
225 (setq xsl-mode-map (make-sparse-keymap))
226 (define-key xsl-mode-map [tab] 'xsl-electric-tab)
227 ;; (define-key xsl-mode-map "\M-\t" 'xsl-complete)
228 (define-key xsl-mode-map [(meta tab)] 'xsl-complete)
229 ;; (define-key xsl-mode-map "\"" 'xsl-electric-quote)
230 ;; (define-key xsl-mode-map "'" 'xsl-electric-apos)
231 (define-key xsl-mode-map "/" 'xsl-electric-slash)
232 (define-key xsl-mode-map "<" 'xsl-electric-less-than)
233 (define-key xsl-mode-map ">" 'xsl-electric-greater-than)
234 ;; (define-key xsl-mode-map "[" 'xsl-electric-lsqb)
235 ;; (define-key xsl-mode-map "(" 'xsl-electric-lpar)
236 ;; (define-key xsl-mode-map "{" 'xsl-electric-lcub)
237 (define-key xsl-mode-map [(control c) (control c)]
239 (define-key xsl-mode-map [(control c) (control p)]
241 (define-key xsl-mode-map [(control o)]
243 (define-key xsl-mode-map "\C-c<" 'xsl-insert-tag)
244 (define-key xsl-mode-map "\C-c\C-t" 'xsl-if-to-choose)
245 ;; (define-key xsl-mode-map [(control m)] 'xsl-electric-return)
246 ;; (define-key xsl-mode-map \10 'xsl-electric-return)
247 (define-key xsl-mode-map "\177" 'backward-delete-char-untabify)
248 ;; (define-key xsl-mode-map "\M-\C-e" 'xsl-next-rule)
249 ;; (define-key xsl-mode-map "\M-\C-a" 'xsl-previous-rule)
250 ;; (define-key xsl-mode-map "\M-\C-h" 'mark-xsl-rule)
253 (defun xsl-if-to-choose ()
254 "Converts <xsl:if> to <xsl:choose>. Works on a single 'ifs' or on a region.
257 <xsl:if test=\"isFive = 5\"><p>It's five!</p></xsl:if>
261 <xsl:when test=\"isFive = 5\"><p>It's five!</p></xsl:when>
262 <xsl:otherwise></xsl:otherwise>
265 If you put your cursor inside the open-tag of the if, it will work on that tag
266 only. If you highlight a region, it will convert every 'if' whose start tag is
267 within that region. It is very easy to convert consecutive 'if's to a single
268 choose by deleting the appropriate lines after executing this command.
270 Bound to C-c C-t by default."
274 (single-if (not (mark)))
276 (the-end (if (mark) (mark) (point)))
278 (if (and (not (null (mark)))
281 (exchange-point-and-mark)
282 (setq the-start (point))
283 (setq the-end (mark))
289 (search-backward "<" nil t)
290 ; (message "xsl-if-to-choose: single if mode")
291 (xsl-convert-if-to-choose-slave)
295 ; (concat "xsl-if-to-choose: Region mode: "
296 ; (int-to-string the-start)
298 ; (int-to-string the-end)
302 (if (save-excursion (search-backward "<xsl:if" the-start t))
303 (while (search-backward "<xsl:if" the-start t)
304 (xsl-convert-if-to-choose-slave)
306 (message "xsl-if-to-choose error: There's no <xsl:if> within the selected region.")
314 (defun xsl-convert-if-to-choose-slave ()
315 (if (looking-at "<xsl:if")
317 ( (start (save-excursion (beginning-of-line) (point))) )
319 (insert "<xsl:choose>\n<xsl:when")
320 (search-forward "</xsl:if>" nil t)
321 (backward-delete-char 9)
322 (insert "</xsl:when>\n<xsl:otherwise></xsl:otherwise>\n</xsl:choose>")
323 (indent-region start (point) nil)
325 (message "xsl-if-to-choose error: point is not within the start tag of an <xsl:if>.")
329 (defun xsl-electric-greater-than (arg)
330 "Insert a \">\" and, optionally, insert a matching end-tag.
332 If the \">\" closes a start-tag and the start-tag is the last thing on
333 the line, `xsl-electric-greater-than' inserts the matching end-tag.
334 Providing a prefix argument, e.g., \\[universal-argument] \\[xsl-electric-greater-than], stops the inserting of the
337 If the element being terminated is listed as a block element in
338 `xsl-all-elements-alist', then point is left on the next line at the
339 correct indent and the end-tag is inserted on the following line at
342 `xsl-electric-greater-than' also fontifies the region around the
350 (let ((limit (point)))
352 (search-backward "<")
353 ;; (message "%s:%s" (point) limit)
355 (looking-at "<\\(\\(\\sw\\|\\s_\\)+\\)\\(\\s-+\\(\\sw\\|\\s_\\)+[ ]*=[ ]*\\('[^']*'\\|\"[^\"]*\"\\)\\)*\\s-*\\(/?\\)>")
356 ;; (message "%s:%s" limit (match-end 0))
357 (= (match-end 0) limit)
358 ;; (message ":%s:" (match-string 6))
359 (not (string-equal (match-string 6) "/"))
360 (not (save-match-data
361 (string-match "^/" (match-string 1))))))))
362 (if (string-equal (nth 1 (assoc (match-string 1) xsl-all-elements-alist)) "block")
364 (xsl-electric-return)
367 (xsl-electric-slash)))
369 (insert (format "</%s>" (match-string 1))))))
372 (font-lock-fontify-region
373 (xsl-font-lock-region-point-min)
374 (xsl-font-lock-region-point-max)))))
376 (defun xsl-electric-apos ()
377 "Function called when \"'\" is pressed in XSL mode."
380 (if (looking-at "\\([\"/})]\\|$\\)")
384 (defun xsl-electric-quote ()
385 "Function called when '\"' is pressed in XSL mode."
388 (if (looking-at "\\(['/})]\\|$\\)")
392 (defun xsl-electric-lsqb ()
393 "Function called when \"[\" is pressed in XSL mode."
396 (if (looking-at "\\([\"'/})]\\|$\\)")
400 (defun xsl-electric-lpar ()
401 "Function called when \"(\" is pressed in XSL mode."
404 (if (looking-at "\\([\]\"'/}]\\|$\\)")
408 (defun xsl-electric-lcub ()
409 "Function called when \"{\" is pressed in XSL mode."
412 (if (looking-at "\\([\])\"'/}]\\|$\\)")
416 (defun xsl-electric-less-than ()
417 "Function called when \"<\" is pressed in XSL mode."
422 (defun xsl-match-opening-tag (a)
423 "Function called to match the next opening tag to a closing tag."
424 (if (looking-at "</")
426 (while (re-search-backward
427 (concat "\\(<\\|</\\)" a "[ \t\n\r>]") nil t)
429 ((looking-at (concat "</" a))
430 (xsl-match-opening-tag a))
431 ((looking-at (concat "<" a))
432 (throw 'start-tag a))
436 (defun xsl-electric-slash ()
437 "Function called when \"/\" is pressed in XSL mode."
445 (if (looking-at "</")
447 (while (re-search-backward "<" nil t)
449 ((looking-at "</\\([^/> \t]+\\)>")
450 ;; (message "End tag: %s" (match-string 1))
452 (xsl-match-opening-tag (match-string 1)))
454 ;; (re-search-backward
455 ;; (concat "<" (match-string 1) "[ \t\n\r>]") nil t))
456 ((looking-at "<\\(\\([^/>]\\|/[^>]\\)+\\)/>"))
457 ;; (message "Empty tag: %s" (match-string 1)))
458 ((looking-at "<!--[^-]*\\(-[^-]+\\)*-->"))
459 ;; skip CDATA sections
460 ((looking-at "<!\\[CDATA\\["))
461 ;; XEmacs Change: and the XMLdecl, DOCTYPE and ENTITYs
463 "<\\(\\?xml\\|!\\(DOCTYPE\\|ENTITY\\)\\)[ \t\n\r]"))
464 ((looking-at "<\\([^/> \n\t]+\\)")
465 ;; (message "Start tag: %s" (match-string 1))
466 (throw 'start-tag (match-string 1)))
468 (throw 'start-tag nil)))))
472 (insert element-name)
476 (font-lock-fontify-region
477 (xsl-font-lock-region-point-min)
478 (xsl-font-lock-region-point-max)))))))))
480 (defun xsl-electric-return ()
481 "Function called when RET is pressed in XSL mode."
486 (defun xsl-open-line (arg)
495 (xsl-electric-tab))))
497 (defun xsl-electric-tab ()
498 "Function called when TAB is pressed in XSL mode."
502 (delete-horizontal-space)
503 (if (looking-at "</")
504 (indent-to (max 0 (- (xsl-calculate-indent) xsl-element-indent-step)))
505 (indent-to (xsl-calculate-indent))))
508 (looking-at "[ \t]+"))
509 (goto-char (match-end 0)))
512 (font-lock-fontify-keywords-region
513 (xsl-font-lock-region-point-min)
514 (xsl-font-lock-region-point-max)))))
517 (defun xsl-close-open-tab-p nil
518 "Return t if the current line contains more right than left angle-brackets."
523 (let ((here (char-after (point))))
525 ((eq here '?\>) (setq open (1- open)))
526 ((eq here '?\<) (setq open (1+ open)))
531 (< open 0) ; true if we've counted more
537 (defun xsl-calculate-indent ()
538 "Calculate what the indent should be for the current line."
539 (let* ((limit (point))
540 (name "[^<>=\"' \t\n]+")
541 (string "\\(\"[^<>\"]*\"\\|'[^<>']*'\\)")
542 (ostring "\\(\"[^<>\"]*\\|'[^<>']*\\)")
543 (attval (concat name "=" string))
544 (oattval (concat name "=" ostring))
545 (element (concat "<\\(" name "\\)"
546 "\\([ \t\n]+" attval "\\)*[ \t\n]*"))
547 (meta (concat "<!\\(DOCTYPE\\|ENTITY\\)"
548 "\\([ \t\n]+\\(" name "\\|" string "\\)\\)*")))
550 (if (re-search-backward "^\\([ \t]*\\)<" nil t)
551 (goto-char (match-end 1))
554 ;; closed comment => stay put
556 (re-search-forward "<!--[^-]*\\(-[^-]+\\)*-->" limit t))
558 ;; open comment => indent by five
560 (+ (current-column) 5))
561 ;; end tag, closed empty tag, open tag immediately followed by
562 ;; other tags/char data or a complete meta tag => stay put
564 (or (looking-at (concat "</" name ">"))
565 ;; XEmacs change: grok whitespace before />.
566 (re-search-forward (concat element "[ \t\n]*/>") limit t)
567 (re-search-forward (concat element ">[ \t]*[^\n]") limit t)
568 (re-search-forward (concat meta ">[ \t]*\n") limit t)))
570 ;; closed open tag followed by new line, or an opening meta tag
571 ;; => indent by xsl-element-indent-step
573 (or (re-search-forward (concat element ">[ \t]*\n") limit t)
574 (re-search-forward (concat meta "\\[[ \t]*\n") limit t)))
575 (+ (current-column) xsl-element-indent-step))
576 ;; incomplete open tag or open meta => indent after tag name
578 (and (or (re-search-forward (concat element "[ \t\n]*") limit t)
579 (re-search-forward (concat meta "[ \t\n]*") limit t))
581 (if xsl-indent-attributes
582 (progn (goto-char (match-end 1))
583 (+ (current-column) 1))
584 (+ (current-column) xsl-element-indent-step)))
585 ;; incomplete attribute value => indent to string start
587 (and (or (re-search-forward (concat element "[ \t\n]+" oattval)
590 (goto-char (match-beginning 4))
591 (+ (current-column) 1))
592 ;; beginning of buffer => stay put (beginning of line)
595 ;; otherwise => indent by xsl-element-indent-step
597 (+ (current-column) xsl-element-indent-step))))))
599 (defun xsl-complete ()
600 "Complete the tag or attribute before point.
601 If it is a tag (starts with < or </) complete with allowed tags,
602 otherwise complete with allowed attributes."
604 (let ((tab ; The completion table
609 (skip-chars-backward "^ \n\t</!&%")
610 (setq pattern (buffer-substring (point) here))
611 (setq c (char-after (1- (point))))
618 ;; (sgml-entity-completion-table
619 ;; (sgml-dtd-entities (sgml-pstate-dtd sgml-buffer-parse-state)))))
624 ;; (sgml-parse-to-here)
625 (setq tab xsl-all-elements-alist))
630 ;; (sgml-parse-to-here)
631 ;; (setq tab (sgml-eltype-completion-table
632 ;; (sgml-current-list-of-endable-eltypes)))))
633 ;; markup declaration
635 ;; (setq tab sgml-markup-declaration-table))
639 ;; (sgml-parse-to-here)
640 (setq tab xsl-all-attribute-alist))
643 (ispell-complete-word)))
645 (let ((completion (try-completion pattern tab)))
646 (cond ((null completion)
648 (message "Can't find completion for \"%s\"" pattern)
652 (message "[Complete]"))
653 ((not (string= pattern completion))
654 (delete-char (length pattern))
658 (message "Making completion list...")
659 (let ((list (all-completions pattern tab)))
660 (with-output-to-temp-buffer " *Completions*"
661 (display-completion-list list)))
662 (message "Making completion list...%s" "done")))))))
664 (defun xsl-insert-tag (tag)
665 "Insert a tag, reading tag name in minibuffer with completion."
668 (completing-read "Tag: " xsl-all-elements-alist)))
669 ;; (xsl-find-context-of (point))
670 ;; (assert (null xsl-markup-type))
671 ;; Fix white-space before tag
672 ;; (unless (xsl-element-data-p (xsl-parse-to-here))
673 (skip-chars-backward " \t")
675 ((looking-at "^\\s-*$")
677 ((looking-at "^\\s-*</")
684 (let ((tag-type (nth 1 (assoc tag xsl-all-elements-alist))))
687 (equal tag-type "block")
688 (equal tag-type nil))
700 (xsl-electric-slash)))
701 ((equal tag-type "inline")
715 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
717 (defun xsl-insert-template (match)
719 (interactive "smatch=")
721 (insert (format "<xsl:template match=\"%s\">\n" match))
728 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
729 ;; Syntax table stuff
731 (defvar xsl-mode-syntax-table nil
732 "Syntax table used while in XSL mode.")
734 (if xsl-mode-syntax-table
736 (setq xsl-mode-syntax-table (make-syntax-table))
737 ;; set the non-alphanumeric characters in XML names to
738 ;; 'symbol constituent' class
739 (modify-syntax-entry ?: "_" xsl-mode-syntax-table)
740 (modify-syntax-entry ?_ "_" xsl-mode-syntax-table)
741 (modify-syntax-entry ?- "_ 1234" xsl-mode-syntax-table)
742 (modify-syntax-entry ?. "_" xsl-mode-syntax-table)
743 ;; "-" is a special case because it is the first and second characters
744 ;; of the start- and end-comment sequences.
745 (modify-syntax-entry ?- "_ 1234" xsl-mode-syntax-table)
746 ;; "%" does double duty in parameter entity declarations and references.
747 ;; Not necessary to make "%" and ";" act like parentheses since the
748 ;; font lock highlighting tells you when you've put the ";" on the
749 ;; end of a parameter entity reference.
750 (modify-syntax-entry ?% "_" xsl-mode-syntax-table)
751 (modify-syntax-entry ?\; "_" xsl-mode-syntax-table)
752 ;; "/" is just punctuation in XSLs, and really only has a role in
753 ;; Formal Public Identifiers
754 (modify-syntax-entry ?/ "." xsl-mode-syntax-table)
755 ;; Sometimes a string is more than just a string, Dr Freud.
756 ;; Unfortunately, the syntax stuff isn't fussy about matching
757 ;; on paired delimiters, and will happily match a single quote
758 ;; with a double quote, and vice versa. At least the font
759 ;; lock stuff is more fussy and won't change colour if the
760 ;; delimiters aren't paired.
761 (modify-syntax-entry ?\" "$" xsl-mode-syntax-table)
762 (modify-syntax-entry ?\' "$" xsl-mode-syntax-table)
763 ;; The occurrence indicators and connectors are punctuation to us.
764 (modify-syntax-entry ?| "." xsl-mode-syntax-table)
765 (modify-syntax-entry ?, "." xsl-mode-syntax-table)
766 (modify-syntax-entry ?& "." xsl-mode-syntax-table)
767 (modify-syntax-entry ?? "." xsl-mode-syntax-table)
768 (modify-syntax-entry ?+ "." xsl-mode-syntax-table)
769 (modify-syntax-entry ?* "." xsl-mode-syntax-table)
770 ;; `<' and `>' are also punctuation
771 (modify-syntax-entry ?< "." xsl-mode-syntax-table)
772 (modify-syntax-entry ?> "." xsl-mode-syntax-table)
774 (modify-syntax-entry ?# "_" xsl-mode-syntax-table))
777 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
780 (defun xsl-sort-alist (alist)
784 (lambda (a b) (string< (car a) (car b)))))
786 (defun xsl-imenu-create-index-function ()
787 "Create an alist of elements, etc. suitable for use with `imenu'."
789 (let ((template-alist '())
792 (attribute-set-alist '())
794 (goto-char (point-min))
797 "^\\s-*<xsl:template\\(\\s-+\\)" nil t)
798 ;; Go to the beginning of the whitespace after the element name
799 (goto-char (match-beginning 1))
800 ;; Match on either single-quoted or double-quoted attribute value.
801 ;; The expression that doesn't match will have return nil for
802 ;; `match-beginning' and `match-end'.
803 ;; Don't move point because the 'mode' attribute may be before
804 ;; the 'match' attribute.
807 "match\\s-*=\\s-*\\(\"\\([^\"]*\\)\"\\|'\\([^']*\\)'\\)"
810 (re-search-forward "<\\|>" nil t)))
812 (let* ((pattern (buffer-substring-no-properties
813 ;; Rely on the pattern that didn't match
814 ;; returning nil and on `or' evaluating the
815 ;; second form when the first returns nil.
822 (pattern-position (or
824 (match-beginning 3))))
825 ;; Test to see if there is a 'mode' attribute.
826 ;; Match on either single-quoted or double-quoted attribute value.
827 ;; The expression that doesn't match will have return nil for
828 ;; `match-beginning' and `match-end'.
831 "mode\\s-*=\\s-*\\(\"\\([^\"]*\\)\"\\|'\\([^']*\\)'\\)"
834 (re-search-forward "<\\|>" nil t)))
836 (let* ((mode-name (buffer-substring-no-properties
837 ;; Rely on the pattern that didn't match
838 ;; returning nil and on `or' evaluating the
839 ;; second form when the first returns nil.
846 (mode-name-alist (assoc mode-name mode-alist)))
848 (setcdr mode-name-alist
849 (list (car (cdr mode-name-alist))
850 (cons pattern pattern-position)))
853 (list mode-name (cons pattern pattern-position))
856 (cons (cons pattern pattern-position)
858 ;; When there's no "match" attribute, can still have "name"
862 "\\s-+name\\s-*=\\s-*\\(\"\\([^\"]*\\)\"\\|'\\([^']*\\)'\\)"
865 (re-search-forward "<\\|>" nil t)))
869 (cons (buffer-substring-no-properties
870 ;; Rely on the pattern that didn't match
871 ;; returning nil and on `or' evaluating the
872 ;; second form when the first returns nil.
881 (match-beginning 3)))
883 (goto-char (point-min))
886 "^\\s-*<xsl:attribute-set\\(\\s-+\\)" nil t)
887 ;; Go to the beginning of the whitespace after the element name
888 (goto-char (match-beginning 1))
889 ;; Match on either single-quoted or double-quoted attribute value.
890 ;; The expression that doesn't match will have return nil for
891 ;; `match-beginning' and `match-end'.
894 "name\\s-*=\\s-*\\(\"\\([^\"]*\\)\"\\|'\\([^']*\\)'\\)"
897 (re-search-forward "<\\|>$" nil t)))
899 (setq attribute-set-alist
901 (cons (buffer-substring-no-properties
902 ;; Rely on the pattern that didn't match
903 ;; returning nil and on `or' evaluating the
904 ;; second form when the first returns nil.
913 (match-beginning 3)))
914 attribute-set-alist))))
915 (goto-char (point-min))
918 "^\\s-*<xsl:key\\(\\s-+\\)" nil t)
919 ;; Go to the beginning of the whitespace after the element name
920 (goto-char (match-beginning 1))
921 ;; Match on either single-quoted or double-quoted attribute value.
922 ;; The expression that doesn't match will have return nil for
923 ;; `match-beginning' and `match-end'.
926 "name\\s-*=\\s-*\\(\"\\([^\"]*\\)\"\\|'\\([^']*\\)'\\)"
929 (re-search-forward "<\\|>$" nil t)))
933 (cons (buffer-substring-no-properties
934 ;; Rely on the pattern that didn't match
935 ;; returning nil and on `or' evaluating the
936 ;; second form when the first returns nil.
945 (match-beginning 3)))
949 (list (cons "xsl:key" (xsl-sort-alist key-alist))))
950 (if attribute-set-alist
951 (list (cons "xsl:attribute-set"
952 (xsl-sort-alist attribute-set-alist))))
954 (list (cons "name=" (xsl-sort-alist name-alist))))
956 ;; Sort the mode-alist members, format the mode names nicely,
957 ;; and sort the templates within each mode.
960 (cons (format "mode=\"%s\"" (car x))
961 (xsl-sort-alist (cdr x))))
962 (xsl-sort-alist mode-alist))))
963 (xsl-sort-alist template-alist))))
966 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
970 (defun xsl-grep (pattern filespec)
971 "Grep for PATTERN in files matching FILESPEC.
973 Runs `grep' with PATTERN and FILESPEC as arguments.
975 PATTERN is the pattern on which `grep' is to match. PATTERN is quoted
976 with single quotes in the `grep' command arguments to avoid
977 interpretation of characters in PATTERN. `xsl-grep' maintains a
978 history of PATTERNs so you can easily re-use a previous value.
980 FILESPEC is the names or regular expression for the files to be
981 scanned by grep. Since `xsl-grep' uses `grep', regular expressions
982 and multiple filenames are supported, and \"*.xsl\" and \"*.XSL
983 *.ent\" are both valid FILESPEC values.
985 When called interactively, the initial FILESPEC is taken from
986 xsl-default-filespec, but `xsl-grep' also maintains a history of
987 FILESPEC arguments so you can easily re-use a previous value. The
988 history is shared with `xsl-etags' so you can re-use the same FILESPEC
989 with both functions."
992 (xsl-read-from-minibuffer "Pattern: "
994 'xsl-grep-pattern-history)
995 (xsl-read-from-minibuffer "Files: "
996 (car xsl-filespec-history)
997 'xsl-filespec-history)))
998 ;; Include "--" in the command in case the pattern starts with "-"
999 (grep (format "grep -n %s -- '%s' %s"
1000 (if (not xsl-grep-case-sensitive-flag)
1008 "Major mode for editing XSL stylesheets.
1012 Turning on XSL mode calls the value of the variable `xsl-mode-hook',
1013 if that value is non-nil.
1017 XSL mode includes a comprehensive set of XSL-specific abbreviations
1018 preloaded into the abbreviations table.
1022 Turning on font lock mode causes various XSL syntactic structures to be
1023 highlighted. To turn this on whenever you visit an XSL file, add
1024 the following to your .emacs file:
1025 \(add-hook 'xsl-mode-hook 'turn-on-font-lock\)
1027 Processing stylesheets:
1029 \\[xsl-process] runs a shell command, in a separate process
1030 asynchronously with output going to the buffer *XSL process*. You can
1031 then use the command \\[next-error] to find the next error message and
1032 move to the line in the XSL document that caused it.
1034 The first time that the program is run and whenever you provide a
1035 prefix argument, e.g. \\[universal-argument] \\[xsl-process], prompts
1036 for input filename, stylesheet file, and output filename. Those
1037 values are used with the templates in `xsl-process-command' to
1038 populate this command's command history with the command lines to run
1039 several XSLT processors using those values. Use M-p and M-n to step
1040 through the predefined commands, edit a command if necessary, or enter
1041 a new command line. The next time that this command is run, the
1042 previously executed command is used as the default.
1044 Searching multiple files:
1046 To search multiple files, use \"\\[execute-extended-command] xsl-grep\" and supply the pattern to
1047 search for and the specification of files to search in response to
1051 (kill-all-local-variables)
1052 (use-local-map xsl-mode-map)
1053 (setq mode-name "XSL")
1054 (setq major-mode 'xsl-mode)
1055 (setq local-abbrev-table xsl-mode-abbrev-table)
1056 ;; XEmacs users don't all have imenu
1057 (if (featurep 'imenu)
1059 ;; If you don't have imenu, you'll get a "free variable"
1060 ;; warning for imenu-create-index-function when you
1061 ;; byte-compile, but not having imenu won't cause problems
1062 ;; when you use xslide
1063 (setq imenu-create-index-function 'xsl-imenu-create-index-function)
1064 (setq imenu-extract-index-name-function 'xsl-imenu-create-index-function)
1065 (imenu-add-to-menubar "Templates")))
1067 ;; (make-local-variable 'comment-column)
1068 ;; (setq comment-column 32)
1069 ;; XEmacs change: make `comment-region' work.
1070 (make-local-variable 'comment-start)
1071 (setq comment-start "<!-- ")
1072 (make-local-variable 'comment-end)
1073 (setq comment-end " -->")
1074 (make-local-variable 'comment-indent-function)
1075 (setq comment-indent-function 'xsl-electric-tab)
1076 (make-local-variable 'comment-start-skip)
1077 ;; This will allow existing comments within declarations to be
1078 ;; recognized. [Does not work well with auto-fill, Lst/940205]
1079 ;;(setq comment-start-skip "--[ \t]*")
1080 (setq comment-start-skip "<!--[ \t]*")
1082 ;; later we should move this into the xsl-mode-hook in
1083 ;; our local .emacs file
1086 ;; XSL font-lock highlighting setup
1087 ;; (xsl-font-make-faces)
1088 (make-local-variable 'font-lock-defaults)
1089 (setq font-lock-defaults '(xsl-font-lock-keywords t))
1090 (if (xsl-fsfemacs-p)
1092 (make-local-variable 'font-lock-mark-block-function)
1093 (setq font-lock-mark-block-function
1094 'xsl-font-lock-mark-block-function)))
1095 (make-local-variable 'indent-line-function)
1096 (setq indent-line-function 'xsl-electric-tab)
1097 ;; (make-local-variable 'font-lock-defaults)
1098 ;; (setq font-lock-defaults
1099 ;; '(xsl-font-lock-keywords nil t ((?- . "w")
1102 ;; add an entry to compilation-error-regexp-alist for XSL
1104 ;; (setq compilation-error-regexp-alist
1105 ;; (cons '("file:/c:/projects/xslide/test.xsl:29:
1106 ;;XSL Error on line \\([0-9]*\\) in file \\(.*\\):$" 2 1)
1107 ;; compilation-error-regexp-alist))
1109 (set-syntax-table xsl-mode-syntax-table)
1110 ;; Maybe insert space characters when user hits "Tab" key
1111 (setq indent-tabs-mode xsl-indent-tabs-mode)
1113 xsl-initial-stylesheet-file
1114 (eq (point-min) (point-max)))
1116 (insert-file-contents xsl-initial-stylesheet-file)
1117 (goto-char xsl-initial-stylesheet-initial-point)))
1118 (run-hooks 'xsl-mode-hook))
1123 (defun xsl-submit-bug-report ()
1124 "Submit via mail a bug report on 'xslide'."
1127 (and (y-or-n-p "Do you really want to submit a report on XSL mode? ")
1128 (reporter-submit-bug-report
1129 xslide-maintainer-address
1130 (concat "xslide.el " xslide-version)
1135 "Please change the Subject header to a concise bug description.\nRemember to cover the basics, that is, what you expected to\nhappen and what in fact did happen. Please remove these\ninstructions from your message.")
1137 (goto-char (point-min))
1138 (mail-position-on-field "Subject")
1140 (delete-region (point) (progn (forward-line) (point)))
1142 "Subject: xslide " xslide-version " is wonderful but...\n"))))
1145 (autoload 'reporter-submit-bug-report "reporter")
1147 ;;;; Last provisions
1148 ;;;(provide 'xslide)
1151 ;;;###autoload(add-to-list 'auto-mode-alist '("\\.\\(?:xsl\\|fo\\)$" . xsl-mode))
1153 ;;; xslide.el ends here