;;; nxhtml-mode.el --- Edit XHTML files ;; ;; Author: Lennart Borgman (lennart O borgman A gmail O com) ;; Parts are from Peter Heslin (see below) ;; Created: 2005-08-05 ;;Version: ;; Last-Updated: 2008-12-28 Sun ;; Keywords: languages ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Commentary: ;; ;; The purpose of nxhtml.el is to add some features that are useful ;; when editing XHTML files to nxml-mode. For more information see ;; `nxhtml-mode'. ;; ;; ;; Usage: ;; ;; See the file readme.txt in the directory above this file. Or, if ;; you do not have that follow the instructions below. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; History: ;; ;; 2006-04-25: Added completion for href, src etc. Removed xhtmlin. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; This file is not part of Emacs ;; ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 2, or (at ;; your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Code: (eval-when-compile (require 'cl)) (eval-when-compile (require 'hideshow)) (eval-when-compile (require 'appmenu-fold nil t)) (eval-when-compile (require 'fold-dwim nil t)) (eval-when-compile (require 'foldit nil t)) (eval-when-compile (require 'html-pagetoc nil t)) (eval-when-compile (require 'html-toc nil t)) (eval-when-compile (require 'mumamo nil t)) (eval-when-compile (require 'mlinks nil t)) (eval-when-compile (require 'nxhtml-base)) ;;(eval-when-compile (require 'nxhtml-menu)) ;; recursive load (eval-when-compile (require 'ourcomments-util nil t)) (eval-and-compile (require 'typesetter nil t)) (eval-when-compile (require 'xhtml-help nil t)) (eval-when-compile (require 'popcmp nil t)) ;; (eval-when-compile ;; (unless (or (< emacs-major-version 23) ;; (boundp 'nxhtml-menu:version) ;; (featurep 'nxhtml-autostart)) ;; (let ((efn (expand-file-name ;; "../autostart.el" ;; (file-name-directory ;; (or load-file-name ;; (when (boundp 'bytecomp-filename) bytecomp-filename) ;; buffer-file-name))))) ;; (message "efn=%s" efn) ;; (load efn)) ;; (require 'rng-valid) ;; (require 'rng-nxml))) (require 'button) (require 'loadhist) (require 'nxml-mode nil t) (require 'rng-nxml nil t) (require 'rng-valid nil t) ;; Require nxml things conditionally to silence byte compiler under ;; Emacs 22. (eval-and-compile (require 'rngalt nil t)) (require 'url-parse) (require 'url-expand) (require 'popcmp nil t) (eval-when-compile (require 'html-imenu nil t)) (eval-when-compile (require 'tidy-xhtml nil t)) (eval-when-compile (require 'html-quote nil t)) (defun nxhtml-version () "Show nxthml version." (interactive) (message "nXhtml mode version %s" nxhtml-menu:version)) ;;(defun nxhtml-nxml-fontify-attribute (att &optional namespace-declaration) ;;"Holds the original `nxml-fontify-attribute' function.") ;;(fset 'nxhtml-nxml-fontify-attribute (symbol-function 'nxml-fontify-attribute)) (defun nxhtml-turn-onoff-tag-do-also (on) (add-hook 'nxhtml-mode-hook 'nxhtml-check-tag-do-also) (dolist (b (buffer-list)) (when (with-current-buffer b (eq major-mode 'nxhtml-mode)) (if on (progn (add-hook 'rngalt-complete-tag-hooks 'nxhtml-complete-tag-do-also t t) ) (remove-hook 'rngalt-complete-tag-hooks 'nxhtml-complete-tag-do-also t) )))) ;;(define-toggle nxhtml-tag-do-also t (define-minor-mode nxhtml-tag-do-also "When completing tag names do some more if non-nil. For some tag names additional things can be done at completion to speed writing up. For example for an tag `nxhtml-mode' can prompt for src attribute and add width and height attributes if this attribute points to a local file. You can add additional elisp code for completing to `nxhtml-complete-tag-do-also'." :global t :init-value t :group 'nxhtml (nxhtml-turn-onoff-tag-do-also nxhtml-tag-do-also)) (when nxhtml-tag-do-also (nxhtml-tag-do-also 1)) (defun nxhtml-tag-do-also-toggle () "Toggle `nxhtml-tag-do-also'." (interactive) (nxhtml-tag-do-also (if nxhtml-tag-do-also -1 1))) (defun nxhtml-check-tag-do-also () (when nxhtml-tag-do-also (nxhtml-turn-onoff-tag-do-also t))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Folding etc. ;; This part is origially taken from ;; http://www.emacswiki.org/cgi-bin/wiki/NxmlModeForXHTML and was ;; originally written by Peter Heslin, but has been changed rather ;; much. ;; (defun nxhtml-hs-adjust-beg-func (pos) ;; (save-excursion ;; (save-match-data ;; ;; (search-backward "<" nil t) ;; ;; (forward-char) ;; ;; (search-forward ">" nil t) ;; ) ;; (point))) (defun nxhtml-hs-forward-sexp-func (pos) (nxhtml-hs-forward-element)) (defun nxhtml-hs-forward-element () (let ((nxml-sexp-element-flag)) (setq nxml-sexp-element-flag (not (looking-at "" "") t)) ((eq where 'in-xml-attr-val) (let (attr delimiter val) (save-excursion (save-match-data (re-search-forward "\\=[^<> \t\r\n\"]*" nil t))) (let* ((name-start (match-beginning 1)) (name-end (match-end 1)) (colon (match-beginning 2)) (attr (buffer-substring-no-properties name-start (or colon name-end))) (value-start (1+ (match-beginning 3))) (tag (save-excursion (when (search-backward-regexp "<[[:alpha:]]+" nil t) (match-string 0)))) (init (buffer-substring-no-properties value-start (point)))) (setq delimiter (char-before value-start)) (cond ((string= "encoding" attr) ;; Give a default that works in browsers today (setq val (nxhtml-coding-systems-complete init (symbol-name nxhtml-default-encoding)))) ((string= "version" attr) (setq val "1.0"))) (when val (insert val) t) ))) ((or (memq where '(in-text after-validation-header in-empty-page))) (rngalt-complete-tag-region-prepare) (insert "<") (condition-case err (nxhtml-redisplay-complete) (quit (message "%s" (error-message-string err)) (undo-start) (undo-more 1) (rngalt-complete-tag-region-cleanup))) t) (t ;;(message "LAST TRY where=%s" (nxhtml-check-where))(sit-for 1) nil) )))) (defun nxhtml-img-tag-do-also () (insert "alt=\"") (rngalt-validate) (insert (read-string "Alt attribute: ") "\" ") (insert "src=\"") (rngalt-validate) (let ((src (nxhtml-read-url nil nil 'nxhtml-image-url-predicate "Image"))) (insert src) (insert "\"") (when (file-exists-p src) (let ((sizes (image-size (create-image (expand-file-name src)) t))) (insert " width=\"" (format "%d" (car sizes)) "\"" " height=\"" (format "%d" (cdr sizes)) "\"") ))) (unless (save-match-data (looking-at "[^<]\\{,200\\}>")) (insert " />"))) (defun nxhtml-redisplay-complete () (rngalt-validate) (rng-cancel-timers) (message "") (redisplay t) (nxml-complete) (rng-activate-timers)) (defun nxhtml-read-from-minibuffer (prompt &optional initial-contents keymap read hist default-value inherit-input-method) (rng-cancel-timers) (message "") (let ((res (read-from-minibuffer prompt initial-contents keymap read hist default-value inherit-input-method))) (rng-activate-timers) res)) (defun nxhtml-meta-tag-do-also () (let ((type (popcmp-completing-read "Type: " '( ;;"Refresh/Redirect" "HTTP Message Headers" "Robot Rules" "Description for Search Engines" )))) (cond ((string= type "Description for Search Engines") (insert " name=\"Description\"") (insert " content=\"") (insert (nxhtml-read-from-minibuffer "Description: ")) (insert "\" />")) ((string= type "Robot Rules") (insert " name=\"Robots\"") (insert " content=\"") (nxhtml-redisplay-complete) (insert " />")) ((string= type "HTTP Message Headers") (insert " http-equiv=\"") (nxhtml-redisplay-complete) (insert " content=\"") (insert (nxhtml-read-from-minibuffer "Content: ")) (insert "\" />"))))) (defun nxhtml-style-tag-do-also () (insert "type=\"text/css\"") (insert " media=\"") (nxhtml-redisplay-complete) (insert ">") (indent-according-to-mode) (insert "\n/* */") (indent-according-to-mode) (insert "\n") (indent-according-to-mode) (insert "\n") (end-of-line -2)) (defun nxhtml-script-tag-do-also () (let ((type (popcmp-completing-read "Type: " '("Inlined" "Linked")))) (cond ((string= type "Inlined") (insert "type=\"text/javascript\">") (indent-according-to-mode) (insert "\n// ") (indent-according-to-mode) (insert "\n") (indent-according-to-mode) (end-of-line -1)) ((string= type "Linked") (insert "type=\"text/javascript\"") (insert " src=\"") (nxhtml-redisplay-complete) (insert ">"))))) (defun nxhtml-link-tag-do-also () (let ((type (popcmp-completing-read "Type: " '( "Other" "Shortcut icon" "Style sheet" )))) (cond ((string= type "Style sheet") (insert " rel=\"Stylesheet\" ") (insert "type=\"text/css\" ") (insert "href=\"") (nxhtml-redisplay-complete) (insert " media=\"") (nxhtml-redisplay-complete) (insert " />")) ((string= type "Shortcut icon") (insert " rel=\"Shortcut Icon\" ") (insert "href=\"") (nxhtml-redisplay-complete) (insert " />")) (t (insert " ") (nxhtml-redisplay-complete) )))) (defun nxhtml-input-tag-do-also () (insert " ") (rngalt-validate) ;; type= (insert "type=\"") (nxhtml-redisplay-complete) (insert " ") (let* ((choice (save-match-data (when (looking-back "type=\"\\(.*\\)\" ") (match-string 1))))) ;;(insert "type=\"" choice "\" ") (rngalt-validate) ;;(message "choice=%s" choice)(sit-for 2) ;; name= (when (member choice '("button" "checkbox" "file" "hidden" "image" "password" "radio" "text")) (insert "name=\"" (read-string "Name (name): ") "\" ") (rngalt-validate)) ;; checked= (when (member choice '("checkbox" "radio")) (when (y-or-n-p "Checked? (checked): ") (insert "checked=\"checked\" ") (rngalt-validate))) ;; disabled= (unless (string= choice "hidden") (unless (y-or-n-p "Enabled? : ") (insert "disabled=\"disabled\" ") (rngalt-validate))) ;; readonly= (when (string= choice "text") (when (y-or-n-p "Readonly? (readonly): ") (insert "readonly=\"readonly\" ")) (rngalt-validate)) (when (string= choice "file") ;; accept= (require 'mailcap) (condition-case err (let ((prompt (concat "Accept mime type, RET to stop (" "C-g to skip" "): ")) (mime " ") mimes (types (when (boundp 'mailcap-mime-extensions) (mapcar (lambda (elt) (cdr elt)) mailcap-mime-extensions)))) (while (< 0 (length mime)) (setq mime (if types (completing-read prompt types) (read-string prompt))) (when (< 0 (length mime)) (if mimes (setq mimes (concat mimes "," mime)) (setq mimes mime)))) (when (and mimes (< 0 (length mimes))) (insert "accept=\"" mimes "\" "))) (quit (message "Skipped accept attribute"))) (rngalt-validate)) (when (string= choice "image") ;; alt= (insert "alt=\"") (rngalt-validate) (insert (read-string "Alt attribute: ") "\" ") (rngalt-validate) ;; src= (insert "src=\"") (rngalt-validate) (let ((src (nxhtml-read-url nil nil 'nxhtml-image-url-predicate "Image"))) (insert src) (insert "\" ")) (rngalt-validate)) ;; value= (cond ((member choice '("button" "reset" "submit")) (nxhtml-do-also-value "Label")) ((member choice '("checkbox" "radio")) (nxhtml-do-also-value "Result")) ((member choice '("hidden" "password" "text")) (nxhtml-do-also-value "Value")) ) (insert "/>") ;;(message "type=%s" choice)(sit-for 2) )) (defun nxhtml-do-also-value (label) (let ((v (read-string (concat label " (value): ")))) (when (and v (< 0 (length v))) (insert " value=\"" v "\" ")))) (defun nxhtml-form-tag-do-also () (insert "action=\"") (rngalt-validate) (let ((src (nxhtml-read-url nil nil nil "Action"))) (insert src "\" ")) ) (defun nxhtml-a-tag-do-also () (insert " href=\"") (rngalt-validate) (insert (nxhtml-read-url t)) (insert "\"") (let* ((pre-choices '("_blank" "_parent" "_self" "_top")) (all-choices (reverse (cons "None" (cons "Frame name" pre-choices)))) choice (prompt "Target: ")) (setq choice (popcmp-completing-read prompt all-choices nil t "" nil nil t)) (unless (string= choice "None") (insert " target=\"") (cond ((member choice pre-choices) (insert choice "\"")) ((string= choice "Frame name") (rngalt-validate) (insert (read-string "Frame name: ") "\"")) (t (error "Uh?"))))) (insert ">") (rngalt-validate) (insert (read-string "Link title: ") "")) (defconst nxhtml-complete-tag-do-also '(("a" nxhtml-a-tag-do-also) ;; (lambda () ;; (insert " href=\"") ;; (rngalt-validate) ;; (insert (nxhtml-read-url t)) ;; (insert "\""))) ("form" nxhtml-form-tag-do-also) ("img" nxhtml-img-tag-do-also) ("input" nxhtml-input-tag-do-also) ("link" nxhtml-link-tag-do-also) ("script" nxhtml-script-tag-do-also) ("style" nxhtml-style-tag-do-also) ("meta" nxhtml-meta-tag-do-also) ) "List of functions to call at tag completion. Each element of the list have the form \(TAG-NAME TAG-FUN) If `nxhtml-tag-do-also' is non-nil then TAG-FUN is called after by `nxml-complete' (with the special setup of this function for `nxhtml-mode') when completing a tag with the name TAG-NAME. The list is handled as an association list, ie only the first occurence of a tag name is used.") (defun nxhtml-complete-tag-do-also-for-state-completion (dummy-completed) "Add this to state completion functions completed hook." (when (and nxhtml-tag-do-also (derived-mode-p 'nxhtml-mode)) ;; Find out tag (let ((tag nil)) (save-match-data ;;(when (looking-back "<\\([a-z]+\\)[[:blank:]]+") (when (looking-back "<\\([a-z]+\\)") (setq tag (match-string 1)))) (when tag (insert " ") (nxhtml-complete-tag-do-also tag))))) (defun nxhtml-complete-tag-do-also (tag) ;; First required attributes: (let ((tagrec (assoc tag nxhtml-complete-tag-do-also))) (when tagrec (funcall (cadr tagrec)))) ) ;;;###autoload (define-minor-mode nxhtml-validation-header-mode "If on use a Fictive XHTML Validation Header for the buffer. See `nxhtml-set-validation-header' for information about Fictive XHTML Validation Headers. This mode may be turned on automatically in two ways: - If you try to do completion of a XHTML tag or attribute then `nxthml-mode' may ask you if you want to turn this mode on if needed. - You can also choose to have it turned on automatically whenever a mumamo multi major mode is used, see `nxhtml-validation-header-if-mumamo' for further information." :global nil :lighter " VH" :group 'nxhtml (if nxhtml-validation-header-mode (progn (unless nxhtml-current-validation-header (setq nxhtml-current-validation-header (nxhtml-get-default-validation-header))) ;;(message "nxhtml-current-validation-header=%s" nxhtml-current-validation-header) (if nxhtml-current-validation-header (progn (nxhtml-apply-validation-header) (add-hook 'change-major-mode-hook 'nxhtml-vhm-change-major nil t) (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) (add-hook 'mumamo-change-major-mode-hook 'nxhtml-vhm-mumamo-change-major nil t) (add-hook 'mumamo-after-change-major-mode-hook 'nxhtml-vhm-mumamo-after-change-major nil t))) (run-with-idle-timer 0 nil 'nxhtml-validation-header-empty (current-buffer)))) (rngalt-set-validation-header nil) (setq nxhtml-current-validation-header nil) (remove-hook 'after-change-major-mode-hook 'nxhtml-vhm-after-change-major t) (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) (remove-hook 'mumamo-change-major-mode-hook 'nxhtml-vhm-mumamo-change-major t) (remove-hook 'mumamo-after-change-major-mode-hook 'nxhtml-vhm-mumamo-after-change-major t)))) (defun nxhtml-can-insert-page-here () (and (not nxhtml-validation-header-mode) (= 1 (point)) (or (= 0 (buffer-size)) (save-restriction (widen) (save-match-data (looking-at (rx buffer-start (0+ space) buffer-end))))))) (defun nxhtml-complete-first-try () (when (nxhtml-can-insert-page-here) (nxhtml-empty-page-completion))) (defun nxhtml-completing-read-tag (prompt table &optional predicate require-match initial-input hist def inherit-input-method) (let ((popcmp-in-buffer-allowed t)) (popcmp-completing-read prompt table predicate require-match initial-input hist def inherit-input-method nxhtml-help-tag nxhtml-tag-sets))) (defun nxhtml-add-required-to-attr-set (tag) (let ((missing (when tag (rngalt-get-missing-required-attr (nxthml-is-single-tag tag))))) (if (not missing) nxhtml-attr-sets (cons (cons "Required" missing) nxhtml-attr-sets)))) (defun nxhtml-get-tag-specific-attr-help (tag) (append (cdr (assoc tag nxhtml-help-attribute-name-tag)) nxhtml-help-attribute-name) ) (defconst nxhtml-in-start-tag-regex ;;(defconst rng-in-start-tag-name-regex (replace-regexp-in-string "w" xmltok-ncname-regexp ;; Not entirely correct since < could be part of attribute value: "<\\(w\\(?::w?\\)?\\)+ [^<]*" t t)) (defun nxhtml-completing-read-attribute-name (prompt table &optional predicate require-match initial-input hist def inherit-input-method) (let* ((tag (save-match-data ;;(when (looking-back "<\\([a-z1-6]+\\) [^<]*") (when (looking-back nxhtml-in-start-tag-regex) (match-string 1)))) (attr-sets (nxhtml-add-required-to-attr-set tag)) (help-attr (nxhtml-get-tag-specific-attr-help tag)) (popcmp-in-buffer-allowed t) ) (popcmp-completing-read prompt table predicate require-match initial-input hist def inherit-input-method help-attr attr-sets))) (defun nxhtml-completing-read-attribute-value (prompt table &optional predicate require-match initial-input hist def inherit-input-method) (let (val) (if table (let ((popcmp-in-buffer-allowed t)) (setq val (popcmp-completing-read prompt table predicate require-match initial-input hist def inherit-input-method))) (let* (init delimiter (lt-pos (save-excursion (search-backward "<" nil t))) (in-attr-val (save-excursion (re-search-backward rng-in-attribute-value-regex lt-pos t))) (in-xml-attr-val (unless in-attr-val (save-excursion (re-search-backward nxhtml-in-xml-attribute-value-regex lt-pos t)))) ) (when (or in-attr-val in-xml-attr-val) ;;(save-match-data (save-excursion (re-search-forward "\\=[^<> \t\r\n\"]*" nil t))) (let* ((name-start (match-beginning 1)) (name-end (match-end 1)) (colon (match-beginning 2)) (attr (buffer-substring-no-properties name-start (or colon name-end))) (value-start (1+ (match-beginning 3))) tag-start-end (tag (save-excursion (when (search-backward-regexp "<[[:alpha:]]+" nil t) (setq tag-start-end (match-end 0)) (match-string-no-properties 0))))) (setq init (buffer-substring-no-properties value-start (point))) (setq delimiter (char-before value-start)) (if in-xml-attr-val (error "in-xml-attr-val should not be true here!") ;; (cond ((string= "encoding" attr) ;; ;; Give a default that works in browsers today ;; (setq val (nxhtml-coding-systems-complete ;; init ;; (symbol-name nxhtml-default-encoding)))) ;; ((string= "version" attr) ;; (setq val "1.0"))) (cond ((string= "rel" attr) (cond ((string= " Fictive XHTML Validation Header " ) ("head-iso-8859-1" . " " ) ("html-iso-8859-1" . " " ) ;; ("doctype-iso-8859-1" . ;; " ;; ;; " ;; ) ;; ("xml-iso-8859-1" . ;; " ;; " ;; ) ("body-utf-8" . " Fictive XHTML Validation Header " ) ("head-utf-8" . " " ) ("head-closed-utf-8" . " " ) ("html-utf-8" . " " ) ;; ("doctype-utf-8" . ;; " ;; ;; " ;; ) ;; ("xml-utf-8" . ;; " ;; " ;; ) ) "Fictive XHTML validation headers. Used by `nxhtml-set-validation-header'." :type '(alist :key-type string :value-type string) :group 'nxhtml) (defcustom nxhtml-default-validation-header nil "Default Fictive XHTML validation header. Must be nil or one of the key values in `nxhtml-validation-headers'." :type 'string :set (lambda (sym val) (if (or (null val) (assoc val nxhtml-validation-headers)) (set-default sym val) (lwarn 'nxhtml-default-validation-header :warning "There is no Fictive XHTML Validation Header named %s" val))) :group 'nxhtml) (defun nxhtml-must-have-validation-headers () (unless nxhtml-validation-headers (error "No XHTML validation headers. Please customize nxhtml-validation-headers."))) (defvar nxhtml-set-validation-header-hist nil) (defcustom nxhtml-guess-validation-header-alist ;;(rx line-start (0+ blank) "" . "head-closed-utf-8") ("^[[:blank:]]* nh 1) (completing-read "XHTML validation header: " nxhtml-validation-headers nil t default nxhtml-set-validation-header-hist) (if (not (y-or-n-p "Only one XHTML validation header is defined. Define more? ")) default (customize-option 'nxhtml-validation-headers) 'adding))))) ;;(lwarn 'svh2 :warning "key=%s" key) (or key (setq key (nxhtml-get-default-validation-header)) (setq key (cons 'schema "XHTML"))) (unless (eq key 'adding) (setq nxhtml-current-validation-header key) (nxhtml-validation-header-mode 1) (nxhtml-apply-validation-header))) (defun nxhtml-apply-validation-header () (when nxhtml-current-validation-header (setq rngalt-major-mode (if (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) (mumamo-main-major-mode) major-mode)) (let* ((key nxhtml-current-validation-header) (rec (unless (listp key) (assoc key nxhtml-validation-headers))) (header (cdr rec))) (if (listp key) (let ((schema-file (rng-locate-schema-file (cdr key)))) (unless schema-file (error "Could not locate schema for type id `%s'" key)) ;type-id)) (rng-set-schema-file-1 schema-file)) (rngalt-set-validation-header header) )))) (defun nxhtml-update-validation-header () "Update the validation header in the buffer as needed." (interactive) (let ((mode-on nxhtml-validation-header-mode)) (when mode-on (nxhtml-validation-header-mode 0)) (setq nxhtml-current-validation-header nil) (when mode-on (nxhtml-validation-header-mode 1)))) (defun nxhtml-vhm-change-major () "Turn off `nxhtml-validation-header-mode' after change major." ;;(message "nxhtml-vhm-change-major here") (unless (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) (setq nxhtml-current-validation-header nil)) (run-with-idle-timer 0 nil 'nxhtml-validation-header-empty (current-buffer))) (put 'nxhtml-vhm-change-mode 'permanent-local-hook t) (defun nxhtml-recheck-validation-header () "Just turn off and on again `nxhtml-validation-header-mode'. This will adjust the XHTML validation to the code currently in the buffer." (interactive) (nxhtml-validation-header-mode -1) (nxhtml-validation-header-mode 1)) (defun nxhtml-validation-header-empty (buffer) "Turn off validation header mode. This is called because there was no validation header." (with-current-buffer buffer (unless nxhtml-current-validation-header ;;(message "nxhtml-validation-header-empty") (save-match-data ;; runs in timer (nxhtml-validation-header-mode -1)) ;;(message "No validation header was needed") ))) (defun nxhtml-turn-on-validation-header-mode () "Turn on `nxhtml-validation-header-mode'." (nxhtml-validation-header-mode 1)) (defun nxhtml-vhm-mumamo-change-major () (put 'rngalt-validation-header 'permanent-local t) (put 'nxhtml-validation-header-mode 'permanent-local t) (put 'nxhtml-current-validation-header 'permanent-local t) ;;(put 'nxhtml-validation-header-mode-major-mode 'permanent-local t) ;;(setq nxhtml-validation-header-mode-major-mode mumamo-set-major-running) ) (defun nxhtml-vhm-mumamo-after-change-major () (put 'rngalt-validation-header 'permanent-local nil) (put 'nxhtml-validation-header-mode 'permanent-local nil) (put 'nxhtml-current-validation-header 'permanent-local nil) ;;(put 'nxhtml-validation-header-mode-major-mode 'permanent-local nil) ) (defcustom nxhtml-validation-headers-check 'html "Defines what check the function with the same name does. The function returns true if the condition here is met." :type '(choice :tag "Add Fictive XHTML Validation Header if:" (const :tag "If buffer contains html" html) (const :tag "If buffer contains html or is empty" html-empty)) :group 'nxhtml) ;; (defun nxhtml-validation-headers-check (buffer) ;; "Return non-nil if buffer contains a html tag or is empty. ;; This is for use with `nxhtml-validation-header-filenames'. ;; The variable `nxhtml-validation-headers-check' determines how the ;; check is made." ;; (if (= 0 (buffer-size buffer)) ;; (eq 'html-empty nxhtml-validation-headers-check) ;; (save-match-data ;; (save-restriction ;; (let ((here (point)) ;; (html nil)) ;; (goto-char (point-min)) ;; (setq html (re-search-forward "" nil t)) ;; (goto-char here) ;; html))))) ;; (defcustom nxhtml-validation-header-filenames ;; '( ;; ("\.php\\'" nxhtml-validation-headers-check) ;; ("\.rhtml\\'" nxhtml-validation-headers-check) ;; ("\.jsp\\'" nxhtml-validation-headers-check) ;; ("\.gsp\\'" nxhtml-validation-headers-check) ;; ) ;; "Alist for turning on `nxhtml-validation-mode'. ;; The entries in the list should have the form ;; \(FILE-REGEXP CHECK-FUNCION) ;; If buffer file name matches the regexp FILE-REGEXP and the ;; function CHECK-FUNCTION returns non-nil when called with the ;; buffer as an argument \(or CHECK-FUNCTION is nil) then ;; `nxhtml-global-validation-header-mode' will turn on ;; `nxhtml-validation-header-mode' in buffer. ;; The function `nxhtml-validation-headers-check' may be a useful ;; value for CHECK-FUNCTION. ;; See also `nxhtml-maybe-turn-on-validation-header'." ;; :type '(alist :key-type regexp :tag "File name regexp" ;; :value-type (group (choice (const :tag "No more check" nil) ;; (function :tag "Check buffer with")))) ;; :group 'nxhtml) ;; (defun nxhtml-maybe-turn-on-validation-header () ;; "Maybe turn on `nxhtml-validation-header-mode' in buffer. ;; This is called by `nxhtml-global-validation-header-mode'. ;; See `nxhtml-validation-header-filenames' for how the check ;; is made." ;; (or (and (or (and mumamo-mode ;; (eq (mumamo-main-major-mode) 'nxhtml-mode)) ;; (eq major-mode 'nxhtml-mode)) ;; rngalt-validation-header ;; nxhtml-current-validation-header ;; nxhtml-validation-header-mode ;; (progn ;; ;;(lwarn 'maybe :warning "quick, buffer=%s" (current-buffer)) ;; (nxhtml-validation-header-mode 1) ;; t)) ;; (when (buffer-file-name) ;; (unless (or ;;nxhtml-validation-header-mode ;; (minibufferp (current-buffer)) ;; (string= " " (substring (buffer-name) 0 1)) ;; (string= "*" (substring (buffer-name) 0 1)) ;; ) ;; (when (catch 'turn-on ;; (save-match-data ;; (dolist (rec nxhtml-validation-header-filenames) ;; (when (string-match (car rec) (buffer-file-name)) ;; (let ((fun (nth 1 rec))) ;; (if (not fun) ;; (progn ;; ;;(lwarn 't :warning "matched %s to %s, nil" (car rec) (buffer-file-name)) ;; (throw 'turn-on t)) ;; (when (funcall fun (current-buffer)) ;; ;;(lwarn 't :warning "matched %s to %s" (car rec) (buffer-file-name)) ;; (throw 'turn-on t)))))))) ;; ;;(lwarn 't :warning "turn on %s, buffer=%s" major-mode (current-buffer)) ;; (nxhtml-validation-header-mode 1)))))) ;; ;; Fix-me: Is this really the way to do it? Would it not be better to ;; ;; tie this to mumamo-mode in the turn on hook there? After all ;; ;; validation headers are probably not used unless mumamo-mode is on. ;; (define-globalized-minor-mode nxhtml-global-validation-header-mode ;; nxhtml-validation-header-mode ;; nxhtml-maybe-turn-on-validation-header ;; :group 'nxhtml) ;; ;; The problem with global minor modes: ;; (when (and nxhtml-global-validation-header-mode ;; (not (boundp 'define-global-minor-mode-bug))) ;; (nxhtml-global-validation-header-mode 1)) (defcustom nxhtml-validation-header-mumamo-modes '(nxhtml-mode) "Main major modes for which to turn on validation header. Turn on Fictive XHTML Validation Header if main major mode for the used mumamo multi major mode is any of those in this list. See `mumamo-defined-turn-on-functions' for information about mumamo multi major modes." :type '(repeat (function :tag "Main major mode in mumamo")) :group 'nxhtml) (defun nxhtml-add-validation-header-if-mumamo () "Maybe turn on validation header. See `nxhtml-validation-header-if-mumamo' for more information." ;;(nxhtml-validation-headers-check (current-buffer)) (when (and (fboundp 'mumamo-main-major-mode) (memq (mumamo-main-major-mode) nxhtml-validation-header-mumamo-modes)) (nxhtml-validation-header-mode 1))) ;;(define-toggle nxhtml-validation-header-if-mumamo nil (define-minor-mode nxhtml-validation-header-if-mumamo "Add a fictive validation header when mumamo is used. If this variable is t then add a Fictive XHTML Validation Header \(see `nxhtml-validation-header-mode') in buffer when mumamo is used. However do this only if `mumamo-main-major-mode' is one of those in `nxhtml-validation-header-mumamo-modes'. Changing this variable through custom adds/removes the function `nxhtml-add-validation-header-if-mumamo' to `mumamo-turn-on-hook'." :global t :group 'nxhtml (if nxhtml-validation-header-if-mumamo (add-hook 'mumamo-turn-on-hook 'nxhtml-add-validation-header-if-mumamo) (remove-hook 'mumamo-turn-on-hook 'nxhtml-add-validation-header-if-mumamo))) (defun nxhtml-validation-header-if-mumamo-toggle () "Toggle `nxhtml-validation-header-if-mumamo'." (interactive) (nxhtml-validation-header-if-mumamo (if nxhtml-validation-header-if-mumamo -1 1))) (defun nxhtml-warnings-are-visible () (get 'rng-error 'face)) (defvar nxhtml-old-rng-error-face nil) (defun nxhtml-toggle-visible-warnings () "Toggle the red underline on validation errors. Those can be quite disturbing when using mumamo multi major modes because there will probably be many validation errors in for example a php buffer, since unfortunately the validation routines in `rng-validate-mode' from `nxml-mode' tries to validate the whole buffer as XHTML. Also, because of a \(normally unimportant) bug in Emacs 22, the red underline that marks an error will sometimes span several lines instead of just marking a single character as it should. \(This bug is a problem with overlays in Emacs 22.)" (interactive) (let ((face (get 'rng-error 'face))) (if face (progn (setq nxhtml-old-rng-error-face (get 'rng-error 'face)) (put 'rng-error 'face nil)) (put 'rng-error 'face nxhtml-old-rng-error-face)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Bug corrections ;; (defun nxml-indent-line () ;; "Indent current line as XML." ;; (let ((indent (nxml-compute-indent)) ;; (from-end (- (point-max) (point)))) ;; (when indent ;; (beginning-of-line) ;; (let ((bol (point))) ;; (skip-chars-forward " \t") ;; ;; There is a problem with some lines, try a quick fix: ;; (when (and (= 0 indent) ;; (not (eq (char-after) ?<))) ;; (save-excursion ;; (save-match-data ;; (when (re-search-backward "^<" nil t) ;; (when (search-forward " ") ;; (setq indent (current-column)))))) ;; (when (= 0 indent) ;; (setq indent nxml-child-indent))) ;; ;; And sometimes nxml-compute-indent get very upset, check for ;; ;; that: ;; (let ((here (point))) ;; (beginning-of-line 0) ;; (back-to-indentation) ;; (when (and (= indent (current-column)) ;; (eq (char-after) ?\")) ;; (setq indent 0)) ;; (goto-char here)) ;; (unless (= (current-column) indent) ;; (delete-region bol (point)) ;; (indent-to indent))) ;; (when (> (- (point-max) from-end) (point)) ;; (goto-char (- (point-max) from-end)))))) ;; FIX-ME: untag should be in nxml-mode.el since it is in no way ;; specific to nxhtml-mode, but I do not want to change nxml-mode.el ;; at the moment. (defcustom nxml-untag-select 'yes "Decide whether to select an element untagged by `nxml-untag-element'. If this variable is 'yes the element is selected after untagging the element. The mark is set at the end of the element and point at the beginning of the element. If this variable is 'no then the element is not selected and point is not moved. If it is 'ask the user is asked what to do." :type '(choice (const :tag "Yes" yes) (const :tag "No" no) (const :tag "Ask" ask)) :group 'nxml) (defun nxml-untag-element (arg) "Remove start and end tag from current element. The mark is by default set to the end of the former element and point is moved to the beginning. Mark is also activated so that it is easy to surround the former element with a new tag. Whether to select the old element is controlled by `nxml-untag-select'. The meaning of the values 'yes and 'no for this variable is flipped by using a universal argument. Note: If you want to `undo' the untag and you use `transient-mark-mode' then you must first do something so that the region is not highlighted (for example C-g)." (interactive "*P") (let ((here (point-marker)) el-start el-start-end el-end el-end-end (select t)) (nxml-backward-up-element) (setq el-start (point)) (nxml-forward-balanced-item) (setq el-start-end (point)) (goto-char el-start) (nxml-forward-element) (setq el-end-end (point-marker)) (nxml-backward-single-balanced-item) (setq el-end (point)) (delete-region el-end el-end-end) (delete-region el-start el-start-end) ;; Select the element or not? (if (eq nxml-untag-select 'ask) (setq select (y-or-n-p "Select the old element? ")) (when (eq nxml-untag-select 'no) (setq select nil)) (when arg (setq select (not select)))) (if (not select) (goto-char here) (goto-char el-end-end) (push-mark nil t t) (setq mark-active t) (setq deactivate-mark nil) (goto-char el-start)))) (defun nxhtml-rollover-insert-2v () "Insert CSS rollover images. The upper half of the image will be used when mouse is out and the lower half when mouse is over the image. Only CSS is used for the rollover. The CSS code is written to the header part of the file if possible, otherwise it is copied to the kill ring/clipboard. The CSS code is built from a template file and the image size. This might be used for example for creating a menu with alternatives vertically or horizontally. Usage example: If you want to make a small button style menu with images you can start like this: Then put point at the X above (this is just a mark, should not be in your code) and call this function. It will add some CSS code to in the header of your file. You may want to tweak this a little bit, see below (or place it somewhere else). It may look like this: #mylinks a { /* Image */ display: block; background: transparent url(\"img/mybutton.png\") 0 0 no-repeat; overflow: hidden; width: 200px; /* Text placement and size, etc */ text-align: center; /* You may need to change top and bottom padding depending on font size. */ padding-top: 11px; font-size: 12px; padding-bottom: 9px; text-decoration: none; white-space: nowrap; border: none; } #mylinks a:hover { background-position: 0 -35px; } #mylinks li { display: inline; padding: 0; margin: 0; float: none; } For an example of usage see the file nxhtml.html that comes with nXhtml and can be opened from the nXhtml menu under nXhtml / nXhtml Help and Setup / nXhtml version nn Overview" (interactive) ;; Fix-me: not quite ready yet, but should work OK." (save-excursion (let* ((tag (progn (search-forward ">" nil t) (unless (re-search-backward (rx "<" (1+ (any "a-zA-Z:")) (1+ (not (any ">"))) " id=\"" (submatch (+? anything)) "\"") nil t) (error "Can't find tag with id backwards")) (match-string-no-properties 0))) (tagid (match-string-no-properties 1)) (tagovl (let ((ovl (make-overlay (match-beginning 0) (match-end 0)))) (overlay-put ovl 'face 'highlight) ovl)) (head-end (save-excursion (search-backward "\n" css "\n\n") (select-window this-window)) (kill-new css) (message "No place to insert CSS, copied to clipboard instead")))) (delete-overlay tagovl) )))) ;; Fix-me: image border 0 ;; Fix-me: SSI ;; Fix-me: Better a tag completion, target etc. ;; Fix-me: image map - is that possible now? ;; Fix-me: Special chars - completing on &? Or popup? Use nxml-insert-named-char ;; Fix-me: Quick table insert? A form? ;; Fix-me: Quick object insert? (applet is depreceated) ;; Fix-me: Better meta insert? Quick meta? ;; Fix-me: Quick div! Better div completion with position: static, ;; relative, absolute and fixed - with some explanations. ;; Fix-me: Quick hr? ;; Fix-me: Import CSS? Export CSS? ;; Fix-me: Use nxhtml-js.el? ;; Fix-me: Scroll bar colors etc? See 1stPage. ;; body { ;; scrollbar-arrow-color: #FF6699; ;; scrollbar-3dlight-color: #00FF33; ;; scrollbar-highlight-color: #66FFFF; ;; scrollbar-face-color: #6699FF; ;; scrollbar-shadow-color: #6633CC; ;; scrollbar-darkshadow-color: #660099; ;; scrollbar-track-color: #CC6633; ;; } ;; Fix-me: More quick menus: http://www.cssplay.co.uk/menus/ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (provide 'nxhtml-mode) ;;; nxhtml-mode.el ends here