1 ;;; nxhtml-mode.el --- Edit XHTML files
3 ;; Author: Lennart Borgman (lennart O borgman A gmail O com)
4 ;; Parts are from Peter Heslin (see below)
7 ;; Last-Updated: 2008-12-28 Sun
12 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16 ;; The purpose of nxhtml.el is to add some features that are useful
17 ;; when editing XHTML files to nxml-mode. For more information see
23 ;; See the file readme.txt in the directory above this file. Or, if
24 ;; you do not have that follow the instructions below.
27 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
31 ;; 2006-04-25: Added completion for href, src etc. Removed xhtmlin.
34 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
36 ;; This file is not part of Emacs
38 ;; This program is free software; you can redistribute it and/or
39 ;; modify it under the terms of the GNU General Public License as
40 ;; published by the Free Software Foundation; either version 2, or (at
41 ;; your option) any later version.
43 ;; This program is distributed in the hope that it will be useful, but
44 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
45 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
46 ;; General Public License for more details.
48 ;; You should have received a copy of the GNU General Public License
49 ;; along with this program; see the file COPYING. If not, write to
50 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
51 ;; Boston, MA 02111-1307, USA.
54 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
58 (eval-when-compile (require 'cl))
59 (eval-when-compile (require 'hideshow))
61 (eval-when-compile (require 'appmenu-fold nil t))
62 (eval-when-compile (require 'fold-dwim nil t))
63 (eval-when-compile (require 'foldit nil t))
64 (eval-when-compile (require 'html-pagetoc nil t))
65 (eval-when-compile (require 'html-toc nil t))
66 (eval-when-compile (require 'mumamo nil t))
67 (eval-when-compile (require 'mlinks nil t))
68 (eval-when-compile (require 'nxhtml-base))
69 ;;(eval-when-compile (require 'nxhtml-menu)) ;; recursive load
70 (eval-when-compile (require 'ourcomments-util nil t))
71 (eval-and-compile (require 'typesetter nil t))
72 (eval-when-compile (require 'xhtml-help nil t))
73 (eval-when-compile (require 'popcmp nil t))
75 ;; (unless (or (< emacs-major-version 23)
76 ;; (boundp 'nxhtml-menu:version)
77 ;; (featurep 'nxhtml-autostart))
78 ;; (let ((efn (expand-file-name
80 ;; (file-name-directory
82 ;; (when (boundp 'bytecomp-filename) bytecomp-filename)
83 ;; buffer-file-name)))))
84 ;; (message "efn=%s" efn)
86 ;; (require 'rng-valid)
87 ;; (require 'rng-nxml)))
91 (require 'nxml-mode nil t)
92 (require 'rng-nxml nil t)
93 (require 'rng-valid nil t)
95 ;; Require nxml things conditionally to silence byte compiler under
97 (eval-and-compile (require 'rngalt nil t))
100 (require 'url-expand)
101 (require 'popcmp nil t)
102 (eval-when-compile (require 'html-imenu nil t))
103 (eval-when-compile (require 'tidy-xhtml nil t))
104 (eval-when-compile (require 'html-quote nil t))
106 (defun nxhtml-version ()
107 "Show nxthml version."
109 (message "nXhtml mode version %s" nxhtml-menu:version))
111 ;;(defun nxhtml-nxml-fontify-attribute (att &optional namespace-declaration)
112 ;;"Holds the original `nxml-fontify-attribute' function.")
113 ;;(fset 'nxhtml-nxml-fontify-attribute (symbol-function 'nxml-fontify-attribute))
116 (defun nxhtml-turn-onoff-tag-do-also (on)
117 (add-hook 'nxhtml-mode-hook 'nxhtml-check-tag-do-also)
118 (dolist (b (buffer-list))
119 (when (with-current-buffer b
120 (eq major-mode 'nxhtml-mode))
123 (add-hook 'rngalt-complete-tag-hooks 'nxhtml-complete-tag-do-also t t)
125 (remove-hook 'rngalt-complete-tag-hooks 'nxhtml-complete-tag-do-also t)
128 ;;(define-toggle nxhtml-tag-do-also t
129 (define-minor-mode nxhtml-tag-do-also
130 "When completing tag names do some more if non-nil.
131 For some tag names additional things can be done at completion to
132 speed writing up. For example for an <img ...> tag `nxhtml-mode'
133 can prompt for src attribute and add width and height attributes
134 if this attribute points to a local file.
136 You can add additional elisp code for completing to
137 `nxhtml-complete-tag-do-also'."
141 (nxhtml-turn-onoff-tag-do-also nxhtml-tag-do-also))
142 (when nxhtml-tag-do-also (nxhtml-tag-do-also 1))
144 (defun nxhtml-tag-do-also-toggle ()
145 "Toggle `nxhtml-tag-do-also'."
147 (nxhtml-tag-do-also (if nxhtml-tag-do-also -1 1)))
149 (defun nxhtml-check-tag-do-also ()
150 (when nxhtml-tag-do-also
151 (nxhtml-turn-onoff-tag-do-also t)))
154 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
159 ;; This part is origially taken from
160 ;; http://www.emacswiki.org/cgi-bin/wiki/NxmlModeForXHTML and was
161 ;; originally written by Peter Heslin, but has been changed rather
164 ;; (defun nxhtml-hs-adjust-beg-func (pos)
167 ;; ;; (search-backward "<" nil t)
169 ;; ;; (search-forward ">" nil t)
173 (defun nxhtml-hs-forward-sexp-func (pos)
174 (nxhtml-hs-forward-element))
176 (defun nxhtml-hs-forward-element ()
177 (let ((nxml-sexp-element-flag))
178 (setq nxml-sexp-element-flag (not (looking-at "<!--")))
179 (unless nil ;;(looking-at outline-regexp)
180 ;;(condition-case nil
181 (nxml-forward-balanced-item 1)
185 (defun nxhtml-setup-for-fold-dwim ()
186 (make-local-variable 'outline-regexp)
187 (setq outline-regexp "\\s *<\\([h][1-6]\\|html\\|body\\|head\\)\\b")
188 (make-local-variable 'outline-level)
189 (setq outline-level 'nxhtml-outline-level)
190 ;;(outline-minor-mode 1)
192 (setq hs-special-modes-alist (assq-delete-all 'nxhtml-mode hs-special-modes-alist))
193 (add-to-list 'hs-special-modes-alist
195 ;;"<!--\\|<[^/>]>\\|<[^/][^>]*[^/]>"
196 "<!--\\|<[^/>]>\\|<[^/][^>]*"
198 "<!--" ;; won't work on its own; uses syntax table
199 nxhtml-hs-forward-sexp-func
200 nil ;nxhtml-hs-adjust-beg-func
202 (set (make-local-variable 'hs-set-up-overlay) 'nxhtml-hs-set-up-overlay)
203 (put 'hs-set-up-overlay 'permanent-local t)
204 (when (featurep 'appmenu-fold)
205 (appmenu-fold-setup))
208 (defun nxhtml-hs-start-tag-end (beg)
212 (or (search-forward ">" (line-end-position) t)
213 (line-end-position)))))
215 (defun nxhtml-hs-set-up-overlay (ovl)
216 (overlay-put ovl 'priority (1+ mlinks-link-overlay-priority))
218 (setq foldit-hs-start-tag-end-func 'nxhtml-hs-start-tag-end)
219 (foldit-hs-set-up-overlay ovl)))
221 (defun nxhtml-outline-level ()
222 ;;(message "nxhtml-outline-level=%s" (buffer-substring (match-beginning 0) (match-end 0)))(sit-for 2)
223 ;; Fix-me: What did I intend to do???
224 ;; (let ((tag (buffer-substring (match-beginning 1) (match-end 1))))
225 ;; (if (eq (length tag) 2)
226 ;; (- (aref tag 1) ?0)
231 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
235 (defcustom nxhtml-use-imenu t
236 "Use imenu in nxhtml-mode."
242 (defcustom nxhtml-default-encoding 'iso-8859-1
247 (defun nxhtml-insert-empty-frames-page ()
248 "Insert an empty frames page."
250 ;;(unless (= 0 (buffer-size))
251 (unless (nxhtml-can-insert-page-here)
252 (error "Buffer is not empty"))
254 "<?xml version=\"1.0\" encoding=\""
255 (symbol-name nxhtml-default-encoding)
257 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\"
258 \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">
259 <html xmlns=\"http://www.w3.org/1999/xhtml\">
263 <frameset cols=\"50%, 50%\">
264 <frame src=\"about:blank\" />
265 <frame src=\"about:blank\" />
268 (search-backward "</title>"))
270 (defun nxhtml-insert-empty-page ()
271 "Insert an empty XHTML page."
273 ;;(unless (= 0 (buffer-size))
274 (unless (nxhtml-can-insert-page-here)
275 (error "Buffer is not empty"))
277 "<?xml version=\"1.0\" encoding=\""
278 (symbol-name nxhtml-default-encoding)
280 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
281 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
282 <html xmlns=\"http://www.w3.org/1999/xhtml\">
289 (search-backward "</title>"))
291 (defun nxhtml-empty-page-completion ()
292 ;;(unless (= 0 (buffer-size)) (error "Buffer is not empty"))
293 (let* ((frames "Frameset page")
294 (normal "Normal page")
295 ;;(vlhead "Validation header")
296 ;;popcmp-popup-completion
297 (initial nil) ;;(unless popcmp-popup-completion normal))
298 (hist (if (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
299 ;;(list vlhead frames normal)
301 (list frames normal)))
303 (completion-ignore-case t))
304 (setq res (popcmp-completing-read "Insert: " hist nil t initial (cons 'hist (length hist))))
305 (cond ((string= res frames)
306 (nxhtml-insert-empty-frames-page))
307 ((string= res normal)
308 (nxhtml-insert-empty-page))
309 ;;((string= res vlhead)
310 ;; (nxhtml-validation-header-mode))
312 (error "Bad res=%s" res))))
313 (rng-auto-set-schema))
317 (defvar nxhtml-mode-hook nil)
318 ;;(add-hook 'nxhtml-mode-hook 'nxml-fontify-buffer)
320 (defun nxhtml-help ()
322 (describe-function 'nxhtml-mode))
324 (defvar nxhtml-current-validation-header nil)
325 (make-variable-buffer-local 'nxhtml-current-validation-header)
326 (put 'nxhtml-current-validation-header 'permanent-local t)
329 ;; FIX-ME: When should this be done? Get tidy-menu-symbol:
330 (when (featurep 'tidy-xhtml)
334 ;; (eval-after-load 'css-mode
335 ;; '(when (featurep 'xhtml-help)
336 ;; (define-key css-mode-map [(control ?c) ?? ?c] 'xhtml-help-show-css-ref)
338 ;; (add-hook 'css-mode-hook
340 ;; (and (featurep 'xhtml-help)
341 ;; (boundp 'css-mode-map)
342 ;; (define-key css-mode-map [(control ?c) ?? ?c]
343 ;; 'xhtml-help-show-css-ref))))
345 ;; This should be run in `change-major-mode-hook'."
346 ;; (defun nxhtml-change-mode ()
347 ;; (when (fboundp 'mlinks-mode)
350 (when (< emacs-major-version 23)
351 (defun nxml-change-mode ()
352 ;; Remove overlays used by nxml-mode.
356 (rng-validate-mode -1)
357 (let ((inhibit-read-only t)
359 (modified (buffer-modified-p)))
360 (nxml-with-invisible-motion
361 (remove-text-properties (point-min) (point-max) '(face nil)))
362 (set-buffer-modified-p modified))))))
364 (defcustom nxhtml-heading-element-name-regexp "[a-z]*"
365 "Used for `nxml-heading-element-name-regexp."
369 ;; Fix-me: Put this is a separate file and load it only if nxml is
371 (put 'nxhtml-mode 'flyspell-mode-predicate 'sgml-mode-flyspell-verify)
373 (define-derived-mode nxhtml-mode nxml-mode "nXhtml"
374 "Major mode for editing XHTML documents.
375 It is based on `nxml-mode' and adds some features that are useful
376 when editing XHTML files.\\<nxhtml-mode-map>
378 The XML menu contains functionality added by `nxml-mode' \(on
379 which this major mode is based). There is also a popup menu
380 added to the \[apps] key.
382 The most important features are probably completion and
383 validation, which is inherited from `nxml-mode' with some small
384 addtions. In very many situation you can use completion. To
385 access it type \\[nxml-complete]. Completion has been enhanced in
388 - If region is active and visible then completion will surround the
389 region with the chosen tag's start and end tag. However only the
390 starting point is checked for validity. If something is wrong after
391 insertion you will however immediately see it if you have validation
393 - It can in some cases give assistance with attribute values.
394 - Completion can be customized, see the menus XHTML - Completion:
395 * You can use a menu popup style completion.
396 * You can have alternatives grouped.
397 * You can get a short help text shown for each alternative.
398 - There does not have to be a '<' before point for tag name
399 completion. (`nxml-mode' requires a '<' before point for tag name
401 - Completes xml version and encoding.
402 - Completes in an empty buffer, ie inserts a skeleton.
404 Here are all key bindings in nxhtml-mode itself:
408 Notice that other minor mode key bindings may also be active, as
409 well as emulation modes. Do \\[describe-bindings] to get a list
410 of all active key bindings. Also, *VERY IMPORTANT*, if mumamo is
411 used in the buffer each mumamo chunk has a different major mode
412 with different key bindings. You can however still see all
413 bindings with \\[describe-bindings], but you have to do that with
414 point in the mumamo chunk you want to know the key bindings in."
415 (set (make-local-variable 'nxml-heading-element-name-regexp)
416 nxhtml-heading-element-name-regexp)
417 (when (fboundp 'nxml-change-mode)
418 (add-hook 'change-major-mode-hook 'nxml-change-mode nil t))
419 ;;(add-hook 'change-major-mode-hook 'nxhtml-change-mode nil t)
420 (when (featurep 'rngalt)
421 (add-hook 'nxml-completion-hook 'rngalt-complete nil t))
422 ;;(define-key nxhtml-mode-map [(meta tab)] 'nxml-complete)
423 ;;(nxhtml-menu-mode 1)
424 (when (and nxhtml-use-imenu
425 (featurep 'html-imenu))
426 (add-hook 'nxhtml-mode-hook 'html-imenu-setup nil t))
428 (nxhtml-setup-for-fold-dwim)
429 (when (featurep 'rngalt)
430 (set (make-local-variable 'rngalt-completing-read-tag) 'nxhtml-completing-read-tag)
431 (set (make-local-variable 'rngalt-completing-read-attribute-name) 'nxhtml-completing-read-attribute-name)
432 (set (make-local-variable 'rngalt-completing-read-attribute-value) 'nxhtml-completing-read-attribute-value)
433 (set (make-local-variable 'rngalt-complete-first-try) 'nxhtml-complete-first-try)
434 (set (make-local-variable 'rngalt-complete-last-try) 'nxhtml-complete-last-try)
437 ;; Fix-me: The nxhtml-mode-map is define by define-derived-mode, but
438 ;; how should keys be added?
440 ;; Replace the Insert End Tag function:
441 (define-key nxhtml-mode-map [(control ?c) (control ?f)] 'rngalt-finish-element)
443 ;; Put completion on the normal key?
444 (define-key nxhtml-mode-map [(meta tab)] 'nxml-complete)
445 ;; Paragraphs (C-p mnemonic for paragraph)
446 (define-key nxhtml-mode-map [(control ?c) (control ?p) ?l] 'longlines-mode)
447 (define-key nxhtml-mode-map [(control ?c) (control ?p) ?f] 'fill-paragraph)
448 (define-key nxhtml-mode-map [(control ?c) (control ?p) ?u] 'unfill-paragraph)
449 ;; Html related (C-h mnemonic for html)
450 (define-key nxhtml-mode-map [(control ?c) (control ?h) ?c] 'nxhtml-save-link-to-here)
451 (define-key nxhtml-mode-map [(control ?c) (control ?h) ?v] 'nxhtml-paste-link-as-a-tag)
452 (define-key nxhtml-mode-map [(control ?c) (control ?h) ?b] 'nxhtml-browse-file)
453 (define-key nxhtml-mode-map [(control ?c) ?<] 'nxml-untag-element)
454 (when (featurep 'html-quote)
455 (define-key nxhtml-mode-map [(control ?c) (control ?q)] 'nxhtml-quote-html)
457 ;; Fix-me: Is pagetoc really that important to have its own keybindings?
458 (when (featurep 'html-pagetoc)
459 (define-key nxhtml-mode-map [(control ?c) (control ?h) ?t ?i] 'html-pagetoc-insert-toc)
460 (define-key nxhtml-mode-map [(control ?c) (control ?h) ?t ?r] 'html-pagetoc-rebuild-toc)
461 (define-key nxhtml-mode-map [(control ?c) (control ?h) ?t ?s] 'html-pagetoc-insert-style-guide)
464 (defun nxhtml-quote-html()
465 "Quote character(s) unsafe in html text parts.
466 If region is visible quote all characters in region. Otherwise
467 just quote current char.
469 Note to CUA users: See `cua-mode' for how to prevent CUA from
470 just copying region when you press C-c."
474 (let* ((rb (region-beginning))
476 (qr (html-quote-html-string
477 (buffer-substring-no-properties rb re))))
478 (delete-region rb re)
480 (let ((cs (html-quote-html-char (char-after))))
484 (defvar nxhtml-single-tags
496 (defun nxthml-is-single-tag (tag)
497 (member tag nxhtml-single-tags))
499 (defvar nxhtml-help-attribute-name
500 '(("title" "Element title")
501 ("class" "Style class of element")
502 ("charset" "Encoding of target")
503 ("coords" "Defining shape")
504 ("href" "Target URL")
505 ("hreflang" "Language of target")
506 ("name" "(DEPRECEATED)")
507 ("rel" "Target's relation to document")
508 ("rev" "Document's relation to target")
509 ("shape" "Area shape")
510 ("target" "Where to open target")
511 ("type" "MIME type of target")
513 ("id" "Unique id of element")
514 ("lang" "Language code")
515 ("dir" "Text direction")
516 ("accesskey" "Keyboard shortcut")
517 ("tabindex" "Tab order of element")
519 ("style" "Inline style")
520 ("disabled" "Tag initially disabled")
521 ("readonly" "User can not modify")
524 ("alink" "(DEPRECEATED)")
525 ("background" "(DEPRECEATED)")
526 ("bgcolor" "(DEPRECEATED)")
527 ("link" "(DEPRECEATED)")
528 ("text" "(DEPRECEATED)")
529 ("vlink" "(DEPRECEATED)")
530 ("xml:lang" "Tag content language")
531 ("cite" "URL with more info")
532 ("method" "HTTP method for sending")
533 ("accept" "Content types")
534 ("accept-charset" "Character sets")
535 ("enctype" "Encoding")
537 (defvar nxhtml-help-attribute-name-tag
539 ("name" "Name for textarea")
543 (defvar nxhtml-help-tag
544 (let ((h (make-hash-table :test 'equal)))
545 (puthash "html" "Document" h)
546 (puthash "head" "Document head" h)
547 (puthash "title" "Document title" h)
548 (puthash "base" "Base URL/target" h)
549 (puthash "meta" "Meta information" h)
550 (puthash "style" "Inline style sheet" h)
551 (puthash "link" "Style sheet etc" h)
552 (puthash "script" "(Java)Script code" h)
553 (puthash "noscript" "Script disabled part" h)
554 (puthash "isindex" "(DEPRECEATED)" h)
556 (puthash "iframe" "Inline frame" h)
557 (puthash "frameset" "Organize frames" h)
558 (puthash "frame" "Sub window" h)
559 (puthash "noframes" "Substitute for frames" h)
561 (puthash "bdo" "Text direction" h)
563 (puthash "body" "Document body" h)
564 (puthash "a" "Link" h)
565 (puthash "p" "Paragraph" h)
566 (puthash "span" "Group inline elements" h)
567 (puthash "br" "Line break" h)
568 (puthash "hr" "Horizontal rule" h)
569 (puthash "div" "Division/section" h)
570 (puthash "img" "Image" h)
571 (puthash "h1" "Header 1" h)
572 (puthash "del" "Deleted text" h)
573 (puthash "strike" "(DEPRECEATED)" h)
574 (puthash "u" "(DEPRECEATED)" h)
575 (puthash "s" "(DEPRECEATED)" h)
576 (puthash "ins" "Inserted text" h)
577 (puthash "sup" "Superscript text" h)
578 (puthash "center" "(DEPRECEATED)" h)
579 (puthash "dir" "(DEPRECEATED)" h)
581 (puthash "blockquote" "Long quotation" h)
582 (puthash "q" "Short quotation" h)
583 (puthash "pre" "Preformatted text" h)
584 (puthash "applet" "(DEPRECEATED)" h)
585 (puthash "basefont" "(DEPRECEATED)" h)
586 (puthash "font" "(DEPRECEATED)" h)
588 ;; The following elements are all font style elements. They are
589 ;; not deprecated, but it is possible to achieve richer effects
590 ;; using style sheets.
591 (puthash "tt" "Renders as teletype or mono spaced text" h)
592 (puthash "i" "Renders as italic text" h)
593 (puthash "b" "Renders as bold text" h)
594 (puthash "big" "Renders as bigger text" h)
595 (puthash "small" "Renders as smaller text" h)
598 ;; The following tags are not deprecated, but it is possible to
599 ;; achieve a much richer effect using style sheets:
600 (puthash "em" "Renders as emphasized text" h)
601 (puthash "strong" "Renders as strong emphasized text" h)
602 (puthash "dfn" "Defines a definition term" h)
603 (puthash "code" "Defines computer code text" h)
604 (puthash "samp" "Defines sample computer code" h)
605 (puthash "kbd" "Defines keyboard text" h)
606 (puthash "var" "Defines a variable" h)
607 (puthash "cite" "Defines a citation" h)
609 (puthash "ul" "Unordered list" h)
610 (puthash "ol" "Ordered list" h)
611 (puthash "li" "List element" h)
612 (puthash "dl" "Definition list" h)
613 (puthash "dt" "Definition term" h)
614 (puthash "dd" "Definition description" h)
617 (puthash "fieldset" "Draw box around" h)
618 (puthash "form" "User input form" h)
619 (puthash "input" "Input field/checkbox etc" h)
620 (puthash "textarea" "Input multiline field" h)
621 (puthash "button" "Push button" h)
622 (puthash "label" "Label for control" h)
623 (puthash "map" "Client side image map" h)
624 (puthash "select" "Drop down list" h)
625 (puthash "option" "Option in drop down list" h)
626 (puthash "menu" "(DEPRECEATED)" h)
628 (puthash "object" "Embedded object" h)
629 (puthash "param" "Object settings" h)
631 (puthash "abbr" "Abbreviation" h)
632 (puthash "address" "For addresses etc" h)
633 (puthash "acronym" "May be used for lookup etc" h)
635 (puthash "table" "Table" h)
636 (puthash "caption" "Table caption" h)
637 (puthash "col" "Table column attributes" h)
638 (puthash "colgroup" "Table column group" h)
639 (puthash "thead" "Table header" h)
640 (puthash "tbody" "Table body" h)
641 (puthash "tfoot" "Table footer" h)
642 (puthash "tr" "Table row" h)
643 (puthash "td" "Table cell" h)
648 (defun nxhtml-short-tag-help (tag)
649 "Display description of tag TAG. If TAG is omitted, try tag at point."
651 (let ((tag (xhtml-help-tag-at-point)))
652 (unless (stringp tag)
653 (setq tag (read-string "No tag at point. Give tag name: ")))
655 (setq tag (downcase tag))
656 (let ((desc (gethash tag nxhtml-help-tag))
657 (use-dialog-box nil))
659 (setq desc (concat tag " -- No short description available")))
660 (when (y-or-n-p (concat desc ". Fetch more information from the Internet? "))
661 ;; Loaded by the autoloading of `xhtml-help-tag-at-point' above:
662 (xhtml-help-browse-tag tag))))
664 (defvar nxhtml-no-single-tags nil)
665 (defvar nxhtml-no-end-tags nil)
667 (defadvice rng-complete-qname-function (around nxhtml-rng-complete-qname-function-ad
668 (string predicate flag)
670 ;;(if (not (eq major-mode 'nxhtml-mode))
671 (if (not nxhtml-completing-with-help)
673 (setq ad-return-value
674 (let ((alist (mapcar (lambda (name) (cons name nil))
675 (nxhtml-rng-generate-qname-list string))))
677 (try-completion string alist predicate))
679 (all-completions string alist predicate))
681 (and (assoc string alist) t)))))))
686 (defvar nxhtml-predicate-error nil)
688 (defun nxhtml-find-ids (file)
689 (let ((buf (find-file-noselect file)))
691 (with-current-buffer buf
692 (when (eq major-mode 'nxhtml-mode)
707 (goto-char (point-min))
708 (while (re-search-forward id-ptrn nil t)
709 (add-to-list 'ids (match-string-no-properties 1)))
712 (defun nxhtml-read-url (&optional allowed-types initial-contents extra-predicate prompt-prefix)
713 (popcmp-mark-completing initial-contents)
714 (let ((local-ovl popcmp-mark-completing-ovl))
715 (setq popcmp-mark-completing-ovl nil)
717 (let* ((url-type (nxhtml-read-url-type allowed-types initial-contents))
718 (base-prompt (cond ((eq url-type 'local-file-url)
720 ((eq url-type 'id-url)
722 ((eq url-type 'web-url)
724 ((eq url-type 'mail-url)
726 ((eq url-type 'any-url)
729 ;;(error "Internal error: bad url-type=%s" url-type)
730 "Unknown URL-type: ")
735 (bad-url initial-contents)
736 (default-directory (if buffer-file-name
737 (file-name-directory buffer-file-name)
740 (setq base-prompt (concat prompt-prefix " " base-prompt)))
741 (setq nxhtml-predicate-error "")
742 (cond ((eq url-type 'local-file-url)
744 ((eq url-type 'web-url)
746 ((eq url-type 'mail-url)
747 (setq type-predicate 'nxhtml-mailto-predicate)
748 (when (and (stringp bad-url)
749 (<= 7 (length bad-url))
750 (string= "mailto:" (substring bad-url 0 7)))
751 (setq bad-url (substring bad-url 7)))))
753 (setq prompt (concat nxhtml-predicate-error " " base-prompt))
754 (cond ((eq url-type 'local-file-url)
755 (setq url (read-file-name prompt nil "" nil bad-url extra-predicate))
756 (when (< 0 (length url))
757 ;; Fix-me: prompt for id here
758 (setq url (file-relative-name
759 (expand-file-name url)))))
760 ((eq url-type 'id-url)
761 (setq url (completing-read prompt (nxhtml-find-ids buffer-file-name)))
763 (setq url (concat "#" url))))
764 ((eq url-type 'web-url)
765 (setq url (nxhtml-read-from-minibuffer prompt bad-url nil nil
766 'nxhtml-read-web-url-history
768 ((eq url-type 'mail-url)
769 (setq url (nxhtml-read-from-minibuffer prompt bad-url nil nil
770 'nxhtml-read-mail-url-history
773 (setq url (nxhtml-read-from-minibuffer prompt bad-url nil nil
774 'nxhtml-read-url-history
776 (when (or (and type-predicate
777 (not (funcall type-predicate url)))
779 (not (funcall extra-predicate url))))
782 (when (eq url-type 'mail-url)
783 (setq url (concat "mailto:" url)))
785 (delete-overlay local-ovl)
788 (defun nxhtml-read-url-type (allowed url-beginning)
789 (assert (or (listp allowed) (eq t allowed)) t)
790 (let* ((prompt "URL-type: ")
791 (parsed-url (url-generic-parse-url url-beginning))
792 (beg-type (url-type parsed-url))
794 (completion-ignore-case t)
797 ;; (url-type (url-generic-parse-url "#some-id"))
798 ;;(lwarn t :warning "url-type=%s, pu=%s" (url-type parsed-url) parsed-url)
799 ;; Emacs 23 bug workaround Sat Jan 26 2008
800 ;;(when (eq beg-type 'cl-struct-url) (setq beg-type (elt parsed-url 1)))
801 (cond ((string= "mailto" beg-type)
802 (setq allowed-u '(?m)))
803 ((or (string= "http" beg-type)
804 (string= "https" beg-type)
805 (string= "ftp" beg-type))
806 (setq allowed-u '(?w)))
807 ((= 1 (length beg-type)) ;; w32
808 (setq allowed-u '(?f)))
809 ((and (null beg-type)
811 (= ?# (string-to-char url-beginning)))
812 (setq allowed-u '(?i)))
814 ;; Be a bit picky and hopefully helpful, check if really allowed:
815 (unless (or (eq allowed t)
816 (equal allowed allowed-u))
817 (let ((temp-u (copy-sequence allowed-u)))
819 (setq temp-u (delq a temp-u)))
821 (setq allowed-u (delq u allowed-u)))))
823 (when (eq allowed-u t)
824 (setq allowed-u '(?f ?i ?w ?m)))
825 (setq allowed-u '(?f ?w)))
826 (dolist (a allowed-u)
829 (setq choices (cons "File" choices)))
831 (setq choices (cons "Id" choices)))
832 ((= a ?w) (setq choices (cons "Url" choices)))
833 ((= a ?m) (setq choices (cons "Mail" choices)))
835 (if (= 1 (length allowed-u))
836 (setq choice (car choices))
837 (setq choice (popcmp-completing-read prompt choices nil t
839 (cond ((string= choice "Id")
841 ((string= choice "File")
843 ((string= choice "Url")
845 ((string= choice "Mail")
849 (defvar nxhtml-read-url-history nil)
850 (defvar nxhtml-read-web-url-history nil)
851 (defvar nxhtml-read-mail-url-history nil)
853 (defconst nxhtml-in-xml-attribute-value-regex
854 (replace-regexp-in-string
859 \\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\
860 \[ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\
861 \[ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\
862 \\(\"[^\"]*\\|'[^']*\\)\\="
866 (defun nxhtml-mailto-predicate (url)
867 "Tries to match a mailto url.
868 This is not supposed to be entirely correct."
869 (setq nxhtml-predicate-error nil)
870 ;; Local pattern copied from gnus.
873 "[a-z0-9$%(*-=?[_][^<>\")!;:,{}]*"
875 "\\(?:[a-z0-9\-]+\.\\)+[a-z0-9]\\{2,4\\}$"))
876 (case-fold-search t))
877 ;;(message "mailpred") (sit-for 1)
878 (if (string-match r url)
880 (setq nxhtml-predicate-error "Malformed email address.")
883 (defcustom nxhtml-image-completion-pattern
884 "\\.\\(?:png\\|jpg\\|jpeg\\|gif\\)$"
885 "Pattern for matching image URLs in completion."
889 (defun nxhtml-image-url-predicate (url)
890 (setq nxhtml-predicate-error nil)
891 (if (or (file-directory-p url)
892 (string-match nxhtml-image-completion-pattern url))
894 (setq nxhtml-predicate-error "Does not match image file name pattern.")
898 (defcustom nxhtml-css-completion-pattern
900 "Pattern for matching css URLs in completion."
904 (defun nxhtml-css-url-predicate (url)
905 (setq nxhtml-predicate-error nil)
906 (if (or (file-directory-p url)
907 (string-match nxhtml-css-completion-pattern url))
909 (setq nxhtml-predicate-error "Does not match css file name pattern.")
913 (defcustom nxhtml-script-completion-pattern
915 "Pattern for matching src URLs in completion in script tags."
919 (defun nxhtml-script-url-predicate (url)
920 (setq nxhtml-predicate-error nil)
921 (if (or (file-directory-p url)
922 (string-match nxhtml-script-completion-pattern url))
924 (setq nxhtml-predicate-error "Does not match script file name pattern.")
928 (defun nxhtml-coding-systems-complete (init default)
933 (unless (and init (< 0 (length init)))
935 (mapc (lambda (coding-system)
936 (let ((mime-charset (coding-system-get coding-system 'mime-charset)))
938 (setq coding-systems (cons
939 (symbol-name mime-charset)
941 (coding-system-list t))
942 (setq coding-systems (sort coding-systems 'string=))
943 (mapc (lambda (coding-system)
944 (unless (< 0 (length coding-system))
947 (when (string= coding-system init) (setq hist-num n)))
950 (setq hist (cons 'coding-systems hist-num))
951 (setq hist 'coding-systems))
952 (completing-read "Encoding (coding system): "
953 coding-systems nil t init hist)))
956 ;; Note: This function does not currently use the state provided by
957 ;; the nxml and rng functions directly. Instead it searches the
958 ;; environment near point to decide what to do.
959 ;; (defun nxhtml-complete-and-insert ()
960 ;; "Perform XHTML completion at point.
961 ;; This is merely an extended version of `nxml-complete' with the following changes:
963 ;; - If region is visible and active then completion will surround the
964 ;; region with the chosen tag's start and end tag. However only the
965 ;; starting point is checked for validity. If something is wrong after
966 ;; insertion you will however immediately see it if you have validation
968 ;; - Can in some cases give completion help inside attribute values.
969 ;; - There does not have to be a '<' before point for tag name
970 ;; completion. (`nxml-mode' requires a '<' before point for tag name
972 ;; - For tag names there is a popup style completion available. This
973 ;; gives a bit more guiding since it groups the alternative tags. Set
974 ;; `popcmp-popup-completion' to use this.
975 ;; - Completes xml version and encoding.
976 ;; - Completes an empty file, ie inserts a skeleton."
979 ;; (where (nxhtml-check-where)))
980 ;; (or (when (eq where 'in-empty-page)
981 ;; (nxhtml-empty-page-completion))
982 ;; (when (and mark-active
983 ;; transient-mark-mode
984 ;; (eq where 'in-text))
985 ;; (nxhtml-insert-tag))
987 ;; (cond ((memq where '(in-start-tag in-closed-start-tag in-end-tag))
988 ;; (re-search-forward "\\=/?[a-z]*" nil t))
989 ;; ((memq where '(in-attr))
990 ;; (re-search-forward "\\=[a-z]*=" nil t))
991 ;; ((memq where '(in-attr-val in-xml-attr-val))
992 ;; (re-search-forward "\\=[^<>\" \t\r\n]*" nil t))
994 ;; (when (run-hook-with-args-until-success 'nxml-completion-hook)
995 ;; (when (re-search-backward "[^=]\"\\=" nil t)
996 ;; (forward-char) (delete-char 1)
997 ;; ;;(undo-start) (undo-more 1)
1000 ;; (when (and (not where)
1002 ;; (= ?\" (char-before)))
1004 ;; (when (or (when (char-before) (= ?> (char-before)))
1005 ;; (eq where 'in-text))
1007 ;; (nxhtml-insert-tag))
1008 ;; ;; Eventually we will complete on entity names here.
1012 ;; (message "Cannot complete in this context")))))
1014 (defvar nxhtml-in-proc-instr-back-regex "<\\?[^<>]*\\=")
1015 (defvar nxhtml-in-proc-instr-forw-regex "\\=[^<>]*\\?>")
1017 (defconst rngalt-in-pre-attribute-value-regex
1018 (replace-regexp-in-string
1020 xmltok-ncname-regexp
1022 \\(?:[ \t\r\n]+w\\(?::w\\)?[ \t\r\n]*=\
1023 \[ \t\r\n]*\\(?:\"[^\"]*\"\\|'[^']*'\\)\\)*\
1024 \[ \t\r\n]+\\(w\\(:w\\)?\\)[ \t\r\n]*=[ \t\r\n]*\
1029 (defun nxhtml-check-where ()
1030 "Get a state for `nxhtml-complete-last-try'."
1032 (lt-pos (save-excursion (search-backward "<" nil t)))
1034 (cond ((= 0 (buffer-size))
1035 (setq res 'in-empty-page))
1036 ((looking-back "<!--[^<>]*\\=" 1 t)
1037 (setq res 'in-comment))
1038 ((let ((face (get-char-property (point) 'face)))
1039 (when (memq face '(nxml-comment-content-face
1040 nxml-comment-delimiter-face))
1041 (setq res 'in-comment)))
1043 ((looking-back nxhtml-in-xml-attribute-value-regex lt-pos t)
1044 (setq res 'in-xml-attr-val))
1045 ((looking-back nxhtml-in-proc-instr-back-regex 1 t)
1046 (setq res 'in-proc-instr))
1047 ((looking-back "<!D[^>]*\\=" 1 t)
1048 (setq res 'in-doctype))
1049 ((looking-back ">[^<]*" 1 t)
1050 (setq res 'in-text))
1051 ((looking-back rng-in-start-tag-name-regex 1 t)
1052 (setq res 'in-tag-start)
1053 (when (looking-at "\\=[^<]*>")
1054 (setq res 'in-closed-start-tag)))
1055 ((looking-back rng-in-end-tag-name-regex 1 t)
1056 (setq res 'in-tag-end))
1057 ((looking-back rng-in-attribute-regex 1 t)
1058 (setq res 'in-attr))
1059 ((looking-back rng-in-attribute-value-regex 1 t)
1060 (setq res 'in-attr-val))
1061 ((looking-back rngalt-in-pre-attribute-value-regex 1 t)
1062 (setq res 'in-pre-attr-val))
1063 ((looking-back "\"")
1064 (setq res 'after-attr-val))
1065 ((and rngalt-validation-header
1066 (looking-back "\\`[^<]*"))
1067 ;; FIX-ME: This is treated the same as in text currently,
1068 ;; but this should be checked. Maybe it is best to test
1069 ;; this here and return the relevant value?
1070 (setq res 'after-validation-header))
1072 ;;(message "res=%s" res)(sit-for 1)
1074 (error "Could not find a state for completion"))
1079 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1080 ;;; Make the completions additions cleaner:
1082 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1084 (defconst nxhtml-tag-sets
1201 (defvar nxhtml-attr-sets
1270 (defun nxhtml-complete-last-try ()
1271 (when rng-current-schema-file-name
1272 (let ((where (nxhtml-check-where)))
1274 ;;((eq where 'after-attr-val)
1277 ((eq where 'in-pre-attr-val)
1279 ((eq where 'in-comment)
1280 (if (not (looking-at "[^>]*<"))
1284 ((eq where 'in-xml-attr-val)
1290 (re-search-forward "\\=[^<> \t\r\n\"]*" nil t)))
1291 (let* ((name-start (match-beginning 1))
1292 (name-end (match-end 1))
1293 (colon (match-beginning 2))
1294 (attr (buffer-substring-no-properties name-start
1295 (or colon name-end)))
1296 (value-start (1+ (match-beginning 3)))
1297 (tag (save-excursion
1298 (when (search-backward-regexp "<[[:alpha:]]+" nil t)
1300 (init (buffer-substring-no-properties value-start (point))))
1301 (setq delimiter (char-before value-start))
1302 (cond ((string= "encoding" attr)
1303 ;; Give a default that works in browsers today
1304 (setq val (nxhtml-coding-systems-complete
1306 (symbol-name nxhtml-default-encoding))))
1307 ((string= "version" attr)
1313 ((or (memq where '(in-text
1314 after-validation-header
1316 (rngalt-complete-tag-region-prepare)
1319 (nxhtml-redisplay-complete)
1321 (message "%s" (error-message-string err))
1324 (rngalt-complete-tag-region-cleanup)))
1327 ;;(message "LAST TRY where=%s" (nxhtml-check-where))(sit-for 1)
1331 (defun nxhtml-img-tag-do-also ()
1334 (insert (read-string "Alt attribute: ")
1338 (let ((src (nxhtml-read-url nil nil 'nxhtml-image-url-predicate "Image")))
1341 (when (file-exists-p src)
1342 (let ((sizes (image-size (create-image (expand-file-name src)) t)))
1344 " width=\"" (format "%d" (car sizes)) "\""
1345 " height=\"" (format "%d" (cdr sizes)) "\"")
1347 (unless (save-match-data (looking-at "[^<]\\{,200\\}>"))
1350 (defun nxhtml-redisplay-complete ()
1356 (rng-activate-timers))
1358 (defun nxhtml-read-from-minibuffer (prompt &optional
1359 initial-contents keymap
1360 read hist default-value
1361 inherit-input-method)
1364 (let ((res (read-from-minibuffer prompt initial-contents keymap
1365 read hist default-value inherit-input-method)))
1366 (rng-activate-timers)
1369 (defun nxhtml-meta-tag-do-also ()
1370 (let ((type (popcmp-completing-read
1373 ;;"Refresh/Redirect"
1374 "HTTP Message Headers"
1376 "Description for Search Engines"
1379 ((string= type "Description for Search Engines")
1380 (insert " name=\"Description\"")
1381 (insert " content=\"")
1382 (insert (nxhtml-read-from-minibuffer "Description: "))
1384 ((string= type "Robot Rules")
1385 (insert " name=\"Robots\"")
1386 (insert " content=\"")
1387 (nxhtml-redisplay-complete)
1389 ((string= type "HTTP Message Headers")
1390 (insert " http-equiv=\"")
1391 (nxhtml-redisplay-complete)
1392 (insert " content=\"")
1393 (insert (nxhtml-read-from-minibuffer "Content: "))
1394 (insert "\" />")))))
1396 (defun nxhtml-style-tag-do-also ()
1397 (insert "type=\"text/css\"")
1398 (insert " media=\"")
1399 (nxhtml-redisplay-complete)
1401 (indent-according-to-mode)
1402 (insert "\n/* <![CDATA[ */")
1403 (indent-according-to-mode)
1405 (indent-according-to-mode)
1406 (insert "\n/* ]]> */")
1407 (indent-according-to-mode)
1408 (insert "\n</style>")
1409 (indent-according-to-mode)
1413 (defun nxhtml-script-tag-do-also ()
1414 (let ((type (popcmp-completing-read
1419 ((string= type "Inlined")
1420 (insert "type=\"text/javascript\">")
1421 (indent-according-to-mode)
1422 (insert "\n// <![CDATA[")
1423 (indent-according-to-mode)
1425 (indent-according-to-mode)
1427 (indent-according-to-mode)
1428 (insert "\n</script>")
1429 (indent-according-to-mode)
1431 ((string= type "Linked")
1432 (insert "type=\"text/javascript\"")
1434 (nxhtml-redisplay-complete)
1435 (insert "></script>")))))
1437 (defun nxhtml-link-tag-do-also ()
1438 (let ((type (popcmp-completing-read "Type: "
1445 ((string= type "Style sheet")
1446 (insert " rel=\"Stylesheet\" ")
1447 (insert "type=\"text/css\" ")
1449 (nxhtml-redisplay-complete)
1450 (insert " media=\"")
1451 (nxhtml-redisplay-complete)
1453 ((string= type "Shortcut icon")
1454 (insert " rel=\"Shortcut Icon\" ")
1456 (nxhtml-redisplay-complete)
1460 (nxhtml-redisplay-complete)
1463 (defun nxhtml-input-tag-do-also ()
1468 (nxhtml-redisplay-complete)
1471 (let* ((choice (save-match-data
1472 (when (looking-back "type=\"\\(.*\\)\" ")
1473 (match-string 1)))))
1474 ;;(insert "type=\"" choice "\" ")
1476 ;;(message "choice=%s" choice)(sit-for 2)
1478 (when (member choice '("button" "checkbox" "file" "hidden" "image"
1479 "password" "radio" "text"))
1481 (read-string "Name (name): ")
1485 (when (member choice '("checkbox" "radio"))
1486 (when (y-or-n-p "Checked? (checked): ")
1487 (insert "checked=\"checked\" ")
1490 (unless (string= choice "hidden")
1491 (unless (y-or-n-p "Enabled? : ")
1492 (insert "disabled=\"disabled\" ")
1495 (when (string= choice "text")
1496 (when (y-or-n-p "Readonly? (readonly): ")
1497 (insert "readonly=\"readonly\" "))
1499 (when (string= choice "file")
1503 (let ((prompt (concat
1504 "Accept mime type, RET to stop ("
1509 (types (when (boundp 'mailcap-mime-extensions)
1510 (mapcar (lambda (elt)
1512 mailcap-mime-extensions))))
1513 (while (< 0 (length mime))
1516 (completing-read prompt types)
1517 (read-string prompt)))
1518 (when (< 0 (length mime))
1520 (setq mimes (concat mimes "," mime))
1521 (setq mimes mime))))
1523 (< 0 (length mimes)))
1524 (insert "accept=\"" mimes "\" ")))
1525 (quit (message "Skipped accept attribute")))
1527 (when (string= choice "image")
1531 (insert (read-string "Alt attribute: ")
1537 (let ((src (nxhtml-read-url nil nil 'nxhtml-image-url-predicate "Image")))
1543 ((member choice '("button" "reset" "submit"))
1544 (nxhtml-do-also-value "Label"))
1545 ((member choice '("checkbox" "radio"))
1546 (nxhtml-do-also-value "Result"))
1547 ((member choice '("hidden" "password" "text"))
1548 (nxhtml-do-also-value "Value"))
1551 ;;(message "type=%s" choice)(sit-for 2)
1554 (defun nxhtml-do-also-value (label)
1555 (let ((v (read-string (concat label " (value): "))))
1558 (insert " value=\"" v "\" "))))
1560 (defun nxhtml-form-tag-do-also ()
1561 (insert "action=\"")
1563 (let ((src (nxhtml-read-url nil nil nil "Action")))
1567 (defun nxhtml-a-tag-do-also ()
1570 (insert (nxhtml-read-url t))
1572 (let* ((pre-choices '("_blank" "_parent" "_self" "_top"))
1573 (all-choices (reverse (cons "None" (cons "Frame name" pre-choices))))
1575 (prompt "Target: "))
1576 (setq choice (popcmp-completing-read prompt all-choices nil t
1578 (unless (string= choice "None")
1579 (insert " target=\"")
1580 (cond ((member choice pre-choices)
1581 (insert choice "\""))
1582 ((string= choice "Frame name")
1584 (insert (read-string "Frame name: ") "\""))
1585 (t (error "Uh?")))))
1588 (insert (read-string "Link title: ")
1591 (defconst nxhtml-complete-tag-do-also
1592 '(("a" nxhtml-a-tag-do-also)
1594 ;; (insert " href=\"")
1595 ;; (rngalt-validate)
1596 ;; (insert (nxhtml-read-url t))
1598 ("form" nxhtml-form-tag-do-also)
1599 ("img" nxhtml-img-tag-do-also)
1600 ("input" nxhtml-input-tag-do-also)
1601 ("link" nxhtml-link-tag-do-also)
1602 ("script" nxhtml-script-tag-do-also)
1603 ("style" nxhtml-style-tag-do-also)
1604 ("meta" nxhtml-meta-tag-do-also)
1606 "List of functions to call at tag completion.
1607 Each element of the list have the form
1611 If `nxhtml-tag-do-also' is non-nil then TAG-FUN is called after
1612 by `nxml-complete' (with the special setup of this function for
1613 `nxhtml-mode') when completing a tag with the name TAG-NAME.
1615 The list is handled as an association list, ie only the first
1616 occurence of a tag name is used.")
1618 (defun nxhtml-complete-tag-do-also-for-state-completion (dummy-completed)
1619 "Add this to state completion functions completed hook."
1620 (when (and nxhtml-tag-do-also
1621 (derived-mode-p 'nxhtml-mode))
1625 ;;(when (looking-back "<\\([a-z]+\\)[[:blank:]]+")
1626 (when (looking-back "<\\([a-z]+\\)")
1627 (setq tag (match-string 1))))
1630 (nxhtml-complete-tag-do-also tag)))))
1632 (defun nxhtml-complete-tag-do-also (tag)
1633 ;; First required attributes:
1634 (let ((tagrec (assoc tag nxhtml-complete-tag-do-also)))
1636 (funcall (cadr tagrec))))
1641 (define-minor-mode nxhtml-validation-header-mode
1642 "If on use a Fictive XHTML Validation Header for the buffer.
1643 See `nxhtml-set-validation-header' for information about Fictive XHTML Validation Headers.
1645 This mode may be turned on automatically in two ways:
1646 - If you try to do completion of a XHTML tag or attribute then
1647 `nxthml-mode' may ask you if you want to turn this mode on if
1649 - You can also choose to have it turned on automatically whenever
1650 a mumamo multi major mode is used, see
1651 `nxhtml-validation-header-if-mumamo' for further information."
1655 (if nxhtml-validation-header-mode
1657 (unless nxhtml-current-validation-header
1658 (setq nxhtml-current-validation-header
1659 (nxhtml-get-default-validation-header)))
1660 ;;(message "nxhtml-current-validation-header=%s" nxhtml-current-validation-header)
1661 (if nxhtml-current-validation-header
1663 (nxhtml-apply-validation-header)
1664 (add-hook 'change-major-mode-hook 'nxhtml-vhm-change-major nil t)
1665 (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
1666 (add-hook 'mumamo-change-major-mode-hook 'nxhtml-vhm-mumamo-change-major nil t)
1667 (add-hook 'mumamo-after-change-major-mode-hook 'nxhtml-vhm-mumamo-after-change-major nil t)))
1668 (run-with-idle-timer 0 nil 'nxhtml-validation-header-empty (current-buffer))))
1669 (rngalt-set-validation-header nil)
1670 (setq nxhtml-current-validation-header nil)
1671 (remove-hook 'after-change-major-mode-hook 'nxhtml-vhm-after-change-major t)
1672 (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
1673 (remove-hook 'mumamo-change-major-mode-hook 'nxhtml-vhm-mumamo-change-major t)
1674 (remove-hook 'mumamo-after-change-major-mode-hook 'nxhtml-vhm-mumamo-after-change-major t))))
1676 (defun nxhtml-can-insert-page-here ()
1677 (and (not nxhtml-validation-header-mode)
1679 (or (= 0 (buffer-size))
1683 (looking-at (rx buffer-start
1687 (defun nxhtml-complete-first-try ()
1688 (when (nxhtml-can-insert-page-here)
1689 (nxhtml-empty-page-completion)))
1691 (defun nxhtml-completing-read-tag (prompt
1693 &optional predicate require-match
1694 initial-input hist def inherit-input-method)
1695 (let ((popcmp-in-buffer-allowed t))
1696 (popcmp-completing-read prompt
1698 predicate require-match
1699 initial-input hist def inherit-input-method
1703 (defun nxhtml-add-required-to-attr-set (tag)
1704 (let ((missing (when tag
1705 (rngalt-get-missing-required-attr
1706 (nxthml-is-single-tag tag)))))
1709 (cons (cons "Required" missing)
1710 nxhtml-attr-sets))))
1712 (defun nxhtml-get-tag-specific-attr-help (tag)
1713 (append (cdr (assoc tag nxhtml-help-attribute-name-tag)) nxhtml-help-attribute-name)
1716 (defconst nxhtml-in-start-tag-regex
1717 ;;(defconst rng-in-start-tag-name-regex
1718 (replace-regexp-in-string
1720 xmltok-ncname-regexp
1721 ;; Not entirely correct since < could be part of attribute value:
1722 "<\\(w\\(?::w?\\)?\\)+ [^<]*"
1726 (defun nxhtml-completing-read-attribute-name (prompt
1728 &optional predicate require-match
1729 initial-input hist def inherit-input-method)
1730 (let* ((tag (save-match-data
1731 ;;(when (looking-back "<\\([a-z1-6]+\\) [^<]*")
1732 (when (looking-back nxhtml-in-start-tag-regex)
1734 (attr-sets (nxhtml-add-required-to-attr-set tag))
1735 (help-attr (nxhtml-get-tag-specific-attr-help tag))
1736 (popcmp-in-buffer-allowed t)
1738 (popcmp-completing-read prompt
1740 predicate require-match
1741 initial-input hist def inherit-input-method
1745 (defun nxhtml-completing-read-attribute-value (prompt
1747 &optional predicate require-match
1748 initial-input hist def inherit-input-method)
1751 (let ((popcmp-in-buffer-allowed t))
1752 (setq val (popcmp-completing-read prompt table
1753 predicate require-match
1754 initial-input hist def inherit-input-method)))
1757 (lt-pos (save-excursion (search-backward "<" nil t)))
1760 (re-search-backward rng-in-attribute-value-regex lt-pos t)))
1764 (re-search-backward nxhtml-in-xml-attribute-value-regex lt-pos t))))
1766 (when (or in-attr-val in-xml-attr-val)
1767 ;;(save-match-data (save-excursion (re-search-forward "\\=[^<> \t\r\n\"]*" nil t)))
1768 (let* ((name-start (match-beginning 1))
1769 (name-end (match-end 1))
1770 (colon (match-beginning 2))
1771 (attr (buffer-substring-no-properties name-start
1772 (or colon name-end)))
1773 (value-start (1+ (match-beginning 3)))
1775 (tag (save-excursion
1776 (when (search-backward-regexp "<[[:alpha:]]+" nil t)
1777 (setq tag-start-end (match-end 0))
1778 (match-string-no-properties 0)))))
1779 (setq init (buffer-substring-no-properties value-start (point)))
1780 (setq delimiter (char-before value-start))
1782 (error "in-xml-attr-val should not be true here!")
1783 ;; (cond ((string= "encoding" attr)
1784 ;; ;; Give a default that works in browsers today
1785 ;; (setq val (nxhtml-coding-systems-complete
1787 ;; (symbol-name nxhtml-default-encoding))))
1788 ;; ((string= "version" attr)
1789 ;; (setq val "1.0")))
1790 (cond ((string= "rel" attr)
1791 (cond ((string= "<link" tag)
1792 (setq val (nxhtml-read-link-rel))
1794 ((string= "media" attr)
1795 (cond ((string= "<link" tag)
1796 (setq val (nxhtml-read-link-media)))
1797 ((string= "<style" tag)
1798 (setq val (nxhtml-read-link-media)))
1800 ((string= "type" attr)
1801 (cond ((string= "<link" tag)
1802 (setq val (nxhtml-read-link-type))
1804 ((string= "http-equiv" attr)
1805 (cond ((string= "<meta" tag)
1806 (setq val (nxhtml-read-meta-http-equiv)))))
1807 ((string= "content" attr)
1808 (cond ((string= "<meta" tag)
1809 (setq val (nxhtml-read-meta-content)))))
1810 ((string= "scheme" attr)
1811 (cond ((string= "<meta" tag)
1812 (setq val (nxhtml-read-meta-scheme)))))
1813 ((string= "name" attr)
1814 (cond ((string= "<meta" tag)
1815 (setq val (nxhtml-read-meta-name)))))
1816 ((string= "href" attr)
1817 (cond ((string= "<a" tag)
1818 (setq val (nxhtml-read-url t init)))
1819 ((string= "<base" tag)
1820 (setq val (nxhtml-read-url nil init nil "Base")))
1821 ((string= "<area" tag)
1822 (setq val (nxhtml-read-url nil init)))
1823 ((string= "<link" tag)
1827 (goto-char tag-start-end)
1829 ((search-forward "text/css" here nil)
1830 (setq predicate 'nxhtml-css-url-predicate))
1832 (setq val (nxhtml-read-url nil init predicate))))
1834 (setq val (nxhtml-read-url nil init)))))
1835 ((string= "src" attr)
1836 (cond ((string= "<img" tag)
1837 (setq val (nxhtml-read-url nil init 'nxhtml-image-url-predicate "Image")))
1838 ((string= "<script" tag)
1839 (setq val (nxhtml-read-url nil init 'nxhtml-script-url-predicate "Script")))
1840 ((string= "<input" tag)
1841 (setq val (nxhtml-read-url nil init 'nxhtml-image-url-predicate "Image")))
1842 ((string= "<frame" tag)
1843 (setq val (nxhtml-read-url nil init nil "Frame Source")))
1844 ((string= "<iframe" tag)
1845 (setq val (nxhtml-read-url nil init nil "Frame Source")))
1847 (setq val (nxhtml-read-url nil init)))))))))))
1848 ;;(unless val (setq val (read-from-minibuffer prompt init)))
1851 (message "No completion of attribute value available here")
1855 (defun nxhtml-read-link-type ()
1857 (let ((types (when (boundp 'mailcap-mime-extensions)
1858 (mapcar (lambda (elt)
1860 mailcap-mime-extensions))))
1861 (completing-read "Link type: " types nil t)))
1863 (defun nxhtml-read-link-media ()
1875 (popcmp-completing-read "For media type: " types nil t)))
1877 (defun nxhtml-read-link-rel ()
1878 (let ((predefined-linktypes '(
1896 (popcmp-completing-read "Predefined LinkTypes: " predefined-linktypes nil t)))
1898 (defun nxhtml-read-meta-name ()
1907 (popcmp-completing-read "Meta name: " types nil t)))
1909 (defun nxhtml-read-meta-content ()
1910 (nxhtml-read-from-minibuffer "Meta content: "))
1912 (defun nxhtml-read-meta-scheme ()
1913 (nxhtml-read-from-minibuffer "Meta scheme: "))
1915 (defun nxhtml-read-meta-http-equiv ()
1922 (popcmp-completing-read "Meta http-equiv: " types nil t)))
1925 (setq rngalt-completing-read-tag nil)
1926 (setq rngalt-complete-last-try nil)
1930 (when (featurep 'typesetter)
1931 (defun typesetter-init-nxhtml-mode ()
1932 (typesetter-init-html-mode))
1935 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1936 ;;; Validation start state
1938 (defcustom nxhtml-validation-headers
1940 ("body-iso-8859-1" .
1941 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
1942 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1943 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1944 <html xmlns=\"http://www.w3.org/1999/xhtml\">
1946 <title>Fictive XHTML Validation Header</title>
1951 ("head-iso-8859-1" .
1952 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
1953 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1954 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1955 <html xmlns=\"http://www.w3.org/1999/xhtml\">
1959 ("html-iso-8859-1" .
1960 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
1961 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1962 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1963 <html xmlns=\"http://www.w3.org/1999/xhtml\">
1966 ;; ("doctype-iso-8859-1" .
1967 ;; "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
1968 ;; <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1969 ;; \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1972 ;; ("xml-iso-8859-1" .
1973 ;; "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
1978 "<?xml version=\"1.0\" encoding=\"utf-8\"?>
1979 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1980 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1981 <html xmlns=\"http://www.w3.org/1999/xhtml\">
1983 <title>Fictive XHTML Validation Header</title>
1989 "<?xml version=\"1.0\" encoding=\"utf-8\"?>
1990 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1991 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
1992 <html xmlns=\"http://www.w3.org/1999/xhtml\">
1996 ("head-closed-utf-8" .
1997 "<?xml version=\"1.0\" encoding=\"utf-8\"?>
1998 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
1999 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
2000 <html xmlns=\"http://www.w3.org/1999/xhtml\">
2007 "<?xml version=\"1.0\" encoding=\"utf-8\"?>
2008 <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
2009 \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
2010 <html xmlns=\"http://www.w3.org/1999/xhtml\">
2013 ;; ("doctype-utf-8" .
2014 ;; "<?xml version=\"1.0\" encoding=\"utf-8\"?>
2015 ;; <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"
2016 ;; \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">
2020 ;; "<?xml version=\"1.0\" encoding=\"utf-8\"?>
2024 "Fictive XHTML validation headers.
2025 Used by `nxhtml-set-validation-header'."
2026 :type '(alist :key-type string :value-type string)
2029 (defcustom nxhtml-default-validation-header nil
2030 "Default Fictive XHTML validation header.
2031 Must be nil or one of the key values in
2032 `nxhtml-validation-headers'."
2034 :set (lambda (sym val)
2036 (assoc val nxhtml-validation-headers))
2037 (set-default sym val)
2038 (lwarn 'nxhtml-default-validation-header
2039 :warning "There is no Fictive XHTML Validation Header named %s" val)))
2042 (defun nxhtml-must-have-validation-headers ()
2043 (unless nxhtml-validation-headers
2045 "No XHTML validation headers. Please customize nxhtml-validation-headers.")))
2047 (defvar nxhtml-set-validation-header-hist nil)
2049 (defcustom nxhtml-guess-validation-header-alist
2050 ;;(rx line-start (0+ blank) "<body")
2052 ("^[[:blank:]]*<body" . "body-utf-8")
2053 ("^[[:blank:]]*</head>" . "head-closed-utf-8")
2054 ("^[[:blank:]]*<head" . "head-utf-8")
2055 ("^[[:blank:]]*<html" . "html-utf-8")
2057 "Alist used by `nxhtml-guess-validation-header'.
2058 Alternatives are tried from top to bottom until one fits."
2059 :type '(alist :key-type (regexp :tag "If NOT found in buffer")
2060 :value-type (string :tag "Use Fictive XHTML Validation Header"))
2063 (defun nxhtml-guess-validation-header ()
2064 "Return Fictive XHTML validation that could fit current buffer.
2065 This guess is made by matching the entries in
2066 `nxhtml-guess-validation-header-alist' against the buffer."
2067 (nxhtml-must-have-validation-headers)
2075 (guesses nxhtml-guess-validation-header-alist))
2076 (goto-char (point-min))
2077 (if (not (search-forward "</" 2000 t))
2079 (setq rec (car guesses))
2080 (setq key (cdr rec)))
2083 (setq rec (car guesses))
2084 (setq guesses (cdr guesses))
2085 (setq regexp (car rec))
2086 (goto-char (point-min))
2087 ;; Fix-me: check for chunk and check if in string.
2089 (while (and (not found)
2090 (re-search-forward regexp nil t))
2091 ;; ensure fontified, but how?
2092 (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
2093 (let ((mumamo-just-changed-major nil))
2094 ;;(unless (and (mumamo-get-existing-chunk-at (point))
2095 (unless (and (mumamo-find-chunks (point) "guess-validation-header")
2096 (eq t (get-text-property (point) 'fontified)))
2097 (mumamo-fontify-region (point-min) (+ 1000 (point))))))
2098 (unless (memq (get-text-property (point) 'face)
2099 '(font-lock-comment-face
2100 font-lock-comment-delimiter-face
2102 font-lock-string-face
2106 (setq key (cdr rec))))))
2107 ;;(unless (re-search-forward regexp nil t) (setq key (cdr rec)))))
2110 (defun nxhtml-open-dir-saved-validation-headers (must-exist)
2111 "Open file with saved validation headers and return buffer."
2112 ;;(lwarn 't :warning "must-exist=%s" must-exist)
2113 (when (buffer-file-name)
2114 (let* ((dir-name (file-name-directory (buffer-file-name)))
2115 (file-name (expand-file-name "nxhtml-val-headers.el"))
2116 emacs-lisp-mode-hook)
2117 (when (or (not must-exist)
2118 (file-exists-p file-name))
2119 (find-file-noselect file-name)))))
2121 (defun nxhtml-get-saved-validation-header ()
2122 (when (buffer-file-name)
2123 (let* ((val-buf (nxhtml-open-dir-saved-validation-headers t))
2124 (file-name (file-name-nondirectory (buffer-file-name)))
2127 (with-current-buffer val-buf
2129 (cadr (assoc file-name validation-headers))))))
2131 (defun nxhtml-remove-saved-validation-header ()
2132 "Removed the saved validation header.
2133 Reverse the action done by `nxhtml-save-validation-header'."
2135 (nxhtml-update-saved-validation-header nil))
2137 (defun nxhtml-save-validation-header ()
2138 "Save the current validation header.
2139 The current validation is saved for the next time you open the
2140 current file. It is then used by `nxhtml-validation-header-mode'
2141 and `nxhtml-set-validation-header'. This means that if you have
2142 turned on `nxhtml-global-validation-header-mode' this validation
2143 header will be set automatically.
2145 The saved validation header can be removed with
2146 `nxhtml-remove-saved-validation-header'.
2148 * Note: There is normally no need to save the validation headers
2149 since `nxhtml-global-validation-header-mode' will add
2150 validation headers as needed most of the time."
2152 (nxhtml-update-saved-validation-header t))
2154 (defun nxhtml-update-saved-validation-header (save)
2155 (unless (buffer-file-name)
2156 (error "Validation Header can only be saved if buffer contains a file."))
2157 (let* ((val-buf (nxhtml-open-dir-saved-validation-headers nil))
2158 ;;(get-buffer-create "temp val head"))
2160 (file-name (file-name-nondirectory (buffer-file-name)))
2161 (entry (list file-name nxhtml-current-validation-header))
2166 (with-current-buffer val-buf
2169 (setq validation-headers
2171 (mapcar (lambda (elt)
2172 (if (string= file-name (car elt))
2177 validation-headers)))
2180 (setq validation-headers (cons entry validation-headers)))
2181 (with-current-buffer val-buf
2183 ;;(print file-name val-buf)
2184 ;;(print nxhtml-current-validation-header val-buf)
2185 ;;(print entry val-buf)
2186 (insert "(setq validation-headers (quote")
2187 (print validation-headers val-buf)
2192 (message "Current validation header for file saved")
2194 (message "Removed saved validation header")
2195 (message "There was no saved validation header")))))
2197 (defun nxhtml-get-default-validation-header ()
2198 "Return default Fictive XHTML validation header key for current buffer.
2199 If `nxhtml-default-validation-header' is non-nil then return
2200 this. Otherwise return saved validation header if there is one
2201 or guess using `nxhtml-guess-validation-header'."
2202 (or nxhtml-default-validation-header
2203 (nxhtml-get-saved-validation-header)
2204 (nxhtml-guess-validation-header)))
2206 (defun nxhtml-set-validation-header (&optional key)
2207 "Set a Fictive XHTML validation header in the buffer.
2208 Such a header is not inserted in the buffer, but is only used by
2209 validation and XHTML completion by `nxhtml-mode'.
2211 The header is active for validation and completion if and only if
2212 `nxhtml-validation-header-mode' is on.
2214 Note that Fictive XHTML Validation Headers are normally chosen
2215 automatically, but you can use this function to override that choice.
2217 The header is chosen from `nxhtml-validation-headers'. If there
2218 is more than one you will be prompted. To set the default fictive
2219 XHTML validation header customize `nxhtml-validation-headers'.
2221 If called non-interactive then the header corresponding to key
2222 KEY will be used. If KEY is nil then it is set to
2223 `nxhtml-default-validation-header'.
2225 This header can be visible or invisible in the buffer, for more
2226 information see `rngalt-show-validation-header'."
2229 (let ((nh (length nxhtml-validation-headers))
2230 (default (nxhtml-get-default-validation-header)))
2232 (completing-read "XHTML validation header: "
2233 nxhtml-validation-headers
2237 nxhtml-set-validation-header-hist)
2238 (if (not (y-or-n-p "Only one XHTML validation header is defined. Define more? "))
2240 (customize-option 'nxhtml-validation-headers)
2242 ;;(lwarn 'svh2 :warning "key=%s" key)
2244 (setq key (nxhtml-get-default-validation-header))
2245 (setq key (cons 'schema "XHTML")))
2246 (unless (eq key 'adding)
2247 (setq nxhtml-current-validation-header key)
2248 (nxhtml-validation-header-mode 1)
2249 (nxhtml-apply-validation-header)))
2251 (defun nxhtml-apply-validation-header ()
2252 (when nxhtml-current-validation-header
2253 (setq rngalt-major-mode
2254 (if (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
2255 (mumamo-main-major-mode)
2257 (let* ((key nxhtml-current-validation-header)
2258 (rec (unless (listp key)
2259 (assoc key nxhtml-validation-headers)))
2262 (let ((schema-file (rng-locate-schema-file (cdr key))))
2264 (error "Could not locate schema for type id `%s'" key)) ;type-id))
2265 (rng-set-schema-file-1 schema-file))
2266 (rngalt-set-validation-header header)
2269 (defun nxhtml-update-validation-header ()
2270 "Update the validation header in the buffer as needed."
2272 (let ((mode-on nxhtml-validation-header-mode))
2273 (when mode-on (nxhtml-validation-header-mode 0))
2274 (setq nxhtml-current-validation-header nil)
2275 (when mode-on (nxhtml-validation-header-mode 1))))
2277 (defun nxhtml-vhm-change-major ()
2278 "Turn off `nxhtml-validation-header-mode' after change major."
2279 ;;(message "nxhtml-vhm-change-major here")
2280 (unless (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode)
2281 (setq nxhtml-current-validation-header nil))
2282 (run-with-idle-timer 0 nil 'nxhtml-validation-header-empty (current-buffer)))
2283 (put 'nxhtml-vhm-change-mode 'permanent-local-hook t)
2285 (defun nxhtml-recheck-validation-header ()
2286 "Just turn off and on again `nxhtml-validation-header-mode'.
2287 This will adjust the XHTML validation to the code currently in
2290 (nxhtml-validation-header-mode -1)
2291 (nxhtml-validation-header-mode 1))
2293 (defun nxhtml-validation-header-empty (buffer)
2294 "Turn off validation header mode.
2295 This is called because there was no validation header."
2296 (with-current-buffer buffer
2297 (unless nxhtml-current-validation-header
2298 ;;(message "nxhtml-validation-header-empty")
2299 (save-match-data ;; runs in timer
2300 (nxhtml-validation-header-mode -1))
2301 ;;(message "No validation header was needed")
2304 (defun nxhtml-turn-on-validation-header-mode ()
2305 "Turn on `nxhtml-validation-header-mode'."
2306 (nxhtml-validation-header-mode 1))
2309 (defun nxhtml-vhm-mumamo-change-major ()
2310 (put 'rngalt-validation-header 'permanent-local t)
2311 (put 'nxhtml-validation-header-mode 'permanent-local t)
2312 (put 'nxhtml-current-validation-header 'permanent-local t)
2313 ;;(put 'nxhtml-validation-header-mode-major-mode 'permanent-local t)
2314 ;;(setq nxhtml-validation-header-mode-major-mode mumamo-set-major-running)
2317 (defun nxhtml-vhm-mumamo-after-change-major ()
2318 (put 'rngalt-validation-header 'permanent-local nil)
2319 (put 'nxhtml-validation-header-mode 'permanent-local nil)
2320 (put 'nxhtml-current-validation-header 'permanent-local nil)
2321 ;;(put 'nxhtml-validation-header-mode-major-mode 'permanent-local nil)
2324 (defcustom nxhtml-validation-headers-check 'html
2325 "Defines what check the function with the same name does.
2326 The function returns true if the condition here is met."
2327 :type '(choice :tag "Add Fictive XHTML Validation Header if:"
2328 (const :tag "If buffer contains html" html)
2329 (const :tag "If buffer contains html or is empty" html-empty))
2332 ;; (defun nxhtml-validation-headers-check (buffer)
2333 ;; "Return non-nil if buffer contains a html tag or is empty.
2334 ;; This is for use with `nxhtml-validation-header-filenames'.
2336 ;; The variable `nxhtml-validation-headers-check' determines how the
2338 ;; (if (= 0 (buffer-size buffer))
2339 ;; (eq 'html-empty nxhtml-validation-headers-check)
2341 ;; (save-restriction
2342 ;; (let ((here (point))
2344 ;; (goto-char (point-min))
2345 ;; (setq html (re-search-forward "</?[a-z]+>" nil t))
2349 ;; (defcustom nxhtml-validation-header-filenames
2351 ;; ("\.php\\'" nxhtml-validation-headers-check)
2352 ;; ("\.rhtml\\'" nxhtml-validation-headers-check)
2353 ;; ("\.jsp\\'" nxhtml-validation-headers-check)
2354 ;; ("\.gsp\\'" nxhtml-validation-headers-check)
2356 ;; "Alist for turning on `nxhtml-validation-mode'.
2357 ;; The entries in the list should have the form
2359 ;; \(FILE-REGEXP CHECK-FUNCION)
2361 ;; If buffer file name matches the regexp FILE-REGEXP and the
2362 ;; function CHECK-FUNCTION returns non-nil when called with the
2363 ;; buffer as an argument \(or CHECK-FUNCTION is nil) then
2364 ;; `nxhtml-global-validation-header-mode' will turn on
2365 ;; `nxhtml-validation-header-mode' in buffer.
2367 ;; The function `nxhtml-validation-headers-check' may be a useful
2368 ;; value for CHECK-FUNCTION.
2370 ;; See also `nxhtml-maybe-turn-on-validation-header'."
2371 ;; :type '(alist :key-type regexp :tag "File name regexp"
2372 ;; :value-type (group (choice (const :tag "No more check" nil)
2373 ;; (function :tag "Check buffer with"))))
2378 ;; (defun nxhtml-maybe-turn-on-validation-header ()
2379 ;; "Maybe turn on `nxhtml-validation-header-mode' in buffer.
2380 ;; This is called by `nxhtml-global-validation-header-mode'.
2382 ;; See `nxhtml-validation-header-filenames' for how the check
2384 ;; (or (and (or (and mumamo-mode
2385 ;; (eq (mumamo-main-major-mode) 'nxhtml-mode))
2386 ;; (eq major-mode 'nxhtml-mode))
2387 ;; rngalt-validation-header
2388 ;; nxhtml-current-validation-header
2389 ;; nxhtml-validation-header-mode
2391 ;; ;;(lwarn 'maybe :warning "quick, buffer=%s" (current-buffer))
2392 ;; (nxhtml-validation-header-mode 1)
2394 ;; (when (buffer-file-name)
2395 ;; (unless (or ;;nxhtml-validation-header-mode
2396 ;; (minibufferp (current-buffer))
2397 ;; (string= " " (substring (buffer-name) 0 1))
2398 ;; (string= "*" (substring (buffer-name) 0 1))
2400 ;; (when (catch 'turn-on
2402 ;; (dolist (rec nxhtml-validation-header-filenames)
2403 ;; (when (string-match (car rec) (buffer-file-name))
2404 ;; (let ((fun (nth 1 rec)))
2407 ;; ;;(lwarn 't :warning "matched %s to %s, nil" (car rec) (buffer-file-name))
2408 ;; (throw 'turn-on t))
2409 ;; (when (funcall fun (current-buffer))
2410 ;; ;;(lwarn 't :warning "matched %s to %s" (car rec) (buffer-file-name))
2411 ;; (throw 'turn-on t))))))))
2412 ;; ;;(lwarn 't :warning "turn on %s, buffer=%s" major-mode (current-buffer))
2413 ;; (nxhtml-validation-header-mode 1))))))
2416 ;; ;; Fix-me: Is this really the way to do it? Would it not be better to
2417 ;; ;; tie this to mumamo-mode in the turn on hook there? After all
2418 ;; ;; validation headers are probably not used unless mumamo-mode is on.
2419 ;; (define-globalized-minor-mode nxhtml-global-validation-header-mode
2420 ;; nxhtml-validation-header-mode
2421 ;; nxhtml-maybe-turn-on-validation-header
2423 ;; ;; The problem with global minor modes:
2424 ;; (when (and nxhtml-global-validation-header-mode
2425 ;; (not (boundp 'define-global-minor-mode-bug)))
2426 ;; (nxhtml-global-validation-header-mode 1))
2429 (defcustom nxhtml-validation-header-mumamo-modes
2431 "Main major modes for which to turn on validation header.
2432 Turn on Fictive XHTML Validation Header if main major mode for the
2433 used mumamo multi major mode is any of those in this list.
2435 See `mumamo-defined-turn-on-functions' for information about
2436 mumamo multi major modes."
2437 :type '(repeat (function :tag "Main major mode in mumamo"))
2440 (defun nxhtml-add-validation-header-if-mumamo ()
2441 "Maybe turn on validation header.
2442 See `nxhtml-validation-header-if-mumamo' for more information."
2443 ;;(nxhtml-validation-headers-check (current-buffer))
2444 (when (and (fboundp 'mumamo-main-major-mode)
2445 (memq (mumamo-main-major-mode) nxhtml-validation-header-mumamo-modes))
2446 (nxhtml-validation-header-mode 1)))
2448 ;;(define-toggle nxhtml-validation-header-if-mumamo nil
2449 (define-minor-mode nxhtml-validation-header-if-mumamo
2450 "Add a fictive validation header when mumamo is used.
2451 If this variable is t then add a Fictive XHTML Validation Header
2452 \(see `nxhtml-validation-header-mode') in buffer when mumamo is
2453 used. However do this only if `mumamo-main-major-mode' is one of
2454 those in `nxhtml-validation-header-mumamo-modes'.
2456 Changing this variable through custom adds/removes the function
2457 `nxhtml-add-validation-header-if-mumamo' to
2458 `mumamo-turn-on-hook'."
2461 (if nxhtml-validation-header-if-mumamo
2462 (add-hook 'mumamo-turn-on-hook 'nxhtml-add-validation-header-if-mumamo)
2463 (remove-hook 'mumamo-turn-on-hook 'nxhtml-add-validation-header-if-mumamo)))
2465 (defun nxhtml-validation-header-if-mumamo-toggle ()
2466 "Toggle `nxhtml-validation-header-if-mumamo'."
2468 (nxhtml-validation-header-if-mumamo (if nxhtml-validation-header-if-mumamo -1 1)))
2470 (defun nxhtml-warnings-are-visible ()
2471 (get 'rng-error 'face))
2473 (defvar nxhtml-old-rng-error-face nil)
2474 (defun nxhtml-toggle-visible-warnings ()
2475 "Toggle the red underline on validation errors.
2476 Those can be quite disturbing when using mumamo multi major modes
2477 because there will probably be many validation errors in for
2478 example a php buffer, since unfortunately the validation routines
2479 in `rng-validate-mode' from `nxml-mode' tries to validate the
2480 whole buffer as XHTML.
2482 Also, because of a \(normally unimportant) bug in Emacs 22,
2483 the red underline that marks an error will sometimes span several
2484 lines instead of just marking a single character as it
2485 should. \(This bug is a problem with overlays in Emacs 22.)"
2487 (let ((face (get 'rng-error 'face)))
2490 (setq nxhtml-old-rng-error-face (get 'rng-error 'face))
2491 (put 'rng-error 'face nil))
2492 (put 'rng-error 'face nxhtml-old-rng-error-face))))
2494 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2496 ;; (defun nxml-indent-line ()
2497 ;; "Indent current line as XML."
2498 ;; (let ((indent (nxml-compute-indent))
2499 ;; (from-end (- (point-max) (point))))
2501 ;; (beginning-of-line)
2502 ;; (let ((bol (point)))
2503 ;; (skip-chars-forward " \t")
2504 ;; ;; There is a problem with some lines, try a quick fix:
2505 ;; (when (and (= 0 indent)
2506 ;; (not (eq (char-after) ?<)))
2509 ;; (when (re-search-backward "^<" nil t)
2510 ;; (when (search-forward " ")
2511 ;; (setq indent (current-column))))))
2512 ;; (when (= 0 indent)
2513 ;; (setq indent nxml-child-indent)))
2514 ;; ;; And sometimes nxml-compute-indent get very upset, check for
2516 ;; (let ((here (point)))
2517 ;; (beginning-of-line 0)
2518 ;; (back-to-indentation)
2519 ;; (when (and (= indent (current-column))
2520 ;; (eq (char-after) ?\"))
2522 ;; (goto-char here))
2523 ;; (unless (= (current-column) indent)
2524 ;; (delete-region bol (point))
2525 ;; (indent-to indent)))
2526 ;; (when (> (- (point-max) from-end) (point))
2527 ;; (goto-char (- (point-max) from-end))))))
2530 ;; FIX-ME: untag should be in nxml-mode.el since it is in no way
2531 ;; specific to nxhtml-mode, but I do not want to change nxml-mode.el
2534 (defcustom nxml-untag-select 'yes
2535 "Decide whether to select an element untagged by `nxml-untag-element'.
2536 If this variable is 'yes the element is selected after untagging
2537 the element. The mark is set at the end of the element and point
2538 at the beginning of the element.
2540 If this variable is 'no then the element is not selected and
2541 point is not moved. If it is 'ask the user is asked what to do."
2542 :type '(choice (const :tag "Yes" yes)
2543 (const :tag "No" no)
2544 (const :tag "Ask" ask))
2547 (defun nxml-untag-element (arg)
2548 "Remove start and end tag from current element.
2549 The mark is by default set to the end of the former element and
2550 point is moved to the beginning. Mark is also activated so that
2551 it is easy to surround the former element with a new tag.
2553 Whether to select the old element is controlled by
2554 `nxml-untag-select'. The meaning of the values 'yes and 'no for
2555 this variable is flipped by using a universal argument.
2557 Note: If you want to `undo' the untag and you use
2558 `transient-mark-mode' then you must first do something so that
2559 the region is not highlighted (for example C-g)."
2561 (let ((here (point-marker))
2567 (nxml-backward-up-element)
2568 (setq el-start (point))
2569 (nxml-forward-balanced-item)
2570 (setq el-start-end (point))
2571 (goto-char el-start)
2572 (nxml-forward-element)
2573 (setq el-end-end (point-marker))
2574 (nxml-backward-single-balanced-item)
2575 (setq el-end (point))
2576 (delete-region el-end el-end-end)
2577 (delete-region el-start el-start-end)
2578 ;; Select the element or not?
2579 (if (eq nxml-untag-select 'ask)
2580 (setq select (y-or-n-p "Select the old element? "))
2581 (when (eq nxml-untag-select 'no)
2584 (setq select (not select))))
2587 (goto-char el-end-end)
2589 (setq mark-active t)
2590 (setq deactivate-mark nil)
2591 (goto-char el-start))))
2593 (defun nxhtml-rollover-insert-2v ()
2594 "Insert CSS rollover images.
2595 The upper half of the image will be used when mouse is out and
2596 the lower half when mouse is over the image.
2598 Only CSS is used for the rollover. The CSS code is written to the
2599 header part of the file if possible, otherwise it is copied to
2600 the kill ring/clipboard.
2602 The CSS code is built from a template file and the image size.
2604 This might be used for example for creating a menu with
2605 alternatives vertically or horizontally.
2609 If you want to make a small button style menu with images you
2610 can start like this:
2612 <div id=\"mylinks\">
2615 X <a href=\"news.html\">News and Notes</a>
2618 <a href=\"doc.html\">Documentation</a>
2623 Then put point at the X above (this is just a mark, should not
2624 be in your code) and call this function.
2626 It will add some CSS code to in the header of your file. You
2627 may want to tweak this a little bit, see below (or place it
2628 somewhere else). It may look like this:
2633 background: transparent url(\"img/mybutton.png\") 0 0 no-repeat;
2636 /* Text placement and size, etc */
2638 /* You may need to change top and bottom padding depending
2642 padding-bottom: 9px;
2643 text-decoration: none;
2644 white-space: nowrap;
2648 background-position: 0 -35px;
2657 For an example of usage see the file nxhtml.html that comes with
2658 nXhtml and can be opened from the nXhtml menu under
2660 nXhtml / nXhtml Help and Setup / nXhtml version nn Overview"
2662 ;; Fix-me: not quite ready yet, but should work OK."
2665 (search-forward ">" nil t)
2666 (unless (re-search-backward (rx "<"
2667 (1+ (any "a-zA-Z:"))
2668 (1+ (not (any ">")))
2670 (submatch (+? anything))
2673 (error "Can't find tag with id backwards"))
2674 (match-string-no-properties 0)))
2675 (tagid (match-string-no-properties 1))
2676 (tagovl (let ((ovl (make-overlay
2677 (match-beginning 0) (match-end 0))))
2678 (overlay-put ovl 'face 'highlight)
2680 (head-end (save-excursion (search-backward "</head" nil t))))
2682 (error "Can't find end of head tag. Need this to insert css."))
2686 (let* ((img-src (nxhtml-read-url
2687 '(?f) nil 'nxhtml-image-url-predicate
2688 (concat "Rollover image for \"" tag "\",")))
2689 (img-sizes (when (file-exists-p img-src)
2690 (image-size (create-image
2691 (expand-file-name img-src))
2695 "Class name for rollover (empty to use id="
2697 (rollover-spec (if (< 0 (length class))
2699 (concat "#" tagid)))
2700 img-width img-height
2705 (font-size (read-number "Font size (px): " 12))
2706 (css-template-file (read-file-name
2707 "CSS template file: "
2708 (expand-file-name "etc/templates/" nxhtml-install-dir)
2714 (if (y-or-n-p "Do you want to center the text? ")
2715 "text-align: center"
2716 (format "padding: %spx" (/ font-size 2))))
2718 (if (y-or-n-p "Do you want the alternatives shown in a vertical list? ")
2721 (css-template-buffer (find-file-noselect
2723 (css-template (with-current-buffer css-template-buffer
2724 ;; Do not widen, let user decide.
2725 (buffer-substring-no-properties
2726 (point-min) (point-max))))
2728 (unless (file-exists-p css-template-file)
2729 (error "Can't find file %s" css-template-file))
2732 (setq img-width (car img-sizes))
2733 (setq img-height (cdr img-sizes)))
2734 (setq img-width (read-number "Width: "))
2735 (setq img-height (read-number "Width: ")))
2736 (setq img-h2 (/ img-height 2))
2737 (setq img-w2 (/ img-width 2))
2738 (setq padding-top (/ (- img-h2 font-size) 2))
2739 ;; Fix-me: I have no idea why I have to subtract 3
2740 ;; from bottom, but inspection with Firebug seems to
2742 (setq padding-bottom (- img-h2 padding-top font-size 3))
2743 (setq css (replace-regexp-in-string "ROLLOVER_SPEC" rollover-spec css t t))
2744 (setq css (replace-regexp-in-string "IMG_WIDTH_2" (number-to-string img-h2) css t t))
2745 (setq css (replace-regexp-in-string "IMG_HEIGHT_2" (number-to-string img-h2) css t t))
2746 (setq css (replace-regexp-in-string "IMG_WIDTH" (number-to-string img-width) css t t))
2747 (setq css (replace-regexp-in-string "IMG_HEIGHT" (number-to-string img-height) css t t))
2748 (setq css (replace-regexp-in-string "IMG_URL" img-src css t t))
2749 (setq css (replace-regexp-in-string "FONT_SIZE" (number-to-string font-size) css t t))
2750 (setq css (replace-regexp-in-string "PADDING_TOP" (number-to-string padding-top) css t t))
2751 (setq css (replace-regexp-in-string "PADDING_BOTTOM" (number-to-string padding-bottom) css t t))
2752 (setq css (replace-regexp-in-string "CENTER_OR_PAD" center-or-pad css t t))
2753 (setq css (replace-regexp-in-string "HOR_OR_VER" hor-or-ver css t t))
2755 (let ((this-window (selected-window)))
2756 (find-file-other-window buffer-file-name)
2757 (goto-char head-end)
2759 (insert "<style type=\"text/css\">\n"
2762 (select-window this-window))
2764 (message "No place to insert CSS, copied to clipboard instead"))))
2765 (delete-overlay tagovl)
2768 ;; Fix-me: image border 0
2769 ;; Fix-me: SSI <!--#include file="file:///C|/EmacsW32/nxml/nxhtml/bug-tests/bug-080609.html" -->
2770 ;; Fix-me: Better a tag completion, target etc.
2771 ;; Fix-me: image map - is that possible now?
2772 ;; Fix-me: Special chars - completing on &? Or popup? Use nxml-insert-named-char
2773 ;; Fix-me: Quick table insert? A form?
2774 ;; Fix-me: Quick object insert? (applet is depreceated)
2775 ;; Fix-me: Better meta insert? Quick meta?
2776 ;; Fix-me: Quick div! Better div completion with position: static,
2777 ;; relative, absolute and fixed - with some explanations.
2778 ;; Fix-me: Quick hr?
2779 ;; Fix-me: Import CSS? Export CSS?
2780 ;; Fix-me: Use nxhtml-js.el?
2781 ;; Fix-me: Scroll bar colors etc? See 1stPage.
2783 ;; scrollbar-arrow-color: #FF6699;
2784 ;; scrollbar-3dlight-color: #00FF33;
2785 ;; scrollbar-highlight-color: #66FFFF;
2786 ;; scrollbar-face-color: #6699FF;
2787 ;; scrollbar-shadow-color: #6633CC;
2788 ;; scrollbar-darkshadow-color: #660099;
2789 ;; scrollbar-track-color: #CC6633;
2791 ;; Fix-me: More quick menus: http://www.cssplay.co.uk/menus/
2793 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2794 (provide 'nxhtml-mode)
2796 ;;; nxhtml-mode.el ends here