1 ;;; psgml-html.el --- HTML mode in conjunction with PSGML
3 ;; Copyright (C) 1994 Nelson Minar.
4 ;; Copyright (C) 1995 Nelson Minar and Ulrik Dickow.
5 ;; Copyright (C) 1996 Ben Wing.
7 ;; This file is part of XEmacs.
9 ;; XEmacs is free software; you can redistribute it and/or modify it
10 ;; under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; XEmacs is distributed in the hope that it will be useful, but
15 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 ;; General Public License for more details.
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with XEmacs; see the file COPYING. If not, write to the Free
21 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 ;; MA 02111-1307, USA.
24 ;;; Synched up with: FSF 19.30.
30 ; Parts were taken from html-helper-mode and from code by Alastair Burt.
32 ; If you'd like to use the hm--html-minor-mode together with this
33 ; mode, you have to put the following line to your ~/.emacs:
34 ; (add-hook 'html-mode-hook 'hm--html-minor-mode)
38 (defvar html-auto-sgml-entity-conversion nil
39 "*Control automatic SGML entity to ISO-8859-1 conversion.")
44 (when html-auto-sgml-entity-conversion
46 (require 'tempo) ;essential part of html-helper-mode
57 "HyperText Markup Language"
60 (defgroup psgml-html nil
61 "HTML mode in conjunction with PSGML"
63 :prefix "html-helper-"
69 (defcustom html-helper-address-string
70 (concat "<a href=\"mailto:"
72 (concat (user-login-name) "@"
73 (or mail-host-address (system-name))))
74 "\">" (user-full-name) "</a>")
75 "*The default author string of each file."
79 (defcustom html-helper-htmldtd-version "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"
80 "*Version of HTML DTD you're using."
84 (defcustom html-helper-do-write-file-hooks t
85 "*If not nil, then modify `local-write-file-hooks' to do timestamps."
89 (defcustom html-helper-build-new-buffer t
90 "*If not nil, then insert `html-helper-new-buffer-strings' for new buffers."
94 (defcustom html-helper-timestamp-hook 'html-helper-default-insert-timestamp
95 "*Hook called for timestamp insertion.
96 Override this for your own timestamp styles."
100 ;; strings you might want to change
102 (defcustom html-helper-new-buffer-template
103 '(html-helper-htmldtd-version
106 " <title>" (p "Document Title: " title) "</title>\n"
110 " <h1>" (s title) "</h1>\n\n"
113 " <address>" html-helper-address-string "</address>\n"
114 (html-helper-return-created-string)
115 html-helper-timestamp-start
116 html-helper-timestamp-end
117 "\n </body>\n</html>\n")
118 "*Template for new buffers.
119 Inserted by `html-helper-insert-new-buffer-strings' if
120 `html-helper-build-new-buffer' is set to t"
124 (defcustom html-helper-timestamp-start "<!-- hhmts start -->\n"
125 "*Start delimiter for timestamps.
126 Everything between `html-helper-timestamp-start' and
127 `html-helper-timestamp-end' will be deleted and replaced with the output
128 of the functions `html-helper-timestamp-hook' if
129 `html-helper-do-write-file-hooks' is t"
133 (defcustom html-helper-timestamp-end "<!-- hhmts end -->"
134 "*End delimiter for timestamps.
135 Everything between `html-helper-timestamp-start' and
136 `html-helper-timestamp-end' will be deleted and replaced with the output
137 of the function `html-helper-insert-timestamp' if
138 `html-helper-do-write-file-hooks' is t"
142 ;; control over what types of tags to load. By default, we load all the
145 (defcustom html-helper-types-to-install
146 '(anchor header logical phys list textel entity image head form table
148 "*List of tag types to install when html-helper-mode is first loaded.
149 If you want to not install some type of tag, override this variable.
150 Order is significant: menus go in this order."
151 :type '(repeat symbol)
154 (defcustom html-helper-use-expert-menu nil
155 "*If not nil, then use the full HTML menu."
159 (defcustom html-helper-user-menu nil
160 "*Extra items to put in the HTML expert menu.
161 The value of this symbol is appended to the beginning of the expert
162 menu that is handed off to easymenu for definition. It should be a
163 list of vectors or lists which themselves are vectors (for submenus)."
167 (defgroup psgml-html-faces nil
168 "Faces for highlighting HTML."
169 :prefix "html-helper-"
173 (defface html-helper-bold-face '((t (:bold t)))
174 "*Face for highlighting bold text."
175 :group 'psgml-html-faces)
177 (defface html-helper-italic-face '((t (:italic t)))
178 "*Face for highlighting italic text."
179 :group 'psgml-html-faces)
181 (defface html-helper-underline-face '((t (:underline t)))
182 "*Face for highlighting underlined text."
183 :group 'psgml-html-faces)
185 (defface html-helper-strikethrough-face '((t (:strikethru t)))
186 "*Face for highlighting strikethrough text."
187 :group 'psgml-html-faces)
189 ;; Could be underline, but it looks ugly at line breaks.
190 (defface html-helper-link-face '((t (:foreground "blue")))
191 "*Face for highlighting link text."
192 :group 'psgml-html-faces)
194 (defface html-helper-significant-tag-face '((t (:foreground "salmon")))
195 "*Face for highlighting html, body, head, form, input and img tags."
196 :group 'psgml-html-faces)
198 ;;}}} end of user variables
199 ;;{{{ type based keymap and menu variable and function setup
201 ;; html-helper-mode has a concept of "type" of tags. Each type is a
202 ;; list of tags that all go together in one keymap and one menu.
203 ;; Types can be added to the system after html-helper has been loaded,
204 ;; briefly by doing html-helper-add-type-to-alist, then
205 ;; html-helper-install-type, then html-helper-add-tag (for each tag)
206 ;; then html-helper-rebuild-menu. See the mode documentation for more detail.
208 (defconst html-helper-type-alist nil
209 "Alist: type of tag -> keymap, keybinding, menu, menu string.
210 Add to this with `html-helper-add-type-to-alist'.")
212 ;;{{{ accessor functions for html-helper-type-alist
214 (defun html-helper-keymap-for (type)
215 "Accessor function for alist: for type, return keymap or nil"
216 (nth 0 (cdr-safe (assq type html-helper-type-alist))))
218 (defun html-helper-key-for (type)
219 "Accessor function for alist: for type, return keybinding or nil"
220 (nth 1 (cdr-safe (assq type html-helper-type-alist))))
222 (defun html-helper-menu-for (type)
223 "Accessor function for alist: for type, return menu or nil"
224 (nth 2 (cdr-safe (assq type html-helper-type-alist))))
226 (defun html-helper-menu-string-for (type)
227 "Accessor function for alist: for type, return menustring or nil"
228 (nth 3 (cdr-safe (assq type html-helper-type-alist))))
230 (defun html-helper-normalized-menu-for (type)
231 "Helper function for building menus from submenus: add on string to menu."
232 (cons (html-helper-menu-string-for type)
233 (eval (html-helper-menu-for type))))
237 (define-derived-mode html-mode sgml-mode "HTML"
238 "Major mode for editing HTML documents.
239 This is based on PSGML mode, and has a sophisticated SGML parser in it.
240 It knows how to properly indent HTML/SGML documents, and it can do
241 a form of document validation (use \\[sgml-next-trouble-spot] to find
242 the next error in your document).
243 Commands beginning with C-z insert various types of HTML tags
244 (prompting for the required information); to iconify or suspend,
246 To literally insert special characters such as < and &, use C-c followed
248 Use \\[sgml-insert-end-tag] to insert the proper closing tag.
249 Use \\[sgml-edit-attributes] to edit the attributes for a tag.
250 Use \\[sgml-show-context] to show the current HTML context.
255 (make-local-variable 'sgml-declaration)
256 (make-local-variable 'sgml-default-doctype-name)
257 (setq sgml-declaration (expand-file-name "html.decl"
259 sgml-default-doctype-name "HTML"
260 sgml-always-quote-attributes t
263 sgml-inhibit-indent-tags '("pre")
264 sgml-minimize-attributes nil
268 ;; font-lock setup for various emacsen: XEmacs, Emacs 19.29+, Emacs <19.29.
269 ;; By Ulrik Dickow <dickow@nbi.dk>. (Last update: 05-Sep-1995).
270 (cond (running-xemacs ; XEmacs/Lucid
271 (put major-mode 'font-lock-keywords-case-fold-search t))
272 ;; XEmacs (19.13, at least) guesses the rest correctly.
273 ;; If any older XEmacsen don't, then tell me.
275 ((string-lessp "19.28.89" emacs-version) ; Emacs 19.29 and later
276 (make-local-variable 'font-lock-defaults)
277 (setq font-lock-defaults '(html-font-lock-keywords t t)))
279 (t ; Emacs 19.28 and older
280 (make-local-variable 'font-lock-keywords-case-fold-search)
281 (make-local-variable 'font-lock-keywords)
282 (make-local-variable 'font-lock-no-comments)
283 (setq font-lock-keywords-case-fold-search t)
284 (setq font-lock-keywords html-font-lock-keywords)
285 (setq font-lock-no-comments t)))
287 (if html-helper-do-write-file-hooks
288 (add-hook 'local-write-file-hooks 'html-helper-update-timestamp))
290 (if (and html-helper-build-new-buffer (zerop (buffer-size)))
291 (html-helper-insert-new-buffer-strings))
293 (set (make-local-variable 'sgml-custom-markup)
294 '(("<A>" "<A HREF=\"\">\r</a>")))
296 ;; Set up the syntax table.
297 (modify-syntax-entry ?< "(>" html-mode-syntax-table)
298 (modify-syntax-entry ?> ")<" html-mode-syntax-table)
299 (modify-syntax-entry ?\" ". " html-mode-syntax-table)
300 (modify-syntax-entry ?\\ ". " html-mode-syntax-table)
301 (modify-syntax-entry ?' "w " html-mode-syntax-table)
303 (tempo-use-tag-list 'html-helper-tempo-tags html-helper-completion-finder)
304 (set (make-local-variable 'imenu-create-index-function)
305 'html-helper-imenu-index)
306 (set (make-local-variable 'imenu-sort-function) nil) ; sorting the
310 ; sigh ... need to call this now to get things working.
311 (sgml-build-custom-menus)
312 ;; (add-submenu nil sgml-html-menu "SGML")
313 (setq sgml-menu-name "HTML")
314 (easy-menu-add sgml-html-menu)
315 (html-helper-rebuild-menu)
316 (unless (featurep 'infodock)
317 (delete-menu-item '("SGML"))))
319 (defvar html-helper-imenu-regexp
320 "\\s-*<h\\([1-9]\\)[^\n<>]*>\\(<[^\n<>]*>\\)*\\s-*\\([^\n<>]*\\)"
321 "*A regular expression matching a head line to be added to the menu.
322 The first `match-string' should be a number from 1-9.
323 The second `match-string' matches extra tags and is ignored.
324 The third `match-string' will be the used in the menu.")
326 ;; Make an index for imenu
327 (defun html-helper-imenu-index ()
328 "Return an table of contents for an html buffer for use with Imenu."
329 (let ((space ?\ ) ; a char
333 (goto-char (point-min))
334 (while (re-search-forward html-helper-imenu-regexp nil t)
338 (* 2 (- (string-to-number (match-string 1)) 1))
342 (setq toc-index (cons (cons toc-str (point)) toc-index))
344 (nreverse toc-index)))
346 (defun html-helper-add-type-to-alist (type)
347 "Add a type specification to the alist.
348 The spec goes (type . (keymap-symbol keyprefix menu-symbol menu-string)).
349 See code for an example."
350 (setq html-helper-type-alist (cons type html-helper-type-alist)))
352 ;; Here are the types provided by html-helper-mode.
353 (mapcar 'html-helper-add-type-to-alist
354 '((entity . (nil nil html-helper-entity-menu "Insert Character Entities"))
355 (textel . (nil nil html-helper-textel-menu "Insert Text Elements"))
356 (head . (html-helper-head-map "\C-zw" html-helper-head-menu "Insert Structural Elements"))
357 (header . (html-helper-base-map "\C-z" html-helper-header-menu "Insert Headers"))
358 (anchor . (html-helper-base-map "\C-z" html-helper-anchor-menu "Insert Hyperlinks"))
359 (logical . (html-helper-base-map "\C-z" html-helper-logical-menu "Insert Logical Styles"))
360 (phys . (html-helper-base-map "\C-z" html-helper-phys-menu "Insert Physical Styles"))
361 (list . (html-helper-list-map "\C-zl" html-helper-list-menu "Insert List Elements"))
362 (form . (html-helper-form-map "\C-zf" html-helper-form-menu "Insert Form Elements"))
363 (table . (html-helper-table-map "\C-zt" html-helper-table-menu "Insert Table Elements"))
364 (image . (html-helper-image-map "\C-zm" html-helper-image-menu "Insert Inlined Images"))
365 (special . (html-helper-base-map "\C-z" html-helper-special-menu "Insert Specials"))))
367 ;; Once html-helper-mode is aware of a type, it can then install the
368 ;; type: arrange for keybindings, menus, etc.
370 (defconst html-helper-installed-types nil
371 "The types that have been installed (used when building menus).
372 There is no support for removing a type once it has been installed.")
374 (defun html-helper-install-type (type)
375 "Install a new tag type: add it to the keymap, menu structures, etc.
376 For this to work, the type must first have been added to the list of types
377 with html-helper-add-type-to-alist."
378 (setq html-helper-installed-types (cons type html-helper-installed-types))
379 (let ((keymap (html-helper-keymap-for type))
380 (key (html-helper-key-for type))
381 (menu (html-helper-menu-for type))
382 (menu-string (html-helper-menu-string-for type)))
386 (define-prefix-command keymap)
387 (define-key html-mode-map key keymap)))
392 ;; install the default types.
393 (mapcar 'html-helper-install-type html-helper-types-to-install)
397 ;;{{{ html-helper-add-tag function for building basic tags
399 (defvar html-helper-tempo-tags nil
400 "List of tags used in completion.")
402 ;; this while loop is awfully Cish
403 ;; isn't there an emacs lisp function to do this?
404 (defun html-helper-string-to-symbol (input-string)
405 "Given a string, downcase it and replace spaces with -.
406 We use this to turn menu entries into good symbols for functions.
407 It's not entirely successful, but fortunately emacs lisp is forgiving."
408 (let* ((s (downcase input-string))
411 (if (char-equal (aref s l) ?\ )
417 (defun html-helper-add-tag (l)
418 "Add a new tag to html-helper-mode.
419 Builds a tempo-template for the tag and puts it into the
420 appropriate keymap if a key is requested. Format:
421 `(html-helper-add-tag '(type keybinding completion-tag menu-name template doc)'"
422 (let* ((type (car l))
423 (keymap (html-helper-keymap-for type))
424 (menu (html-helper-menu-for type))
426 (completer (nth 2 l))
430 (command (tempo-define-template (html-helper-string-to-symbol name)
432 'html-helper-tempo-tags)))
434 (if (null (memq type html-helper-installed-types)) ;type loaded?
436 (if (stringp key) ;bind key somewhere?
437 (if keymap ;special keymap?
438 (define-key (eval keymap) key command) ;t: bind to prefix
439 (define-key html-mode-map key command)) ;nil: bind to global
441 (if menu ;is there a menu?
442 (set menu ;good, cons it in
443 (cons (vector name command t) (eval menu))))
448 ;;{{{ most of the HTML tags
450 ;; These tags are an attempt to be HTML 3.2 compliant
451 ;; For reference see <URL:http://www.w3.org/TR/REC-html32.html>
453 ;; order here is significant: within a tag type, menus and mode help
454 ;; go in the reverse order of what you see here. Sorry about that, it's
461 (entity "\C-c#" "&#" "Ascii Code" ("&#" (r "Ascii: ") ";"))
462 (entity "\C-c\"" """ "Quotation mark" ("""))
463 (entity "\C-c$" "®" "Registered" ("®"))
464 (entity "\C-c@" "©" "Copyright" ("©"))
465 (entity "\C-c-" "­" "Soft Hyphen" ("­"))
466 (entity "\C-c " " " "Nonbreaking Space" (" "))
467 (entity "\C-c&" "&" "Ampersand" ("&"))
468 (entity "\C-c>" ">" "Greater Than" (">"))
469 (entity "\C-c<" "<" "Less Than" ("<"))
472 (logical "v" "<div" "Text Division" ("<div align=\"" (r "Alignment: ") "\">" (r "Text: ") "</div>"))
473 (logical "n" "<center>" "Center" ("<center>" (r "Text: ") "</center>"))
474 (logical "q" "<blockquote>" "Blockquote" ("<blockquote>" (r "Quote: ") "</blockquote>"))
475 (logical "c" "<code>" "Code" ("<code>" (r "Code: ") "</code>"))
476 (logical "x" "<samp>" "Sample" ("<samp>" (r "Sample code") "</samp>"))
477 (logical "r" "<cite>" "Citation" ("<cite>" (r "Citation: ") "</cite>"))
478 (logical "k" "<kbd>" "Keyboard Input" ("<kbd>" (r "Keyboard: ") "</kbd>"))
479 (logical "v" "<var>" "Variable" ("<var>" (r "Variable: ") "</var>"))
480 (logical "d" "<dfn>" "Definition" ("<dfn>" (r "Definition: ") "</dfn>"))
481 (logical "a" "<address>" "Address" ("<address>" r "</address>"))
482 (logical "e" "<em>" "Emphasized" ("<em>" (r "Text: ") "</em>"))
483 (logical "s" "<strong>" "Strong" ("<strong>" (r "Text: ") "</strong>"))
484 (logical "p" "<pre>" "Preformatted" ("<pre>" (r "Text: ") "</pre>"))
487 (phys "p" "<sup>" "Superscript" ("<sup>" (r "Text: ") "</sup>"))
488 (phys "u" "<sub>" "Subscript" ("<sub>" (r "Text: ") "</sub>"))
489 (phys "s" "<small>" "Small" ("<small>" (r "Text: ") "</small>"))
490 (phys "g" "<big>" "Big" ("<big>" (r "Text: ") "</big>"))
491 (phys "-" "<strike>" "Strikethru" ("<strike>" (r "Text: ") "</strike>"))
492 (phys "u" "<u>" "Underline" ("<u>" (r "Text: ") "</u>"))
493 (phys "o" "<i>" "Italic" ("<i>" (r "Text: ") "</i>"))
494 (phys "b" "<b>" "Bold" ("<b>" (r "Text: ") "</b>"))
495 (phys "t" "<tt>" "Fixed" ("<tt>" (r "Text: ") "</tt>"))
498 (header "6" "<h6>" "Header 6" ("<h6>" (r "Header: ") "</h6>"))
499 (header "5" "<h5>" "Header 5" ("<h5>" (r "Header: ") "</h5>"))
500 (header "4" "<h4>" "Header 4" ("<h4>" (r "Header: ") "</h4>"))
501 (header "3" "<h3>" "Header 3" ("<h3>" (r "Header: ") "</h3>"))
502 (header "2" "<h2>" "Header 2" ("<h2>" (r "Header: ") "</h2>"))
503 (header "1" "<h1>" "Header 1" ("<h1>" (r "Header: ") "</h1>"))
506 (form "o" "<option>" "Option" (& "<option>" > ))
507 (form "v" "<option value" "Option with Value" (& "<option value=\"" (r "Value: ") "\">" >))
508 (form "s" "<select" "Selections" ("<select name=\"" (p "Name: ") "\">\n<option>" > "\n</select>")"<select")
509 (form "z" "<input" "Reset Form" ("<input type=\"RESET\" value=\"" (p "Reset button text: ") "\">"))
510 (form "b" "<input" "Submit Form" ("<input type=\"SUBMIT\" value=\"" (p "Submit button text: ") "\">"))
511 (form "i" "<input" "Image Field" ("<input type=\"IMAGE\" name=\"" (p "Name: ") "\" src=\"" (p "Image URL: ") "\">"))
512 (form "h" "<input" "Hidden Field" ("<input type=\"HIDDEN\" name=\"" (p "Name: ") "\" value=\"" (p "Value: ") "\">"))
513 (form "p" "<textarea" "Text Area" ("<textarea name=\"" (p "Name: ") "\" rows=\"" (p "Rows: ") "\" cols=\"" (p "Columns: ") "\">" r "</textarea>"))
514 (form "c" "<input" "Checkbox" ("<input type=\"CHECKBOX\" name=\"" (p "Name: ") "\">"))
515 (form "r" "<input" "Radiobutton" ("<input type=\"RADIO\" name=\"" (p "Name: ") "\">"))
516 (form "t" "<input" "Text Field" ("<input type=\"TEXT\" name=\"" (p "Name: ") "\" size=\"" (p "Size: ") "\">"))
517 (form "f" "<form" "Form" ("<form action=\"" (p "Action: ") "\" method=\"" (p "Method: ") "\">\n</form>\n"))
520 (table "d" "<td>" "Data cell" ("<td>"))
521 (table "h" "<th>" "Header" ("<th>"))
522 (table "r" "<tr>" "Row" ("<tr>"))
523 (table "t" "<table>" "Table" ("<table>\n<tr>\n</table>\n"))
526 (list "t" "<dt>" "Definition Item" (& "<dt>" > (p "Term: ") "\n<dd>" > (r "Definition: ")))
527 (list "l" "<li>" "List Item" (& "<li>" > (r "Item: ")))
528 (list "r" "<dir>" "DirectoryList" (& "<dir>" > "\n<li>" > (r "Item: ") "\n</dir>" >))
529 (list "m" "<menu>" "Menu List" (& "<menu>" > "\n<li>" > (r "Item: ") "\n</menu>" >))
530 (list "o" "<ol>" "Ordered List" (& "<ol>" > "\n<li>" > (r "Item: ") "\n</ol>" >))
531 (list "d" "<dl>" "Definition List" (& "<dl>" > "\n<dt>" > (p "Term: ") "\n<dd>" > (r "Definition: ") "\n</dl>" >))
532 (list "u" "<ul>" "Unordered List" (& "<ul>" > "\n<li>" > (r "Item: ") "\n</ul>" >))
535 (anchor "n" "<a name=" "Link Target" ("<a name=\"" (p "Anchor name: ") "\">" (r "Anchor text: ") "</a>"))
536 (anchor "h" "<a href=" "Hyperlink" ("<a href=\"" (p "URL: ") "\">" (r "Anchor text: ") "</a>"))
539 (image "m" "<map name=" "Image map" ("<map name=\"" (r "Map name: ") "\">"))
540 (image "a" nil "Aligned Image" ("<img align=\"" (r "Alignment: ") "\" src=\"" (r "Image URL: ") "\">"))
541 (image "i" "<img src=" "Image" ("<img src=\"" (r "Image URL: ") "\">"))
542 (image "e" "<img align=" "Aligned Image With Alt. Text" ("<img align=\"" (r "Alignment: ") "\" src=\"" (r "Image URL: ") "\" alt=\"" (r "Text URL: ") "\">"))
543 (image "t" "<img alt=" "Image With Alternate Text" ("<img alt=\"" (r "Text URL: ") "\" src=\"" (r "Image URL: ") "\">"))
546 (special "a" "<applet code=" "Applet" ("<applet code=\"" (r "Applet class: ") "\" width=" (r "Applet width: ") " height=" (r "Applet height: ") ">"))
547 (special "b" "<basefont size=" "Base font size" ("<basefont size=" (r "Font size: ") ">"))
548 (special "c" "<font color=" "Font color" ("<font color=\"" (r "Color: ") "\">" (r "Text: ") "</font>"))
549 (special "s" "<font size=" "Font size" ("<font size=" (r "Font size: ") ">" (r "Text: ") "</font>"))
552 (textel "\C-c=" nil "Horizontal Line" (& "<hr>\n"))
553 (textel "\C-c\C-m" nil "Line Break" ("<br>\n"))
554 (textel "\e\C-m" nil "Paragraph" ("<p>" (progn (sgml-indent-line) nil) "\n"))
557 (head "H" "<head>" "Head" ("<head>\n" "</head>\n"))
558 (head "B" "<body>" "Body" ("<body>\n" "</body>\n"))
559 (head "i" "<isindex>" "Isindex" ("<isindex>\n"))
560 (head "n" "<nextid>" "Nextid" ("<nextid>\n"))
561 (head "h" "<meta http-equiv=" "HTTP Equivalent" ("<meta http-equiv=\"" (p "Equivalent: ") "\" content=\"" (r "Content: ") "\">\n"))
562 (head "m" "<meta name=" "Meta Name" ("<meta name=\"" (p "Name: ") "\" content=\"" (r "Content: ") "\">\n"))
563 (head "l" "<link" "Link" ("<link href=\"" p "\">"))
564 (head "s" "<script>" "Script" ("<script>"))
565 (head "y" "<style>" "Style" ("<style>"))
566 (head "b" "<base" "Base" ("<base href=\"" r "\">"))
567 (head "t" "<title>" "Title" ("<title>" (r "Document title: ") "</title>"))
571 ;;{{{ html-helper-smart-insert-item
573 ;; there are two different kinds of items in HTML - those in regular
574 ;; lists <li> and those in dictionaries <dt>..<dd>
575 ;; This command will insert the appropriate one depending on context.
577 (defun html-helper-smart-insert-item (&optional arg)
578 "Insert a new item, either in a regular list or a dictionary."
580 (let ((case-fold-search t))
583 (re-search-backward "<li>\\|<dt>\\|<ul>\\|<ol>\\|<dd>\\|<menu>\\|<dir>\\|<dl>" nil t)
584 (looking-at "<dt>\\|<dl>\\|<dd>"))
585 (tempo-template-html-definition-item arg)
586 (tempo-template-html-list-item arg))))
588 ;; special keybindings in the prefix maps (not in the list of tags)
589 (and (boundp 'html-helper-base-map)
590 (define-key html-helper-base-map "i" 'html-helper-smart-insert-item))
592 (define-key html-mode-map "\C-z\C-z" 'suspend-or-iconify-emacs)
593 (define-key html-mode-map "\C-zg" 'html-insert-mailto-reference-from-click)
595 ;; and, special menu bindings
596 (and (boundp 'html-helper-list-menu)
597 (setq html-helper-list-menu
598 (cons '["List Item" html-helper-smart-insert-item t] html-helper-list-menu)))
604 ;; menus are built for easymenu. html-helper-add-tag builds
605 ;; submenus based on tag type, the expert menu code lumps them
606 ;; together into one list and calls easy-menu-define
608 (defun html-helper-rebuild-menu nil
609 "Rebuild and install the HTML menu (using `easy-menu-define').
610 If `html-helper-use-expert-menu' is nil, then just use a novice menu."
611 (let ((menu (html-helper-expert-menu)))
612 (easy-menu-remove menu)
613 (easy-menu-add menu html-mode-map)))
615 (defun html-helper-toggle-expert-menu (&optional arg)
616 "Toggle full HTML menus. Optional arg acts like minor-mode args."
618 (setq html-helper-use-expert-menu
619 (if (null arg) (not html-helper-use-expert-menu)
620 (> (prefix-numeric-value arg) 0)))
621 (html-helper-rebuild-menu))
623 ;; Expert menus: consed up out of html-helper-installed-types
624 (defun html-helper-expert-menu ()
625 "This menu is based on the current value of `html-helper-installed-types'.
626 This function can be called again, it redoes the entire menu."
627 ;; Start with the user-provided menu stuff
628 (let ((html-helper-mode-menu html-helper-user-menu))
629 ;; Now cons in the browse-url functions
630 (if (fboundp 'browse-url-of-file)
631 (setq html-helper-mode-menu
632 (cons '["Load this Buffer in Browser" browse-url-of-file t]
633 html-helper-mode-menu)))
634 (setq html-helper-mode-menu
635 (cons (vector "Browse URL at point"
636 (when (and (boundp 'browse-url-browser-function)
637 browse-url-browser-function)
638 ;; If the value is not a function it should be a list of pairs
639 ;; (REGEXP . FUNCTION)
641 ((functionp browse-url-browser-function))
642 ((listp browse-url-browser-function)
643 (dolist (elt browse-url-browser-function)
644 (when (not (string-match "mail" (symbol-name (cdr-safe elt))))
645 (return (cdr elt)))))))
647 html-helper-mode-menu))
649 ;; cons in the timestamp delimiters
650 (setq html-helper-mode-menu
651 (cons '["Insert Timestamp Delimiter"
652 html-helper-insert-timestamp-delimiter-at-point t]
653 html-helper-mode-menu))
655 ;; now cons up the main menu out of the submenus
657 (function (lambda (type)
658 (setq html-helper-mode-menu
659 (cons (html-helper-normalized-menu-for type)
660 html-helper-mode-menu))))
661 html-helper-installed-types)
663 ;; now tack on our name
664 (setq html-helper-mode-menu (cons "Insert" html-helper-mode-menu))
667 (define-key html-mode-map (kbd "<M-iso-left-tab>") 'tempo-complete-tag)
668 ;;("\M-\C-f" tempo-forward-mark)
669 ;;("\M-\C-b" tempo-backward-mark)
671 html-helper-mode-menu))
675 ;;{{{ patterns for font-lock
677 ; Old patterns from html-mode.el
678 ;(defvar html-font-lock-keywords
680 ; '("\\(<[^>]*>\\)+" . font-lock-comment-face)
681 ; '("[Hh][Rr][Ee][Ff]=\"\\([^\"]*\\)\"" 1 font-lock-string-face t)
682 ; '("[Ss][Rr][Cc]=\"\\([^\"]*\\)\"" 1 font-lock-string-face t))
683 ; "Patterns to highlight in HTML buffers.")
685 ;; By Ulrik Dickow <dickow@nbi.dk>.
687 ;; Originally aimed at Emacs 19.29. Later on disabled syntactic fontification
688 ;; and reordered regexps completely, to be compatible with XEmacs (it doesn't
689 ;; understand OVERRIDE=`keep').
691 ;; We make an effort on handling nested tags intelligently.
694 (defvar html-font-lock-keywords
695 (let (;; Titles and H1's, like function defs.
696 ;; We allow for HTML 3.0 attributes, like `<h1 align=center>'.
697 (tword "\\(h1\\|title\\)\\([ \t\n]+[^>]+\\)?")
698 ;; Names of tags to boldify.
699 (bword "\\(b\\|h[2-4]\\|strong\\)\\([ \t\n]+[^>]+\\)?")
700 ;; Names of tags to italify.
701 (iword "\\(address\\|cite\\|em\\|i\\|var\\)\\([ \t\n]+[^>]+\\)?")
702 ;; Regexp to match shortest sequence that surely isn't a bold end.
703 ;; We simplify a bit by extending "</strong>" to "</str.*".
704 ;; Do similarly for non-italic and non-title ends.
705 (not-bend (concat "\\([^<]\\|<\\([^/]\\|/\\([^bhs]\\|"
707 "h\\([^2-4]\\|[2-4][^>]\\)\\|"
708 "s\\([^t]\\|t[^r]\\)\\)\\)\\)"))
709 (not-iend (concat "\\([^<]\\|<\\([^/]\\|/\\([^aceiv]\\|"
710 "a\\([^d]\\|d[^d]\\)\\|"
711 "c\\([^i]\\|i[^t]\\)\\|"
712 "e\\([^m]\\|m[^>]\\)\\|"
714 "v\\([^a]\\|a[^r]\\)\\)\\)\\)"))
715 (not-tend (concat "\\([^<]\\|<\\([^/]\\|/\\([^ht]\\|"
716 "h[^1]\\|t\\([^i]\\|i[^t]\\)\\)\\)\\)")))
717 (list ; Avoid use of `keep', since XEmacs will treat it the same as `t'.
718 ;; First fontify the text of a HREF anchor. It may be overridden later.
719 ;; Anchors in headings will be made bold, for instance.
720 '("<a\\s-+href[^>]*>\\([^>]+\\)</a>"
721 1 html-helper-link-face t)
722 ;; Tag pairs like <b>...</b> etc.
723 ;; Cunning repeated fontification to handle common cases of overlap.
724 ;; Bold complex --- possibly with arbitrary other non-bold stuff inside.
725 (list (concat "<" bword ">\\(" not-bend "*\\)</\\1>")
726 3 'html-helper-bold-face t)
727 ;; Italic complex --- possibly with arbitrary non-italic kept inside.
728 (list (concat "<" iword ">\\(" not-iend "*\\)</\\1>")
729 3 'html-helper-italic-face t)
730 ;; Bold simple --- first fontify bold regions with no tags inside.
731 (list (concat "<" bword ">\\(" "[^<]" "*\\)</\\1>")
732 3 'html-helper-bold-face t)
733 ;; Any tag, general rule, just after bold/italic stuff.
734 '("\\(<[^>]*>\\)" 1 font-lock-type-face t)
735 ;; Titles and level 1 headings (anchors do sometimes appear in h1's)
736 (list (concat "<" tword ">\\(" not-tend "*\\)</\\1>")
737 3 'font-lock-function-name-face t)
738 ;; Underline is rarely used. Only handle it when no tags inside.
739 '("<u>\\([^<]*\\)</u>" 1 html-helper-underline-face t)
740 ;; Ditto for strikethrough.
741 '("<strike>\\([^<]*\\)</strike>" 1 html-helper-strikethrough-face t)
742 ;; Forms, anchors & images (also fontify strings inside)
743 '("\\(<\\(form\\|i\\(mg\\|nput\\)\\)\\>[^>]*>\\)"
744 1 html-helper-significant-tag-face t)
745 '("</a>" 0 font-lock-keyword-face t)
746 '("\\(<a\\b[^>]*>\\)" 1 font-lock-keyword-face t)
747 '("=[ \t\n]*\\(\"[^\"]+\"\\)" 1 font-lock-string-face t)
748 ;; Large-scale structure keywords (like "program" in Fortran).
749 ;; "<html>" "</html>" "<body>" "</body>" "<head>" "</head>" "</form>"
750 '("</?\\(body\\|form\\|h\\(ead\\|tml\\)\\)>"
751 0 html-helper-significant-tag-face t)
752 ;; HTML special characters
753 '("&[^;\n]*;" 0 font-lock-string-face t)
754 ;; SGML things like <!DOCTYPE ...> with possible <!ENTITY...> inside.
755 '("\\(<![a-z]+\\>[^<>]*\\(<[^>]*>[^<>]*\\)*>\\)"
756 1 font-lock-comment-face t)
757 ;; Comments: <!-- ... -->. They traditionally override anything else.
758 ;; It's complicated 'cause we won't allow "-->" inside a comment, and
759 ;; font-lock colours the *longest* possible match of the regexp.
760 '("\\(<!--\\([^-]\\|-[^-]\\|--[^>]\\)*-->\\)"
761 1 font-lock-comment-face t)))
762 "Additional expressions to highlight in HTML mode.")
764 (put 'html-mode 'font-lock-defaults '(html-font-lock-keywords nil t))
768 ;;{{{ patterns for hilit19
770 ;; Define some useful highlighting patterns for the hilit19 package.
771 ;; These will activate only if hilit19 has already been loaded.
772 ;; Thanks to <dickow@nbi.dk> for some pattern suggestions
774 (if (featurep 'hilit19)
775 (hilit-set-mode-patterns
777 '(("<!--" "-->" comment)
778 ("<![a-z]+\\>[^<>]*\\(<[^>]*>[^<>]*\\)*>" nil comment) ;<!DOCTYPE ...>
779 ("<title>" "</title>" defun)
780 ("<h[1-6]>" "</h[1-6]>" bold) ;only colour inside tag
783 ("<img\\b" ">" include)
784 ("<option\\|</?select\\|<input\\|</?form\\|</?textarea" ">" include)
785 ;; First <i> highlighting just handles unnested tags, then do nesting
786 ("<i>[^<]*</i>" nil italic)
788 ("<i>" "</i>" italic)
789 ("<u>" "</u>" underline)
790 ("&[^;\n]*;" nil string)
792 nil 'case-insensitive)
797 ;;{{{ completion finder for tempo
799 ;; The regexp finds everything between the last < or & and point,
800 ;; which is good enough to match the tags HTML might complete.
801 (defvar html-helper-completion-finder "\\(\\(<\\|&\\).*\\)\\="
802 "Passed to tempo-use-tag-list, used to find tags to complete.")
808 (defun html-helper-update-timestamp ()
809 "Basic function for updating timestamps.
810 It finds the timestamp in the buffer by looking for
811 `html-helper-timestamp-start', deletes all text up to
812 `html-helper-timestamp-end', and runs `html-helper-timestamp-hook' which
813 will should insert an appropriate timestamp in the buffer."
815 (goto-char (point-max))
816 (if (not (search-backward html-helper-timestamp-start nil t))
817 (message "timestamp delimiter start was not found")
818 (let ((ts-start (+ (point) (length html-helper-timestamp-start)))
819 (ts-end (if (search-forward html-helper-timestamp-end nil t)
820 (- (point) (length html-helper-timestamp-end))
823 (message "timestamp delimiter end was not found. Type C-c C-t to insert one.")
824 (delete-region ts-start ts-end)
826 (run-hooks 'html-helper-timestamp-hook)))))
829 (defun html-helper-return-created-string ()
830 "Return a \"Created:\" string."
831 (let ((time (current-time-string)))
832 (concat "<!-- Created: "
833 (substring time 0 20)
834 (nth 1 (current-time-zone))
839 (defun html-helper-default-insert-timestamp ()
840 "Default timestamp insertion function."
841 (let ((time (current-time-string)))
842 (insert "Last modified: "
843 (substring time 0 20)
844 (nth 1 (current-time-zone))
849 (defun html-helper-insert-timestamp-delimiter-at-point ()
850 "Simple function that inserts timestamp delimiters at point.
851 Useful for adding timestamps to existing buffers."
853 (insert html-helper-timestamp-start)
854 (insert html-helper-timestamp-end))
858 (defun mail-address-at-point (pos &optional buffer)
859 "Return a list (NAME ADDRESS) of the address at POS in BUFFER."
860 (or buffer (setq buffer (current-buffer)))
866 (or (re-search-forward "[\n,]" nil t)
867 (error "Can't find address at position"))
870 (or (re-search-backward "[\n,:]" nil t)
871 (error "Can't find address at position"))
873 (re-search-forward "[ \t]*" nil t)
875 (mail-extract-address-components (buffer-substring beg end))))))
877 (defun html-insert-mailto-reference-from-click ()
878 "Insert a mailto: reference for the clicked-on e-mail address."
881 (message "Click on a mail address:")
883 (setq event (next-command-event))
884 (or (mouse-event-p event)
886 (let ((lis (mail-address-at-point (event-closest-point event)
887 (event-buffer event))))
888 (insert "<a href=\"mailto:" (car (cdr lis)) "\">"
889 (or (car lis) (car (cdr lis))) "</a>"))))
892 (defun html-quote-region (begin end)
893 "\"Quote\" any characters in the region that have special HTML meanings.
894 This converts <'s, >'s, and &'s into the HTML commands necessary to
895 get those characters to appear literally in the output."
899 (while (search-forward "&" end t)
903 (setq end (+ 4 end)))
905 (while (search-forward "<" end t)
909 (setq end (+ 3 end)))
911 (while (search-forward ">" end t)
915 (setq end (+ 3 end)))))
917 ;;{{{ html-helper-insert-new-buffer-strings
919 (tempo-define-template "html-skeleton" html-helper-new-buffer-template
921 "Insert a skeleton for a HTML document")
923 (defun html-helper-insert-new-buffer-strings ()
924 "Insert `html-helper-new-buffer-strings'."
925 (tempo-template-html-skeleton))
930 (autoload 'html-mode "psgml-html" "HTML mode." t)
932 (defvar sgml-html-menu
934 (append '(["View in default browser" browse-url-of-buffer t]
935 ["View in Firefox" sgml-html-netscape-file
936 (buffer-file-name (current-buffer))]
937 ["View in Konqueror" sgml-html-kfm-file
938 (buffer-file-name (current-buffer))]
939 ["View in W3" w3-preview-this-buffer t]
941 ["HTML-Quote Region" html-quote-region t]
943 (cdr sgml-main-menu))))
945 (defun sgml-html-netscape-file ()
946 "Preview the file for the current buffer in Firefox."
949 (concat "file:" (buffer-file-name (current-buffer)))))
951 (defun sgml-html-kfm-file ()
952 "Preview the file for the current buffer in Konqueror."
955 (concat "file:" (buffer-file-name (current-buffer)))))
957 ;;;###autoload(add-to-list 'auto-mode-alist '("\\.[sj]?html?\\'" . html-mode))
958 ;;;###autoload(add-to-list 'auto-mode-alist '("\\.jsp\\'" . html-mode))
960 ;;; end of psgml-html.el