1 ;;; tidy-xhtml.el --- Interface to the HTML Tidy program
3 ;; Copyright (C) 2001, 2002, 2003, 2006, 2007 by Free Software
6 ;; Emacs Lisp Archive Entry
7 ;; Ancestors filename: tidy.el
8 ;; Author: Kahlil (Kal) HODGSON <dorge@tpg.com.au>
9 ;; Author: Lennart Borgman (lennart O borgman A gmail O com)
10 ;; Original X-URL: http://www.emacswiki.org/elisp/tidy.el
11 ;; Last-Updated: 2008-03-09T13:10:06+0100 Sun
12 (defconst tidy-xhtml:version "2.25")
13 ;; Keywords: languages
15 ;; This file is NOT part of GNU Emacs.
17 ;; This file is free software; you can redistribute it and/or modify
18 ;; it under the terms of the GNU General Public License as published by
19 ;; the Free Software Foundation; either version 2, or (at your option)
22 ;; This file is distributed in the hope that it will be useful,
23 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
24 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 ;; GNU General Public License for more details.
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with GNU Emacs; see the file COPYING. If not, write to
29 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
30 ;; Boston, MA 02111-1307, USA.
34 ;; Provides a simple interface to the HTML Tidy program -- a free
35 ;; utility that can fix common errors in your mark-up and clean up
36 ;; sloppy editing automatically. See
38 ;; <http://tidy.sourceforge.net/>
40 ;; for more details. This package provides the following functions:
46 ;; `tidy-parse-config-file',
47 ;; `tidy-save-settings',
48 ;; `tidy-describe-options',
49 ;; `tidy-show-xhtml-options',
50 ;; `tidy-set-xhtml-options',
52 ;; These can be invoked interactively (using M-x) or via the menu-bar.
53 ;; The function `tidy-buffer' sends the current buffer to HTML Tidy,
54 ;; replacing the existing contents with a "tidied" version. If
55 ;; `tidy-buffer' is given a prefix argument, tidy operates on the
56 ;; current region, ignoring mark-up outside <BODY>...</BODY> tags
57 ;; (useful for writhing cgi scripts in Pearl). Warnings and errors
58 ;; are presented in a compilation buffer to facilitate tracking down
59 ;; necessary changes (e.g. C-x ` is bound to `next-error').
61 ;; This package also provides menu-bar support for setting Tidy's many
62 ;; options, and includes support for Tidy configuration files. The
63 ;; function `tidy-parse-config-file' will synchronise options
64 ;; displayed in the menu-bar with the settings in `tidy-config-file'.
65 ;; This is normally called by the load-hook for your HTML editing mode
66 ;; (see installation instructions below). The function
67 ;; `tidy-save-settings' will save the current option settings to your
68 ;; `tidy-config-file'. Finally `tidy-describe-options' allows you to
69 ;; browse the documentation strings associated with each option.
75 ;; This package assumes you have and up-to-date HTML Tidy program
76 ;; installed on your system. See the URL above for instructions on
77 ;; how to do this. To set up this support package, first place the
78 ;; "tidy.el" file somewhere in your `load-path' and open it in Emacs.
79 ;; Byte-compile and load this package using the command
81 ;; M-x emacs-lisp-byte-compile-and-load <RET>
83 ;; Next customise the variables `tidy-config-file', `tidy-temp-dir'
84 ;; `tidy-shell-program', `tidy-menu-lock' and `tidy-menu-x-position'
86 ;; M-x customize-group <RET> tidy <RET>
88 ;; Now add the following autoloads to your ".emacs.el" file:
90 ;; (autoload 'tidy-buffer "tidy" "Run Tidy HTML parser on current buffer" t)
91 ;; (autoload 'tidy-parse-config-file "tidy" "Parse the `tidy-config-file'" t)
92 ;; (autoload 'tidy-save-settings "tidy" "Save settings to `tidy-config-file'" t)
93 ;; (autoload 'tidy-build-menu "tidy" "Install an options menu for HTML Tidy." t)
95 ;; If you use html-mode to edit HTML files then add something like
98 ;; (defun my-html-mode-hook () "Customize my html-mode."
99 ;; (tidy-build-menu html-mode-map)
100 ;; (local-set-key [(control c) (control c)] 'tidy-buffer)
101 ;; (setq sgml-validate-command "tidy"))
103 ;; (add-hook 'html-mode-hook 'my-html-mode-hook)
105 ;; This will set up a "tidy" menu in the menu bar and bind the key
106 ;; sequence "C-c C-c" to `tidy-buffer' in html-mode (normally bound to
107 ;; `validate-buffer').
109 ;; For other modes (like html-helper-mode) simple change the variables
110 ;; `html-mode-hook' and `html-mode-map' to whatever is appropriate e.g.
112 ;; (defun my-html-mode-hook () "Customize my html-helper-mode."
113 ;; (tidy-build-menu html-helper-mode-map)
114 ;; (local-set-key [(control c) (control c)] 'tidy-buffer)
115 ;; (setq sgml-validate-command "tidy"))
117 ;; (add-hook 'html-helper-mode-hook 'my-html-mode-hook)
119 ;; Finally, restart Emacs and open an HTML file to test-drive the tidy
120 ;; package. For people new to HTML tidy check that the option "markup"
121 ;; under the "Input/Output" sub menu is set. You can read the
122 ;; documentation on this option via the menu item "Describe Options".
128 ;; 0. Now compatible with CVS version of Tidy as at 22 May 2003
129 ;; 1. Improved menu support to facillitate incorporting new options
130 ;; 2. Menu lock option makes menu stick when toggling options.
131 ;; 3. Now runs on XEmacs!!
132 ;; 4. Uses error file rather than std-error to retrieve errors (this
133 ;; fixes some odd pop up behaviour)
134 ;; 5. minor bug fix (empty config files)
135 ;; 6. handle buffer modified query in error buffer better
136 ;; 7. make it impossible to mark the error buffer as modified
137 ;; 8. Added the variable `tidy-temp-directory'.
138 ;; 9. Bugfix in tidy-buffer: call find-file-noselect with NOWARN
139 ;; 10. Removes ^M on w32.
140 ;; 11. Changed defcustom types to 'file and 'directory.
141 ;; 12. Added `tidy-set-xhtml-options'.
142 ;; 13. Tried to handle encodings.
143 ;; 14. Added the function `tidy-region'.
144 ;; 15. Added ediff support.
145 ;; 16. Added `tidy-tree'.
146 ;; 17. Added `tidy-html-site'.
150 ;; 1. Automatically set "char-encoding" according to the buffer encoding
151 ;; 2. Should check value of HTML_TIDY environment variable.
156 ;; Requires a version of HTML Tidy that understands the "-f"
157 ;; "-config" "--show-body-only" command line options e.g. source-forge
160 ;; There may be a bug with setting doctypes. I don't use this feature
161 ;; yet and, well, don't really know how its supposed to work:-)
163 ;; Care with character encodings!!
168 ;; 2006-05-09: New features 10-17 above.
170 ;; 2006-05-24: Fixed some errors spotted by Andreas Roethler.
175 ;; This code was inspired by an Emacs "tip" suggested by Pete Gelbman.
177 ;; Thanks to Hans-Michael Stahl for comments regarding XEmacs
180 ;; Thanks to Thomas Baumann for bugfix's in `tidy-parse-config-file'
181 ;; and `tidy-buffer'.
183 ;; Thanks to Chris Lott for comments regarding installation and menu
186 ;; Thanks to Jeroen Baekelandt for noting a problem with ange-ftp and
187 ;; inspiring `tidy-temp-directory'.
191 ;;;;; Forward references (stuff which must come first)
193 (eval-when-compile (require 'cl))
194 (eval-when-compile (require 'ediff))
195 (eval-when-compile (require 'mumamo nil t))
196 (eval-when-compile (require 'ourcomments-util nil t))
198 (add-to-list 'load-path default-directory))
199 (eval-when-compile (require 'html-site nil t))
200 (require 'easymenu) ;; This makes menus so much easier!
201 (require 'compile) ;; To make the error buffer more sexy
202 (require 'cus-edit) ;; Just for face custom-button
205 ;; The following two are functions so that the same compiled code will
206 ;; work in both situations (time cost is negligible)
208 (defsubst tidy-xemacs-p ()
209 "Return t iff we are running XEmacs this session."
210 (not (null (string-match "^XEmacs.*" (emacs-version)))))
212 (defsubst tidy-windows-p ()
213 "Return t iff we are running on a Windows system."
214 (memq system-type '(emx win32 w32 mswindows ms-dos windows-nt)))
216 ;; function definitions
219 (defalias 'tidy-x-event-function 'event-function)
220 (defalias 'tidy-x-event-object 'event-object)
221 (defalias 'tidy-x-find-menu-item 'find-menu-item)
222 (defalias 'tidy-x-get-popup-menu-response 'get-popup-menu-response)
223 (defalias 'tidy-x-make-event 'make-event)
224 (defalias 'tidy-x-misc-user-event-p 'misc-user-event-p)
230 "Provides a simple interface to the HTML Tidy program -- a free
231 utility that can fix common errors in your mark-up and clean up
232 sloppy editing automatically. See
234 <http://tidy.sourceforge.net/>
236 for more details. This package provides the following functions:
239 `tidy-parse-config-file',
240 `tidy-save-settings', and
241 `tidy-describe-options',
243 These can be invoked interactively (using M-x) or via the menu-bar.
244 The function `tidy-buffer' sends the current buffer to HTML Tidy,
245 replacing the existing contents with a \"tidied\" version. If
246 `tidy-buffer' is given a prefix argument, tidy operates on the
247 current region, ignoring mark-up outside <BODY>...</BODY> tags
248 \(useful for writhing cgi scripts in Pearl). Warnings and errors
249 are presented in a compilation buffer to facilitate tracking down
250 necessary changes (e.g. C-x ` is bound to `next-error').
252 This package also provides menu-bar support for setting Tidy's many
253 options, and includes support for Tidy configuration files. The
254 function `tidy-parse-config-file' will synchronise options
255 displayed in the menu-bar with the settings in `tidy-config-file'.
256 This is normally called by the load-hook for your HTML editing mode
257 \(see installation instructions below). The function
258 `tidy-save-settings' will save the current option settings to your
259 `tidy-config-file'. Finally `tidy-describe-options' allows you to
260 browse the documentation strings associated with each option.
265 ;; (defcustom tidy-use-ediff nil
266 ;; "If non-nil call ediff in `tidy-buffer' instead of replacing."
270 (defvar tidy-warnings 0)
271 (defvar tidy-errors 0)
272 (defvar tidy-message nil)
274 ;;(defvar tidy-batch-buffer nil)
275 (defvar tidy-batch-last-file nil)
277 (defvar tidy-default-config-file "~/.tidyrc")
279 (defvar tidy-config-file-parsed nil)
281 (defcustom tidy-config-file tidy-default-config-file
282 "Path to your default tidy configuration file.
284 This is used by `tidy-parse-config-file' to synchronise Tidy's behaviour
285 inside Emacs with its behaviour outside, and by `tidy-save-settings' to
286 set your configuration file from within Emacs. If you never want this to
287 happen, set `tidy-config-file' to \"\"."
290 :set (lambda (symbol value)
291 (set-default symbol value)
292 (if (file-readable-p value)
293 ;; Just set the default values here:
294 ;;(tidy-parse-config-file)
295 ;; Just tell we need to parse:
296 (setq tidy-config-file-parsed nil)
297 (if (file-exists-p value)
298 (lwarn '(tidy-config-file)
299 :warning "Tidy config file not readable: %s" value)
300 (unless (string= value tidy-default-config-file)
301 (lwarn '(tidy-config-file)
302 :warning "Tidy config file not found: %s" value))))))
305 (defcustom tidy-shell-program "tidy"
308 :type '(choice (file :must-match t)
309 (string :tag "File name (searched for in path): "))
310 :set (lambda (symbol value)
311 (set-default symbol value)
312 (unless (string= value "tidy")
313 (or (file-executable-p value)
314 (executable-find value)
315 (lwarn '(tidy-shell-program)
316 :error "Tidy program not found: %s" value)))))
318 (defcustom tidy-temp-directory temporary-file-directory
319 "Directory where tidy places its temp files. The default is the
320 current directory which works fine unless you are operating on remote
321 files via `ange-ftp' and its ilk, in which case it will try to place
322 the temp files on the remote server (and will probably fail). If this
323 is the case try setting this variable to something like \"/tmp/\" or
327 :set-after '(temporary-file-directory))
329 (defcustom tidy-menu-lock t
330 " *Non-nil means menu is locked (i.e. doesn't pop down) when
331 selecting toggle and radio options.
333 See also `tidy-menu-x-position'."
337 (defcustom tidy-menu-x-position 211
338 "Specify menu position height in pixels.
340 This variable is used to set the horizontal position of the locked
341 menu, so don't forget to adjust it if menu position is not ok.
343 See also `tidy-menu-lock'."
347 ;;;;; Local Variables
349 (defvar tidy-debug nil
350 "If t then we rebuild everything on reload. Useful for debugging.")
352 ;;(eval-when-compile (setq tidy-debug t))
354 (defun tidy-toggle-debug ()
355 "Toggle value of tidy-debug."
357 (message "tidy-debug is %s" (setq tidy-debug (not tidy-debug))))
359 ;; (defun tidy-boolean-option-value (symbol)
360 ;; "Return t when the symbol's value is \"yes\"."
361 ;; (let ((name (symbol-name symbol)))
362 ;; (assert (string= "tidy-" (substring name 0 5)))
363 ;; (setq name (substring name 5))
364 ;; (let ((entry (assoc name tidy-options-alist)))
365 ;; (assert (string= "Boolean" (nth 2 entry)))))
366 ;; (when (symbol-value symbol)
367 ;; (string= (symbol-value symbol))))
369 (defvar tidy-options-alist nil
370 "An alist containing all valid tidy options.
371 Each element is a list of the form
372 (NAME, SUB-MENU, VALUE-TYPE, DEFAULT-VALUE, DOC-STRING).
373 This is used to automatically construct variables and a menu bar.
374 To add new or modify exiting options simply modify this list.")
376 ;; Fix-me: built the options list dynamically, point to
377 ;; http://tidy.sourceforge.net/docs/quickref.html for help
378 (defun tidy-build-options-alist ()
379 (when (and tidy-shell-program
380 (executable-find tidy-shell-program))
381 (let ((outbuf (get-buffer-create "* Tidy options *")))
382 (call-process tidy-shell-program
384 outbuf ;; Output here
385 nil ;; Do not display
387 (switch-to-buffer outbuf))))
389 (when (or (null tidy-options-alist) tidy-debug)
390 (setq tidy-options-alist
392 ("add-xml-decl" "Fix Markup" "Boolean" "no"
396 Example: y/n, yes/no, t/f, true/false, 1/0
398 This option specifies if Tidy should add the XML declaration when
399 outputting XML or XHTML. Note that if the input already includes an <?xml
400 ... ?> declaration then this option will be ignored.")
402 ;; ("add-xml-pi" "Fix Markup" "Boolean" "no"
406 ;; Example: y/n, yes/no, t/f, true/false, 1/0
408 ;; This option is the same as the add-xml-decl option.")
410 ("add-xml-space" "Fix Markup" "Boolean" "no"
414 Example: y/n, yes/no, t/f, true/false, 1/0
416 This option specifies if Tidy should add xml:space=\"preserve\" to elements
417 such as <PRE>, <STYLE> and <SCRIPT> when generating XML. This is needed if
418 the whitespace in such elements is to be parsed appropriately without
419 having access to the DTD.")
421 ("alt-text" "Fix Markup" "String" ""
426 This option specifies the default \"alt=\" text Tidy uses for <IMG>
427 attributes. This feature is dangerous as it suppresses further
428 accessibility warnings. You are responsible for making your documents
429 accessible to people who can not see the images!")
431 ("ascii-chars" "Fix Markup" "Boolean" "yes"
435 Example: y/n, yes/no, t/f, true/false, 1/0
437 Can be used to modify behavior of -c (--clean yes) option.
438 Defaults to \"yes\" when using -c. Set to \"no\" to prevent
439 converting &emdash;, ”, and other named character entities
440 to their ascii equivalents.")
442 ("assume-xml-procins" "Fix Markup" "Boolean" "no"
446 Example: y/n, yes/no, t/f, true/false, 1/0
448 This option specifies if Tidy should change the parsing of processing
449 instructions to require ?> as the terminator rather than >. This option is
450 automatically set if the input is in XML.")
452 ("bare" "Fix Markup" "Boolean" "no"
456 Example: y/n, yes/no, t/f, true/false, 1/0
458 This option specifies if Tidy should strip Microsoft specific HTML from
459 Word 2000 documents, and output spaces rather than non-breaking spaces
460 where they exist in the input.")
462 ("break-before-br" "Fix Markup" "Boolean" "no"
466 Example: y/n, yes/no, t/f, true/false, 1/0
468 This option specifies if Tidy should output a line break before each <BR>
471 ("char-encoding" "Encoding" "Encoding" "ascii"
475 Example: ascii, latin1, raw, utf8, iso2022, mac, win1252
477 This option specifies the character encoding Tidy uses for both the input
478 and output. Possible values are: ascii, latin1, raw, utf8, iso2022, mac,
479 win1252. For ascii, Tidy will accept Latin-1 (ISO-8859-1) character
480 values, but will use entities for all characters whose value > 127. For
481 raw, Tidy will output values above 127 without translating them into
482 entities. For latin1, characters above 255 will be written as
483 entities. For utf8, Tidy assumes that both input and output is encoded as
484 UTF-8. You can use iso2022 for files encoded using the ISO-2022 family of
485 encodings e.g. ISO-2022-JP. For mac and win1252, Tidy will accept vendor
486 specific character values, but will use entities for all characters whose
489 ("clean" "Fix Markup" "Boolean" "no"
493 Example: y/n, yes/no, t/f, true/false, 1/0
495 This option specifies if Tidy should strip out surplus presentational tags
496 and attributes replacing them by style rules and structural markup as
497 appropriate. It works well on the HTML saved by Microsoft Office products.")
499 ("doctype" "Fix Markup" "DocType" "auto"
503 Example: auto, omit, strict, loose, transitional, user specified fpi \(string\)
505 This option specifies the DOCTYPE declaration generated by Tidy. If set to
506 \"omit\" the output won't contain a DOCTYPE declaration. If set to \"auto\"
507 \(the default\) Tidy will use an educated guess based upon the contents of
508 the document. If set to \"strict\", Tidy will set the DOCTYPE to the strict
509 DTD. If set to \"loose\", the DOCTYPE is set to the loose \(transitional\)
510 DTD. Alternatively, you can supply a string for the formal public
511 identifier \(FPI\). For example:
513 doctype: \"-//ACME//DTD HTML 3.14159//EN\"
515 If you specify the FPI for an XHTML document, Tidy will set
516 the system identifier to the empty string. Tidy leaves the DOCTYPE for
517 generic XML documents unchanged.")
519 ("drop-empty-paras" "Fix Markup" "Boolean" "yes"
523 Example: y/n, yes/no, t/f, true/false, 1/0
525 This option specifies if Tidy should discard empty paragraphs. If set to
526 no, empty paragraphs are replaced by a pair of <BR> elements as HTML4
527 precludes empty paragraphs.")
529 ("drop-font-tags" "Fix Markup" "Boolean" "no"
533 Example: y/n, yes/no, t/f, true/false, 1/0
535 This option specifies if Tidy should discard <FONT> and <CENTER> tags
536 rather than creating the corresponding style rules, but only if the clean
537 option is also set to yes.")
539 ("drop-proprietary-attributes" "Fix Markup" "Boolean" "no"
543 Example: y/n, yes/no, t/f, true/false, 1/0
545 This option specifies if Tidy should strip out proprietary attributes,
546 such as MS data binding attributes.")
548 ("enclose-block-text" "Fix Markup" "Boolean" "no"
552 Example: y/n, yes/no, t/f, true/false, 1/0
554 This option specifies if Tidy should insert a <P> element to enclose any
555 text it finds in any element that allows mixed content for HTML
556 transitional but not HTML strict.")
558 ("enclose-text" "Fix Markup" "Boolean" "no"
562 Example: y/n, yes/no, t/f, true/false, 1/0
564 This option specifies if Tidy should enclose any text it finds in the body
565 element within a <P> element. This is useful when you want to take
566 existing HTML and use it with a style sheet.")
568 ;; ("error-file" "Omit" "String" "-none-"
573 ;; This option specifies the error file Tidy uses for errors and
574 ;; warnings. Normally errors and warnings are output to \"stderr\".
576 ;; This is option is ignored in Emacs.")
578 ("escape-cdata" "Fix Markup" "Boolean" "no"
582 Example: y/n, yes/no, t/f, true/false, 1/0
584 This option specifies if Tidy should convert <![CDATA[]]> sections to
587 ("fix-backslash" "Fix Markup" "Boolean" "yes"
591 Example: y/n, yes/no, t/f, true/false, 1/0
593 This option specifies if Tidy should replace backslash characters \"\\\" in
594 URLs by forward slashes \"/\".")
596 ("fix-bad-comments" "Fix Markup" "Boolean" "yes"
600 Example: y/n, yes/no, t/f, true/false, 1/0
602 This option specifies if Tidy should replace unexpected hyphens with \"=\"
603 characters when it comes across adjacent hyphens. The default is yes. This
604 option is provided for users of Cold Fusion which uses the comment syntax:
607 ("fix-uri" "Fix Markup" "Boolean" "yes"
611 Example: y/n, yes/no, t/f, true/false, 1/0
613 This option specifies if Tidy should check attribute values that carry
614 URIsfor illegal characters and if such are found, escape them as HTML 4
617 ("force-output" "Input/Output" "Boolean" "no"
621 Example: y/n, yes/no, t/f, true/false, 1/0
623 This option specifies if Tidy should produce output even if errors are
624 encountered. Use this option with care - if Tidy reports an error,
625 this means Tidy was not able to, or is not sure how to, fix the error,
626 so the resulting output may not reflect your intention.")
628 ;; ("gnu-emacs" "Omit" "Boolean" "no"
632 ;; Example: y/n, yes/no, t/f, true/false, 1/0
634 ;; This option specifies if Tidy should change the format for reporting
635 ;; errors and warnings to a format that is more easily parsed by GNU
638 ;; This option is automatically set in Emacs." )
640 ("hide-comments" "Fix Markup" "Boolean" "no"
644 Example: y/n, yes/no, t/f, true/false, 1/0
646 This option specifies if Tidy should print out comments.")
648 ("hide-endtags" "Fix Markup" "Boolean" "no"
652 Example: y/n, yes/no, t/f, true/false, 1/0
654 This option specifies if Tidy should omit optional end-tags when
655 generating the pretty printed markup. This option is ignored if you are
658 ("indent" "Indentation" "AutoBool" "no"
662 Example: auto, y/n, yes/no, t/f, true/false, 1/0
664 This option specifies if Tidy should indent block-level tags. If set to
665 \"auto\", this option causes Tidy to decide whether or not to indent the
666 content of tags such as TITLE, H1-H6, LI, TD, TD, or P depending on whether
667 or not the content includes a block-level element. You are advised to avoid
668 setting indent to yes as this can expose layout bugs in some browsers.")
670 ("indent-attributes" "Indentation" "Boolean" "no"
674 Example: y/n, yes/no, t/f, true/false, 1/0
676 This option specifies if Tidy should begin each attribute on a new line.")
678 ("indent-cdata" "Indent" "Boolean" "no"
682 Example: y/n, yes/no, t/f, true/false, 1/0
684 This option specifies if Tidy should indent <![CDATA[]]> sections.")
686 ("indent-spaces" "Indentation" "Integer" "2"
690 Example: 0, 1, 2, ...
692 This option specifies the number of spaces Tidy uses to indent content,
693 when indentation is enabled.")
695 ("input-encoding" "Encoding" "Encoding" "latin1"
699 Example: ascii, latin1, raw, utf8, iso2022, mac, win1252
701 This option specifies the character encoding Tidy uses for the input. See
702 char-encoding for more info.")
704 ("input-xml" "Input/Output" "Boolean" "no"
708 Example: y/n, yes/no, t/f, true/false, 1/0
710 This option specifies if Tidy should use the XML parser rather than the
711 error correcting HTML parser.")
713 ("join-classes" "Fix Markup" "Boolean" "no"
717 Example: y/n, yes/no, t/f, true/false, 1/0
719 This option specifies if Tidy should combine class names to generate a
720 single new class name, if multiple class assignments are detected on an
723 ("join-styles" "Fix Markup" "Boolean" "yes"
727 Example: y/n, yes/no, t/f, true/false, 1/0
729 This option specifies if Tidy should combine styles to generate a single
730 new style, if multiple style values are detected on an element.")
732 ("keep-time" "Preference" "Boolean" "no"
736 Example: y/n, yes/no, t/f, true/false, 1/0
738 This option specifies if Tidy should alter the last modified time for
739 files it writes back to. The default is no, which allows you to tidy files
740 without affecting which ones will be uploaded to a Web server when using a
741 tool such as 'SiteCopy'. Note that this feature may not work on some
744 ("literal-attributes" "Preference" "Boolean" "no"
748 Example: y/n, yes/no, t/f, true/false, 1/0
750 This option specifies if Tidy should ensure that whitespace characters
751 within attribute values are passed through unchanged.")
753 ("logical-emphasis" "Fix Markup" "Boolean" "no"
757 Example: y/n, yes/no, t/f, true/false, 1/0
759 This option specifies if Tidy should replace any occurrence of <I> by <EM>
760 and any occurrence of <B> by <STRONG>. In both cases, the attributes are
761 preserved unchanged. This option can be set independently of the clean and
762 drop-font-tags options.")
764 ("lower-literals" "Preference" "Boolean" "yes"
768 Example: y/n, yes/no, t/f, true/false, 1/0
770 This option specifies if Tidy should convert the value of an attribute
771 that takes a list of predefined values to lower case. This is required for
774 ("markup" "Input/Output" "Boolean" "yes"
778 Example: y/n, yes/no, t/f, true/false, 1/0
780 This option specifies if Tidy should generate a pretty printed version of
781 the markup. Note that Tidy won't generate a pretty printed version if it
782 finds significant errors (see force-output).")
784 ("ncr" "Preference" "Boolean" "yes"
788 Example: y/n, yes/no, t/f, true/false, 1/0
790 This option specifies if Tidy should allow numeric character references.")
792 ("newline" "Encoding" "Encoding" "LF"
796 Example: LF, CRLF, CR
798 Line ending style. \(Only used in batch operations here.\)")
800 ("new-blocklevel-tags" "Tags" "Tag names" ""
804 Example: tagX, tagY, ...
806 This option specifies new block-level tags. This option takes a space or
807 comma separated list of tag names. Unless you declare new tags, Tidy will
808 refuse to generate a tidied file if the input includes previously unknown
809 tags. Note you can't change the content model for elements such as
810 <TABLE>, <UL>, <OL> and <DL>.")
812 ("new-empty-tags" "Tags" "Tag names" ""
816 Example: tagX, tagY, ...
818 This option specifies new empty inline tags. This option takes a space or
819 comma separated list of tag names. Unless you declare new tags, Tidy will
820 refuse to generate a tidied file if the input includes previously unknown
821 tags. Remember to also declare empty tags as either inline or blocklevel.")
823 ("new-inline-tags" "Tags" "Tag names" ""
827 Example: tagX, tagY, ...
829 This option specifies new non-empty inline tags. This option takes a space
830 or comma separated list of tag names. Unless you declare new tags, Tidy
831 will refuse to generate a tidied file if the input includes previously
834 ("new-pre-tags" "Tags" "Tag names" ""
838 Example: tagX, tagY, ...
840 This option specifies new tags that are to be processed in exactly the
841 same way as HTML's <PRE> element. This option takes a space or comma
842 separated list of tag names. Unless you declare new tags, Tidy will refuse
843 to generate a tidied file if the input includes previously unknown
844 tags. Note you can not as yet add new CDATA elements (similar to
847 ("numeric-entities" "Preference" "Boolean" "no"
851 Example: y/n, yes/no, t/f, true/false, 1/0
853 This option specifies if Tidy should output entities other than the
854 built-in HTML entities \(&, <, > and "\) in the numeric
855 rather than the named entity form.")
857 ("output-bom" "Encoding" "AutoBool" "auto"
861 Example: auto, y/n, yes/no, t/f, true/false, 1/0
863 This option specifies if Tidy should write a Unicode Byte Order Mark
864 character (BOM; also known as Zero Width No-Break Space; has value of
865 U+FEFF) to the beginning of the output; only for UTF-8 and UTF-16 output
866 encodings. If set to \"auto\", this option causes Tidy to write a BOM to the
867 output only if a BOM was present at the beginning of the input. A BOM is
868 always written for XML/XHTML output using UTF-16 output encodings.")
870 ("output-encoding" "Encoding" "Encoding" "ascii"
874 Example: ascii, latin1, raw, utf8, iso2022, mac, win1252
876 This option specifies the character encoding Tidy uses for the output. See
877 char-encoding for more info. May only be different from input-encoding for
878 Latin encodings (ascii, latin1, mac, win1252).")
880 ("output-xhtml" "Input/Output" "Boolean" "no"
884 Example: y/n, yes/no, t/f, true/false, 1/0
886 This option specifies if Tidy should generate pretty printed output,
887 writing it as extensible HTML. This option causes Tidy to set the DOCTYPE
888 and default namespace as appropriate to XHTML. If a DOCTYPE or namespace
889 is given they will checked for consistency with the content of the
890 document. In the case of an inconsistency, the corrected values will
891 appear in the output. For XHTML, entities can be written as named or
892 numeric entities according to the setting of the \"numeric-entities\"
893 option. The original case of tags and attributes will be preserved,
894 regardless of other options.")
896 ("output-xml" "Input/Output" "Boolean" "no"
900 Example: y/n, yes/no, t/f, true/false, 1/0
902 This option specifies if Tidy should pretty print output, writing it as
903 well-formed XML. Any entities not defined in XML 1.0 will be written as
904 numeric entities to allow them to be parsed by a XML parser. The original
905 case of tags and attributes will be preserved, regardless of other
908 ("quiet" "Input/Output" "Boolean" "no"
912 Example: y/n, yes/no, t/f, true/false, 1/0
914 This option specifies if Tidy should output the summary of the numbers of
915 errors and warnings, or the welcome or informational messages.")
917 ("quote-ampersand" "Preference" "Boolean" "yes"
921 Example: y/n, yes/no, t/f, true/false, 1/0
923 This option specifies if Tidy should output unadorned & characters as
926 ("quote-marks" "Preference" "Boolean" "no"
930 Example: y/n, yes/no, t/f, true/false, 1/0
932 This option specifies if Tidy should output \" characters as " as is
933 preferred by some editing environments. The apostrophe character \' is
934 written out as ' since many web browsers don't yet support '.")
936 ("quote-nbsp" "Preference" "Boolean" "yes"
940 Example: y/n, yes/no, t/f, true/false, 1/0
942 This option specifies if Tidy should output non-breaking space characters
943 as entities, rather than as the Unicode character value 160 (decimal).")
945 ("raw" "Omit" "Boolean" "no"
949 Example: y/n, yes/no, t/f, true/false, 1/0 char-encoding
951 Currently not used, but this option would be the same as the
952 char-encoding: raw option.")
954 ("repeated-attributes" "Fix Markup" ("keep-first" "keep-last") "keep-last"
958 Example: keep-first, keep-last
960 This option specifies if Tidy should keep the first or last attribute, if
961 an attribute is repeated, e.g. has two align attributes.")
964 ("replace-color" "Fix Markup" "Boolean" "no"
968 Example: y/n, yes/no, t/f, true/false, 1/0
970 This option specifies if Tidy should replace numeric values in color
971 attributes by HTML/XHTML color names where defined, e.g. replace
972 \"#ffffff\" with \"white\"." )
974 ("slide-style" "Omit" "String"
978 split Currently not used.")
980 ;; ("show-body-only" "Omit" "Boolean" "no"
984 ;; Example: y/n, yes/no, t/f, true/false, 1/0
986 ;; This option specifies if Tidy should print only the contents of the body
987 ;; tag as an HTML fragment. Useful for incorporating existing whole pages as
988 ;; a portion of another page.
990 ;; Emacs overrides this option.")
992 ("show-errors" "Input/Output" "Integer" "6"
996 Example: 0, 1, 2, ...
998 This option specifies the number Tidy uses to determine if further errors
999 should be shown. If set to 0, then no errors are shown.")
1001 ("show-warnings" "Input/Output" "Boolean" "yes"
1005 Example: y/n, yes/no, t/f, true/false, 1/0
1007 This option specifies if Tidy should suppress warnings. This can be useful
1008 when a few errors are hidden in a flurry of warnings.")
1010 ("slide-style" "Omit" "String" ""
1015 Currently not used.")
1017 ("split" "Omit" "Boolean" "no"
1021 Example: y/n, yes/no, t/f, true/false, 1/0
1023 This option specifies if Tidy should create a sequence of slides from
1024 the input, splitting the markup prior to each successive <H2>. The
1025 slides are written to \"slide001.html\", \"slide002.html\" etc.
1027 There is currently no Emacs support for this option.")
1029 ("tab-size" "Indentation" "Integer" "4"
1033 Example: 0, 1, 2, ...
1035 This option specifies the number of columns that Tidy uses between
1036 successive tab stops. It is used to map tabs to spaces when reading the
1037 input. Tidy never outputs tabs.")
1039 ("tidy-mark" "Preference" "Boolean" "yes"
1043 Example: y/n, yes/no, t/f, true/false, 1/0
1045 This option specifies if Tidy should add a meta element to the document
1046 head to indicate that the document has been tidied. Tidy won't add a meta
1047 element if one is already present.")
1049 ("uppercase-attributes" "Preference" "Boolean" "no"
1053 Example: y/n, yes/no, t/f, true/false, 1/0
1055 This option specifies if Tidy should output attribute names in upper
1056 case. The default is no, which results in lower case attribute names,
1057 except for XML input, where the original case is preserved.")
1059 ("uppercase-tags" "Preference" "Boolean" "no"
1063 Example: y/n, yes/no, t/f, true/false, 1/0
1065 This option specifies if Tidy should output tag names in upper case. The
1066 default is no, which results in lower case tag names, except for XML
1067 input, where the original case is preserved.")
1069 ("word-2000" "Fix Markup" "Boolean" "no"
1073 Example: y/n, yes/no, t/f, true/false, 1/0
1075 This option specifies if Tidy should go to great pains to strip out all
1076 the surplus stuff Microsoft Word 2000 inserts when you save Word documents
1077 as \"Web pages\". Doesn't handle embedded images or VML.")
1079 ("wrap" "Line Wrapping" "Integer" "68"
1083 Example: 0, 1, 2, ...
1085 This option specifies the right margin Tidy uses for line wrapping. Tidy
1086 tries to wrap lines so that they do not exceed this length. Set wrap to
1087 zero if you want to disable line wrapping.")
1089 ("wrap-asp" "Line Wrapping" "Boolean" "yes"
1093 Example: y/n, yes/no, t/f, true/false, 1/0
1095 This option specifies if Tidy should line wrap text contained within ASP
1096 pseudo elements, which look like: <% ... %>.")
1098 ("wrap-attributes" "Line Wrapping" "Boolean" "no"
1102 Example: y/n, yes/no, t/f, true/false, 1/0
1104 This option specifies if Tidy should line wrap attribute values, for
1105 easier editing. This option can be set independently of
1106 wrap-script-literals.")
1108 ("wrap-jste" "Line Wrapping" "Boolean" "yes"
1112 Example: y/n, yes/no, t/f, true/false, 1/0
1114 This option specifies if Tidy should line wrap text contained within JSTE
1115 pseudo elements, which look like: <# ... #>.")
1117 ("wrap-php" "Line Wrapping" "Boolean" "yes"
1121 Example: y/n, yes/no, t/f, true/false, 1/0
1123 This option specifies if Tidy should line wrap text contained within PHP
1124 pseudo elements, which look like: <?php ... ?>.")
1126 ("wrap-script-literals" "Line Wrapping" "Boolean" "no"
1130 Example: y/n, yes/no, t/f, true/false, 1/0
1132 This option specifies if Tidy should line wrap string literals that appear
1133 in script attributes. Tidy wraps long script string literals by inserting
1134 a backslash character before the line break.")
1136 ("wrap-sections" "Line Wrapping" "Boolean" "yes"
1140 Example: y/n, yes/no, t/f, true/false, 1/0
1142 This option specifies if Tidy should line wrap text contained within
1143 <![... ]> section tags.")
1145 ;; ("write-back" "Omit" "Boolean" "no"
1149 ;; Example: y/n, yes/no, t/f, true/false, 1/0
1151 ;; This option specifies if Tidy should write back the tidied markup to
1152 ;; the same file it read from. You are advised to keep copies of
1153 ;; important files before tidying them, as on rare occasions the result
1154 ;; may not be what you expect.
1156 ;; This option is ignored by Emacs.")
1160 ;;;;; Create a variable for each option in `tidy-options-alist'"
1162 ;; these variables are made buffer local so that different buffers can
1163 ;; use a different set of options
1165 (let ((options-alist tidy-options-alist)
1166 option name symbol docstring)
1168 (while (setq option (car options-alist))
1169 (setq name (nth 0 option)
1170 docstring (nth 4 option)
1171 symbol (intern (concat "tidy-" name)))
1172 ;; create the variable on the fly
1173 (put symbol 'variable-documentation docstring)
1174 (make-variable-buffer-local symbol)
1175 (set symbol nil) ;;default)
1176 (setq options-alist (cdr options-alist))
1181 ;;;;; Quick options setting
1183 (defvar tidy-xhtml-values
1185 (add-xml-decl "yes")
1186 (add-xml-space "no")
1189 (fix-backslash "yes")
1190 (fix-bad-comments "yes")
1193 (indent-cdata "yes")
1195 (join-classes "yes")
1197 (lower-literals "yes")
1199 (output-xhtml "yes")
1201 (quote-ampersand "yes")
1204 (uppercase-attributes "no")
1205 (uppercase-tags "no")))
1207 (defun tidy-xhtml-options-ok ()
1209 (dolist (optval tidy-xhtml-values)
1210 (let* ((opt (car optval))
1212 (nam (symbol-name opt))
1213 (ent (assoc nam tidy-options-alist))
1215 (sym (intern (concat "tidy-" nam))))
1216 (when (equal val def)
1218 (unless (equal val (symbol-value sym))
1222 (defun tidy-show-xhtml-options ()
1223 "List the settings set by `tidy-set-xhtml-options'."
1225 (with-output-to-temp-buffer (help-buffer)
1226 (with-current-buffer (help-buffer)
1227 (help-setup-xref (list #'tidy-show-xhtml-settings) (interactive-p))
1228 (let ((inhibit-read-only t)
1231 (insert "Values that will be set by `tidy-set-xhtml-options'. ")
1233 (put-text-property 0 (length s)
1234 'face '(:foreground "green")
1236 (insert s " indicates that the local value in the current buffer")
1237 (insert " is the value that would be set, ")
1239 (put-text-property 0 (length s)
1240 'face '(:foreground "red")
1242 (insert s " indicates it is not.\n\n")
1243 (fill-region point (point))
1244 (dolist (optval tidy-xhtml-values)
1245 (let* ((opt (car optval))
1247 (nam (symbol-name opt))
1248 (ent (assoc nam tidy-options-alist))
1250 (cur (symbol-value (intern (concat "tidy-" nam))))
1251 (show (copy-seq val))
1253 (unless cur (setq cur def))
1254 (put-text-property 0 (length show)
1257 '(:foreground "green")
1258 'face '(:foreground "red"))
1260 (insert (format "%25s => %s\n" opt show))))))
1261 (with-no-warnings (print-help-return-message))))
1263 (defun tidy-set-xhtml-options (&optional only-current-buffer)
1264 "Set option necessary to convert to XHTML.
1265 To get a list of this settings use `tidy-show-xhtml-options'.
1267 Note that the option variables are buffer local. The default
1268 variable values are always set. If ONLY-CURRENT-BUFFER is nil set
1269 the buffer local variables in all buffers."
1271 (not (y-or-n-p "Set XHTML options in all buffers? "))))
1272 (let ((buffers (if (not only-current-buffer)
1274 (list (current-buffer)))))
1275 (dolist (buffer buffers)
1276 (when (buffer-live-p buffer)
1277 (with-current-buffer buffer
1278 (dolist (optval tidy-xhtml-values)
1279 (let* ((opt (car optval))
1281 (nam (symbol-name opt))
1282 (ent (assoc nam tidy-options-alist))
1284 (symbol (intern (concat "tidy-" nam))))
1285 (when (equal val def)
1287 (set-default symbol val) ;; The least overhead I think
1288 (unless (equal val (symbol-value symbol))
1289 (set symbol val)))))))))
1292 ;;;;; Menu Lock (adapted from printing.el)
1297 (or (boundp 'current-menubar)
1298 (defvar current-menubar nil))
1299 (or (fboundp 'tidy-menu-position)
1300 (defun tidy-menu-position () ""))
1301 (or (fboundp 'tidy-menu-lock)
1302 (defun tidy-menu-lock (entry state path) ""))
1303 (or (fboundp 'tidy-menu-lookup)
1304 (defun tidy-menu-lookup (path) ""))
1307 ;; always define these
1308 (defvar tidy-menu nil "Menu used by tidy.")
1309 (defvar tidy-menu-position nil)
1310 (defvar tidy-menu-state nil)
1315 (defun tidy-menu-position ()
1319 'x tidy-menu-x-position
1324 (defun tidy-menu-lock (entry state path)
1325 (when (and (not (interactive-p)) tidy-menu-lock)
1326 (or (and tidy-menu-position (eq state tidy-menu-state))
1327 (setq tidy-menu-position (tidy-menu-position)
1328 tidy-menu-state state))
1329 (let* ((menu (tidy-menu-lookup path))
1330 (result (tidy-x-get-popup-menu-response menu tidy-menu-position)))
1331 (and (tidy-x-misc-user-event-p result)
1332 (funcall (tidy-x-event-function result)
1333 (tidy-x-event-object result))))
1334 (setq tidy-menu-position nil)))
1337 (defun tidy-menu-lookup (path)
1338 (car (tidy-x-find-menu-item current-menubar (cons "Tidy" path)))))
1342 (defun tidy-menu-position ()
1344 (list (list tidy-menu-x-position '-5)
1345 (selected-frame)))) ; frame
1348 ;; (defun tidy-menu-lock-old (entry state path)
1349 ;; (when (and (not (interactive-p)) tidy-menu-lock)
1350 ;; (or (and tidy-menu-position (eq state tidy-menu-state))
1351 ;; (setq tidy-menu-position (tidy-menu-position )
1352 ;; tidy-menu-state state))
1353 ;; (let* ((menu (tidy-menu-lookup path))
1354 ;; (result (x-popup-menu tidy-menu-position menu)))
1356 ;; (let ((command (lookup-key menu (vconcat result))))
1357 ;; (if (fboundp command)
1358 ;; (funcall command)
1359 ;; (eval command)))))
1360 ;; (setq tidy-menu-position nil)))
1361 (defun tidy-menu-lock (entry state path)
1362 (when (and (not (interactive-p)) tidy-menu-lock)
1363 (or (and tidy-menu-position (eq state tidy-menu-state))
1364 (setq tidy-menu-position (tidy-menu-position )
1365 tidy-menu-state state))
1366 ;;(popup-menu tidy-menu tidy-menu-position)))
1367 (run-with-idle-timer 1 nil 'popup-menu tidy-menu tidy-menu-position)))
1370 (defun tidy-menu-lookup (dummy)
1371 (lookup-key (current-local-map) [menu-bar Tidy])))
1374 ;;;;; Define classes of menu items
1376 (defun tidy-set (var-sym value mess entry state &optional path)
1377 "Set the value of the symbol VAR-SYM to VALUE giving a message
1378 derived from VALUE and MESS. Pass on menu data to `tidy-menu-lock'."
1380 (message "%s is %s" mess value)
1381 (tidy-menu-lock entry state path))
1383 (defun tidy-boolean-entry (symbol name type default menu)
1384 "Returns a menu entry that allows us to toggle the value of SYMBOL.
1385 SYMBOL refers to the option called NAME which has default value
1386 DEFAULT. TYPE should always have the value \"Boolean\". MENU refers
1387 to the sub-menu that this item belongs to and POSITION its position in
1389 (cond ((equal default "no")
1391 (list 'tidy-set (list 'quote symbol)
1392 (list 'if symbol 'nil "yes")
1398 :selected (list 'if symbol 't 'nil))))
1400 ((equal default "yes")
1401 (list (vector name (list 'tidy-set (list 'quote symbol)
1402 (list 'if symbol 'nil "no")
1408 :selected (list 'if symbol 'nil 't))))))
1410 (defun tidy-list-entry (symbol name type default menu)
1411 "Returns a menu entry that allows us to set via a radio button the
1412 value of SYMBOL. SYMBOL refers to the option called NAME which has
1413 default value DEFAULT. TYPE should be a list of the possible
1414 values. MENU refers to the sub-menu that this item belongs to and
1415 POSITION its position in that list."
1416 (let (value element)
1417 (while (setq value (car type))
1418 (if (equal value default)
1423 (concat name " is \"" value "\"")
1424 (list 'tidy-set (list 'quote symbol)
1425 (list 'if symbol 'nil value)
1431 :selected (list 'if symbol 'nil 't)
1437 (concat name " is \"" value "\"")
1439 (list 'tidy-set (list 'quote symbol)
1440 (list 'if symbol 'nil value)
1448 'if (list 'string-equal symbol value)
1451 (setq type (cdr type)))
1454 (defun tidy-set-string (symbol name default)
1455 "Set the value of SYMBOL identified by name to VALUE,
1456 unless VALUE equals DEFAULT, in which case we set it to nil."
1458 (let* ((last-value (symbol-value symbol))
1461 (read-string (format "Set %s to: " name)
1462 (or last-value default) nil) ;; no default arg
1463 (read-string (format "Set %s to: " name)
1464 (or last-value default) nil default))))
1465 (set symbol (if (equal new-value default) nil new-value))))
1467 (defun tidy-set-integer (symbol name default)
1468 "Set the value of SYMBOL identified by name to VALUE,
1469 unless VALUE = DEFAULT, in which case we set it to nil."
1471 (let* ((last-value (symbol-value symbol))
1472 ;; careful to interpret the string as a number
1476 (read-string (format "Set %s to: " name)
1477 (or last-value default) nil)
1478 (read-string (format "Set %s to: " name)
1479 (or last-value default) nil default)
1481 (set symbol (if (= new-value (string-to-number default)) nil
1482 (number-to-string new-value)))))
1485 (defun tidy-string-entry (symbol name type default menu)
1486 "Returns a menu entry that allows us to set the value of SYMBOL.
1487 SYMBOL refers to the option called NAME which has default value
1488 DEFAULT. TYPE should always be one of \"String\" \"Tags\", or
1489 \"DocType\". MENU and POSITION are not used in this case."
1491 (list (vector (concat "set " name)
1492 (list 'tidy-set-string
1493 (list 'quote symbol)
1496 (defun tidy-integer-entry (symbol name type default menu)
1497 "Returns a menu entry that allows us to set the value of SYMBOL.
1498 SYMBOL refers to the option called NAME which has default value
1499 DEFAULT. TYPE should always have the value \"Integer\". MENU and
1500 POSITION are not used in this case. "
1501 (list (vector (concat "set " name)
1502 (list 'tidy-set-integer
1503 (list 'quote symbol)
1506 (defun tidy-exe-found ()
1507 (when tidy-shell-program
1508 ;;(file-executable-p (car (split-string tidy-shell-program)))))
1509 (or (file-executable-p tidy-shell-program)
1510 (executable-find tidy-shell-program))))
1513 (defvar tidy-top-menu nil
1514 "The first part of the menu.")
1515 (when (or (null tidy-top-menu) tidy-debug)
1518 ["Tidy Buffer" tidy-buffer
1519 :active (tidy-exe-found)]
1521 ;; ["Tidy Region" tidy-region
1522 ;; :active (and (mark)
1523 ;; (tidy-exe-found))
1524 ;; :keys "C-u \\[tidy-buffer]"]
1526 ["Tidy Directory Tree" tidy-tree
1527 :active (tidy-exe-found)]
1529 ["Tidy Site" tidy-tree
1530 :active (and (featurep 'html-site)
1533 "----------------------------------------------"
1535 ["Customize Tidy" (customize-group-other-window 'tidy)]
1537 ;; ["Use Ediff" (lambda () (interactive)
1538 ;; (setq tidy-use-ediff (not tidy-use-ediff)))
1540 ;; :selected tidy-use-ediff
1543 ;; ["Load Settings" tidy-parse-config-file
1544 ;; :active (and tidy-config-file (file-exists-p tidy-config-file))]
1546 ;; ["Load Settings All Buffers" (lambda () (interactive)
1547 ;; (tidy-parse-config-file t))
1548 ;; :active (and tidy-config-file (file-readable-p tidy-config-file))]
1550 ["Save Settings" tidy-save-settings
1551 :active (and tidy-config-file (file-readable-p tidy-config-file))]
1553 "----------------------------------------------"
1557 (defvar tidy-newline-menu
1559 ["LF" (tidy-set 'tidy-newline
1565 :selected (if (null tidy-newline) t nil)]
1567 ["CRLF" (tidy-set 'tidy-newline
1573 :selected (if (equal tidy-newline "CRLF") t nil)]
1575 ["CR" (tidy-set 'tidy-newline
1581 :selected (if (equal tidy-newline "CRLF") t nil)]
1584 (defvar tidy-doctype-menu nil "The second to last sub-menu.")
1585 (when (or (null tidy-doctype-menu) tidy-debug)
1586 (setq tidy-doctype-menu
1587 '("Set doctype" ;; ==>
1589 ["auto" (tidy-set 'tidy-doctype
1595 :selected (if (null tidy-doctype) t nil)]
1597 ["omit" (tidy-set 'tidy-doctype
1603 :selected (if (equal tidy-doctype "omit") t nil)]
1605 ["strict" (tidy-set 'tidy-doctype
1611 :selected (if (equal tidy-doctype "strict") t nil)]
1613 ["loose" (tidy-set 'tidy-doctype
1619 :selected (if (equal tidy-doctype "loose") t nil)]
1621 ["transitional" (tidy-set 'tidy-doctype
1627 :selected (if (equal tidy-doctype "transitional") t nil)]
1629 ["fpi" (null nil) ;; stub function
1631 :selected (if (or (null tidy-doctype)
1632 (equal tidy-doctype "omit")
1633 (equal tidy-doctype "strict")
1634 (equal tidy-doctype "loose"))
1637 ["reset fpi" (tidy-set-string 'tidy-doctype "doctype" "" "")]
1640 (defconst tidy-emacs-encoding-lbl "Use Emacs' encoding")
1642 (defun tidy-create-encoding-menu (label encoding-what msg-what)
1644 (vector tidy-emacs-encoding-lbl (list 'tidy-set (list 'quote encoding-what)
1645 tidy-emacs-encoding-lbl ;(list 'tidy-get-buffer-encoding)
1650 :selected (list 'if (list 'equal encoding-what tidy-emacs-encoding-lbl) t nil)
1653 "----------------------------------------------"
1655 (vector "ascii" (list 'tidy-set (list 'quote encoding-what)
1661 :selected (list 'if (list 'null encoding-what) t nil) ;; default
1664 (vector "raw" (list 'tidy-set (list 'quote encoding-what)
1670 :selected (list 'if (list 'equal encoding-what "raw") t nil))
1672 (vector "latin1" (list 'tidy-set (list 'quote encoding-what)
1678 :selected (list 'if (list 'equal encoding-what "latin1") t nil))
1680 (vector "utf8" (list 'tidy-set (list 'quote encoding-what)
1686 :selected (list 'if (list 'equal encoding-what "utf8") t nil))
1688 (vector "iso2022" (list 'tidy-set (list 'quote encoding-what)
1694 :selected (list 'if (list 'equal encoding-what "iso2022") t nil))
1696 (vector "mac" (list 'tidy-set (list 'quote encoding-what)
1702 :selected (list 'if (list 'equal encoding-what "mac") t nil))
1704 (vector "win1252" (list 'tidy-set (list 'quote encoding-what)
1710 :selected (list 'if (list 'equal encoding-what "win1252") t nil))
1713 ;; (defvar tidy-char-encoding-menu nil "The last sub-menu.")
1714 ;; (when (or (null tidy-char-encoding-menu) tidy-debug)
1715 ;; (setq tidy-char-encoding-menu
1716 ;; (tidy-create-encoding-menu
1717 ;; "Set char-encoding" 'tidy-char-encoding "char-encoding")))
1718 ;; (defvar tidy-input-encoding-menu nil "The last sub-menu.")
1719 ;; (when (or (null tidy-input-encoding-menu) tidy-debug)
1720 ;; (setq tidy-input-encoding-menu
1721 ;; (tidy-create-encoding-menu
1722 ;; "Set input-encoding" 'tidy-input-encoding "input-encoding")))
1723 (defvar tidy-output-encoding-menu nil "The last sub-menu.")
1724 (when (or (null tidy-output-encoding-menu) tidy-debug)
1725 (setq tidy-output-encoding-menu
1726 (tidy-create-encoding-menu
1727 "Set output-encoding" 'tidy-output-encoding "output-encoding")))
1729 ;;;;; Create a menu item for each option that has a valid sub-menu
1732 (when (or (null tidy-menu) tidy-debug)
1733 (let ((options-alist tidy-options-alist)
1735 ;; sub menus are divided into two parts with list type options
1736 ;; coming first, followed by the rest
1738 markup-menu-bool markup-menu-set
1739 line-wrap-menu-bool line-wrap-menu-set
1740 preference-menu-bool preference-menu-set
1741 indent-menu-bool indent-menu-set
1742 io-menu-bool io-menu-set
1743 tags-menu-bool tags-menu-set
1745 name sub-menu type default symbol entry entry-function option)
1747 (while (setq option (car options-alist))
1748 (setq name (nth 0 option)
1749 sub-menu (nth 1 option)
1751 default (nth 3 option)
1752 symbol (intern (concat "tidy-" name))
1755 (cond ((equal type "Boolean")
1756 (setq entry-function 'tidy-boolean-entry))
1758 ((equal type "AutoBool")
1759 (setq entry-function 'tidy-list-entry)
1760 (setq type '("auto" "yes" "no")))
1762 ((equal type "DocType")
1763 (setq entry '())) ;; handled below
1765 ((equal type "Tag names")
1766 (setq entry-function 'tidy-string-entry))
1768 ((equal type "String")
1769 (setq entry-function 'tidy-string-entry))
1771 ((equal type "Integer")
1772 (setq entry-function 'tidy-integer-entry))
1774 ((equal type "Encoding")
1775 (setq entry '()));; handled below
1778 (setq entry-function 'tidy-list-entry))
1780 (error (concat "Tidy: unhandled value type " type " for " name))))
1782 (cond ((equal sub-menu "Fix Markup")
1783 (setq entry (funcall
1791 (if (or (equal type "Boolean") (equal type "AutoBool") (listp type))
1792 (setq markup-menu-bool (append markup-menu-bool entry))
1793 (setq markup-menu-set (append markup-menu-set entry))))
1795 ((equal sub-menu "Indentation")
1796 (setq entry (funcall
1804 (if (or (equal type "Boolean") (equal type "AutoBool") (listp type))
1805 (setq indent-menu-bool (append indent-menu-bool entry))
1806 (setq indent-menu-set (append indent-menu-set entry))))
1808 ((equal sub-menu "Line Wrapping")
1809 (setq entry (funcall
1817 (if (or (equal type "Boolean") (equal type "AutoBool") (listp type))
1818 (setq line-wrap-menu-bool (append line-wrap-menu-bool entry))
1819 (setq line-wrap-menu-set (append line-wrap-menu-set entry))))
1821 ((equal sub-menu "Input/Output")
1822 (setq entry (funcall
1830 (if (or (equal type "Boolean") (equal type "AutoBool") (listp type))
1831 (setq io-menu-bool (append io-menu-bool entry))
1832 (setq io-menu-set (append io-menu-set entry))))
1834 ((equal sub-menu "Preference")
1835 (setq entry (funcall
1843 (if (or (equal type "Boolean") (equal type "AutoBool") (listp type))
1844 (setq preference-menu-bool (append preference-menu-bool entry))
1845 (setq preference-menu-set (append preference-menu-set entry))))
1847 ((equal sub-menu "Tags")
1848 (setq entry (funcall
1856 (if (or (equal type "Boolean") (equal type "AutoBool"))
1857 (setq tags-menu-bool (append tags-menu-bool entry))
1858 (setq tags-menu-set (append tags-menu-set entry))))
1859 (t)) ;; we simple omit all other menus
1861 (setq options-alist (cdr options-alist)))
1863 (setq tidy-menu (append
1866 (list "Quick Options Settings"
1867 (vector "Set Options for XHTML"
1868 'tidy-set-xhtml-options
1870 :selected '(tidy-xhtml-options-ok)
1872 (vector "Show Options for XHTML"
1873 'tidy-show-xhtml-options
1876 (list (append (list "Advanced")
1879 ;; "----------------------------------------------"
1881 ;; ["Menu Lock" (tidy-set 'tidy-menu-lock
1882 ;; (if tidy-menu-lock nil t)
1887 ;; :selected (if tidy-menu-lock t nil)
1889 ;; (vector "Menu Lock"
1892 ;; :selected '(if tidy-menu-lock t nil)
1894 (list (vector "Menu Lock"
1895 '(tidy-set 'tidy-menu-lock
1896 (if tidy-menu-lock nil t)
1902 :selected '(if tidy-menu-lock t nil)
1904 (list (list "-------"))
1906 (list (append (list "Fix Markup")
1909 (list (append (list "Line Wrapping")
1911 line-wrap-menu-set))
1912 (list (append (list "Preference")
1913 preference-menu-bool
1914 preference-menu-set))
1915 (list (append (list "Indentation")
1918 (list (append (list "Input/Output")
1921 (list (append (list "Tags")
1924 (list tidy-doctype-menu)
1925 (list tidy-output-encoding-menu)
1926 (list tidy-newline-menu)
1928 '(["Describe Options" tidy-describe-options t])
1929 (list (list "-------"))
1932 "Open Tidy home page in your web browser."
1934 (browse-url "http://tidy.sourceforge.net/"))
1940 (defvar tidy-menu-symbol nil)
1941 ;;(tidy-build-menu (&optional map)
1943 (defun tidy-build-menu (&optional map)
1944 "Set up the tidy menu in MAP.
1945 Used to set up a Tidy menu in your favourite mode."
1946 (interactive) ;; for debugging
1947 (unless tidy-menu-symbol
1948 (unless tidy-config-file-parsed
1949 (tidy-parse-config-file)
1950 (setq tidy-config-file-parsed t))
1951 ;;(or map (setq map (current-local-map)))
1952 (easy-menu-remove tidy-menu)
1953 (easy-menu-define tidy-menu-symbol map "Menu for Tidy" tidy-menu)
1954 (setq tidy-menu-symbol (delete "Tidy" tidy-menu-symbol))
1955 (easy-menu-add tidy-menu map))
1958 ;;;;; Option description support
1960 ;; quiet FSF Emacs and XEmacs compilers
1962 (progn (or (fboundp 'event-point) (defun event-point (dummy) ""))
1963 (or (fboundp 'posn-point) (defun posn-point (dummy) ""))
1964 (or (fboundp 'event-start) (defun event-start (dummy) ""))))
1966 (defun tidy-describe-this-option-mouse (click)
1968 (let ((p (if (tidy-xemacs-p)
1970 (posn-point (event-start click)))))
1971 (tidy-describe-this-option p)))
1973 (defun tidy-describe-this-option (&optional point)
1974 "Describe variable associated with the text at point."
1975 (interactive (list (point)))
1977 (let* ((variable (get-text-property
1981 buffer) ;; reuse the help buffer
1983 (with-output-to-temp-buffer (help-buffer)
1984 (help-setup-xref (list #'tidy-describe-this-option point) (interactive-p))
1985 (with-current-buffer (help-buffer)
1986 (setq value (symbol-value variable))
1987 (insert (substring (symbol-name variable) 5) ;; clip the `tidy-' prefix
1989 (if value (insert value) (insert "set to the default value"))
1990 (insert "\n\n" (documentation-property variable 'variable-documentation))
1991 (local-set-key [(q)] 'tidy-quit-describe-options)
1992 (with-no-warnings (print-help-return-message)))))))
1994 (defun tidy-quit-describe-options ()
1995 "Rid thyself of any display associated with Tidy's options."
1997 (bury-buffer (get-buffer "*tidy-options*"))
1998 (delete-windows-on (get-buffer "*tidy-options*"))
1999 (bury-buffer (get-buffer "*Help*"))
2000 (delete-windows-on (get-buffer "*Help*")))
2002 ;; nicked this from cal-desk-calendar.el:-)
2003 (defun tidy-current-line ()
2004 "Get the current line number (in the buffer) of point."
2010 (1+ (count-lines 1 (point))))))
2012 (defun tidy-goto-line (line)
2015 (goto-char (point-min))
2016 (forward-line (1- line))))
2018 (defun tidy-describe-options ()
2019 "Interactively access documentation strings for `tidy-' variables."
2021 (let ((buffer (get-buffer "*tidy-options*")))
2022 (if buffer (pop-to-buffer buffer)
2023 ;; else build it from scratch
2024 (setq buffer (get-buffer-create "*tidy-options*"))
2029 (option-alist tidy-options-alist)
2030 (column2a (+ (length "drop-proprietary-attributes") 3))
2031 (column2b (/ (window-width) 3))
2032 (column2 (if (> column2a column2b) column2a column2b))
2033 (column3 (* 2 column2))
2036 (two-third-length 0))
2040 (setq buffer-read-only nil)
2041 (delete-region (point-min) (point-max)) ;; empty the buffer
2043 ;; set up local bindings
2045 (local-set-key [(button2)] 'tidy-describe-this-option-mouse)
2046 (local-set-key [(mouse-2)] 'tidy-describe-this-option-mouse))
2048 (local-set-key "\r" 'tidy-describe-this-option)
2049 (local-set-key [(q)] 'tidy-quit-describe-options)
2051 (insert "Press RET over option to see its description. "
2052 "Type \"q\" to quit." "\n\n")
2054 (setq start-line (tidy-current-line))
2055 (setq third-length (1+ (/ (length option-alist) 3) ))
2056 (setq two-third-length (1- (* 2 third-length)))
2058 (while (setq name (car (car-safe option-alist)))
2059 (setq option-alist (cdr option-alist))
2060 (setq count (+ count 1))
2063 ((< count third-length) ;; 0 <= count < third-length
2064 (setq start (point))
2068 ((< count two-third-length) ;; third-length <= count < two-third-length
2069 (if (= count third-length)
2070 (tidy-goto-line start-line)
2073 (setq start (point))
2074 (indent-to-column column2)
2076 (put-text-property start end 'mouse-face 'default)
2077 (setq start (point))
2080 (t ;; two-third-length <= count < length
2081 (if (= count two-third-length)
2082 (tidy-goto-line start-line)
2085 (setq start (point))
2086 (indent-to-column column3)
2088 (put-text-property start end 'mouse-face 'default)
2089 (setq start (point))
2091 (setq end (point))))
2093 ;; make the strings funky
2094 (put-text-property start end 'mouse-face 'highlight)
2095 (put-text-property start end 'tidy-variable (intern (concat "tidy-" name)))
2097 (setq buffer-read-only t)
2098 ;;(beginning-of-buffer)
2099 (goto-char (point-min))
2100 (pop-to-buffer buffer)
2103 ;;;;; Configuration file support
2105 (defun tidy-parse-config-file (&optional all-buffers)
2106 "Parse `tidy-config-file' and set variables accordingly.
2107 If `tidy-config-file' is nil or \"\" do nothing. If the file does
2108 not exist just give a message.
2110 Note that the option variables are buffer local. The default
2111 variable values are always set. If ALL-BUFFERS is non-nil set the
2112 buffer local variables in all buffers."
2114 (y-or-n-p "Set Tidy config file values in all buffers? ")))
2115 (tidy-set-xhtml-options all-buffers)
2116 (when (and tidy-config-file
2117 (not (string= "" tidy-config-file)))
2118 (if (not (file-exists-p tidy-config-file))
2119 (unless (string= tidy-config-file tidy-default-config-file)
2120 (message "Could not find Tidy config file \"%s\"." tidy-config-file))
2121 (message "Parsing config file...")
2122 (let ((html-buffer (current-buffer))
2123 (config-buffer (find-file-noselect tidy-config-file t))
2125 (with-current-buffer config-buffer
2126 (goto-char (point-min)) ;; unnecessary but pedantic
2128 ;; delete all comments
2129 (while (re-search-forward "//.*\n" nil t)
2130 (replace-match "" nil nil))
2132 (goto-char (point-min))
2133 (while (re-search-forward "\\([a-z,-]+\\):\\s-*\\(.*\\)\\s-*" nil t)
2135 ;; Thanks to Thomas Baumann for this bugfix
2136 (let ((variable (concat "tidy-" (match-string 1)))
2137 (value (match-string 2)))
2138 ;;(set-default (intern variable value))
2139 (set-default (intern variable) value)
2140 (setq config-variables
2141 (cons (cons variable value) config-variables))
2142 (with-current-buffer html-buffer
2143 (set (intern variable) value))
2146 (set-buffer-modified-p nil) ;; don't save changes
2147 (kill-buffer config-buffer))
2149 (dolist (buffer (buffer-list))
2150 (when (buffer-live-p buffer)
2151 (with-current-buffer buffer
2152 (dolist (optval config-variables)
2153 (let* ((opt (car optval))
2156 (set sym val))))))))
2157 (message "Parsing config file...done")
2160 (defun tidy-save-settings (&optional config-file)
2161 "Query saving the current settings to your `tidy-config-file'.
2162 The local values in the current buffer will be saved."
2164 (or config-file (setq config-file tidy-config-file))
2167 ;; should check for locks!
2168 (if (or (not (interactive-p))
2169 (y-or-n-p "Save settings to your tidy configuration file? "))
2171 (let ((buffer (find-file-noselect config-file t))
2172 (option-alist tidy-options-alist)
2173 (outer-buffer (current-buffer))
2174 option name symbol value)
2175 (with-current-buffer buffer
2176 (delete-region (point-min) (point-max)) ;; clear the buffer
2178 ;; need this line so that config file is always non empty
2179 (insert "// HTML Tidy configuration file \n")
2180 (while (setq option (car option-alist))
2181 (setq option-alist (cdr option-alist))
2182 (setq name (nth 0 option)
2183 symbol (intern (concat "tidy-" name)))
2184 (with-current-buffer outer-buffer
2185 (setq value (symbol-value symbol)))
2186 (when (string= value tidy-emacs-encoding-lbl)
2187 (setq value (tidy-get-buffer-encoding)))
2188 (when value ;; nil iff default
2189 (insert (car option) ": " value "\n")))
2192 ;;(basic-save-buffer)
2193 (kill-buffer buffer)
2197 ;;;;; Main user function
2199 (eval-when-compile (defvar tidy-markup nil ""))
2201 (defun tidy-set-buffer-unmodified (dummy1 dummy2 dumm3)
2202 "Used to prevent error buffer form being marked as modified."
2203 (set-buffer-modified-p nil))
2205 ;; See http://www.mhonarc.org/MHonArc/doc/resources/charsetaliases.html
2206 (defconst tidy-encodings-mime-charset-list
2208 ;; ("raw") ;; Same as ascii??
2209 ("ascii" . "us-ascii")
2210 ("latin0" . "iso-8859-15")
2211 ("latin1" . "iso-8859-1")
2212 ("iso2022" . "iso-2022-jp") ;; Correct? There are several iso-2022-..
2214 ("mac" . "macintosh")
2215 ("win1252" . "windows-1252")
2216 ("ibm858" . "cp850")
2217 ("utf16le" . "utf-16-le")
2218 ("utf16be" . "utf-16-be")
2219 ("utf16" . "utf-16")
2221 ("shiftjis" . "shift_jis")
2223 "Encoding names used by Tidy and Emacs.
2224 First column is Tidy's name, second Emacs' name."
2227 (defun tidy-get-buffer-encoding ()
2228 "Get Tidy's name for value of `buffer-file-coding-system'."
2229 (tidy-get-tidy-encoding buffer-file-coding-system))
2231 (defun tidy-get-tidy-encoding (emacs-coding-system)
2232 (let ((encoding (rassoc
2234 (coding-system-get emacs-coding-system 'mime-charset))
2235 tidy-encodings-mime-charset-list)))
2237 (setq encoding (car encoding))
2238 (setq encoding "raw"))
2241 (defun tidy-temp-config-file ()
2242 (expand-file-name "temp-tidy-config"
2243 tidy-temp-directory))
2245 (defconst tidy-output-buf-name "Tidy (X)HTML Output")
2247 (defvar tidy-tidied-buffer nil)
2248 (make-variable-buffer-local 'tidy-tidied-buffer)
2249 (put 'tidy-tidied-buffer 'permanent-local t)
2251 (defun tidy-check-is-tidied (orig-buf tidy-buf)
2252 (with-current-buffer tidy-buf
2253 (unless tidy-tidied-buffer
2254 (error "%s is not a tidy output buffer" tidy-buf))
2255 (unless (eq orig-buf tidy-tidied-buffer)
2256 (error "Buffer does not contain tidied %s" orig-buf))))
2258 (defconst tidy-control-buffer-name "Tidy Control Buffer")
2260 (defvar tidy-output-encoding) ;; dyn var
2262 (defun tidy-buffer ()
2263 "Run the HTML Tidy program on the current buffer.
2264 Show the errors in a buffer with buttons to:
2266 - show the original buffer
2267 - show the tidied output
2268 - copy tidied to original
2271 This buffer also contains any error and warning messages and they
2272 link to the original source code.
2274 If the buffer to tidy contains a fictive XHTML validation header
2275 \(see `nxhtml-validation-header-mode') then the corresponding
2276 header is added before running tidy. This header is removed again
2277 after tidying, together with additions tidy might have done at
2278 the end of the buffer.
2280 You may tidy part of the buffer, either by narrowing the buffer
2281 or by selecting a region and having it visibly marked (`cua-mode'
2282 etc). A fictive XHTML validation header will apply as
2283 above. However if there is no such header then when you tidy part
2284 of the buffer still a hopefully suitable header is added before
2286 ;; Fix-me: copy back parts outside visible region
2288 (message "starting tidy-buffer")
2289 (let* ((is-narrowed (buffer-narrowed-p))
2290 (validation-header (when (boundp 'rngalt-validation-header)
2291 (let ((header (nth 2 rngalt-validation-header)))
2292 (when header (concat header "\n")))))
2293 (region-restricted (and mark-active
2295 (or (< (point-min) (region-beginning))
2296 (< (region-end) (point-max)))))
2297 (partial (or validation-header
2300 (start (if region-restricted (region-beginning) (point-min)))
2301 (end (if region-restricted (region-end) (point-max)))
2302 (region-header (when region-restricted
2303 (when (< (point-min) (region-beginning))
2304 (buffer-substring-no-properties
2305 (point-min) (region-beginning)))))
2306 (region-footer (when region-restricted
2307 (when (< (region-end) (point-max))
2308 (buffer-substring-no-properties
2309 (region-end) (point-max)))))
2310 (tidy-beg-mark "<!-- TIDY BEGIN MARK 142505535 -->\n")
2311 (tidy-end-mark "<!-- TIDY END MARK 143345187 -->")
2312 ;;(whole-file t) ;(and (= start 1) (= end (1+ (buffer-size)))))
2313 (filename buffer-file-name)
2314 ;;(orig-dir (file-name-directory filename))
2315 (orig-buffer (current-buffer))
2316 (work-buffer (get-buffer-create "* Tidy Temporary Work Buffer *"))
2317 (line-header-offset nil)
2319 ;; Gasp! We have to use temp files here because the command
2320 ;; line would likely get too long!
2322 (error-buf-name tidy-control-buffer-name)
2324 (error-file (expand-file-name error-buf-name
2325 tidy-temp-directory))
2327 (error-buffer (get-buffer-create error-buf-name))
2329 (output-buffer (get-buffer-create tidy-output-buf-name))
2331 (config-file (tidy-temp-config-file))
2333 ;;(eol (coding-system-eol-type buffer-file-coding-system))
2334 ;;(encoding (coding-system-get buffer-file-coding-system 'mime-charset))
2339 ;;(use-ediff tidy-use-ediff)
2344 ;; (when (and use-ediff
2345 ;; (not tidy-show-warnings)) ;; default "yes" hence inverted logic
2346 ;; (setq use-ediff (y-or-n-p "Warning can not be shown when using ediff. Still use ediff? ")))
2347 (unless buffer-file-name
2348 (error "Can't tidy buffer with no file name"))
2350 (when (buffer-modified-p orig-buffer)
2351 (error "Can't tidy buffer because it is modified"))
2353 (with-current-buffer error-buffer
2354 (setq buffer-read-only nil)
2356 (setq tidy-tidied-buffer orig-buffer))
2359 ;; (message "coding-system: %s, %s, %s"
2360 ;; (find-operation-coding-system
2361 ;; 'call-process-region start end command)
2362 ;; coding-system-for-write
2363 ;; buffer-file-coding-system)
2364 (let* ((coding-system-for-write buffer-file-coding-system)
2365 (tidy-input-encoding (tidy-get-tidy-encoding coding-system-for-write)))
2367 (let ((output-mode (if (not (featurep 'mumamo))
2369 (if (and (boundp 'mumamo-multi-major-mode)
2370 mumamo-multi-major-mode)
2371 mumamo-multi-major-mode
2373 (with-current-buffer output-buffer
2375 ;;(when (and (fboundp 'mumamo-mode) mumamo-mode) (setq want-mumamo t) (mumamo-mode 0))
2376 (funcall output-mode)
2377 (set (make-local-variable 'coding-system-for-read) coding-system-for-write)))
2379 (let ((tidy-output-encoding tidy-output-encoding))
2380 (unless tidy-output-encoding
2381 (setq tidy-output-encoding tidy-input-encoding))
2382 ;;(message "tidy-input-enc=%s, tidy-output-enc=%s" tidy-input-encoding tidy-output-encoding)
2383 (tidy-save-settings config-file)
2386 ;; Tidy does not replace the xml declaration so it must be removed:
2387 ;(setq tidy-add-xml-decl "no")
2388 (let (;(orig-min (point-min)) (orig-max (point-max))
2390 ;; (when region-restricted
2391 ;; ;; We have a visible region
2392 ;; (setq orig-min (region-beginning))
2393 ;; (setq orig-max (region-end)))
2394 (with-current-buffer work-buffer
2396 (when validation-header
2397 (insert validation-header))
2399 ;; Have to insert things to make tidy insert at correctt
2400 ;; position. A bit of guessing here to keep it simple.
2401 (let ((p "\n<p>TIDY</p>\n")
2403 (he "\n<head><title></title></head>\n")
2405 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
2406 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"
2407 "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
2408 "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n")))
2409 (goto-char (point-min))
2410 (if (re-search-forward "<body[^>]*>" nil t)
2412 (if (search-forward "</head>" nil t)
2414 (if (re-search-forward "<html[^>]*>" nil t)
2416 (insert ht he b p))))
2417 (goto-char (point-max))
2418 (insert "\n" tidy-beg-mark)))
2419 (setq line-header-offset (line-number-at-pos))
2420 (insert-buffer-substring orig-buffer start end) ;orig-min orig-max)
2421 (when partial (insert "\n" tidy-end-mark "\n"))
2425 (point-min) (point-max)
2430 "-config" config-file
2431 "--error-file" error-file
2433 ;;(if (not whole-file) "--show-body-only" "--show-body-only")
2434 ;;(if (not whole-file) "yes" "no")
2435 "--show-body-only" "no"
2437 "--gnu-emacs-file" (file-name-nondirectory filename)
2439 (default-directory (file-name-directory filename))
2441 (apply 'call-process-region args)))
2445 ;; Since XEmacs can't grab the std error stream we use an error file
2446 ;;(setq error-buffer (find-file-noselect error-file t))
2447 (with-current-buffer error-buffer
2448 (setq tidy-tidied-buffer orig-buffer)
2449 (insert-file-contents error-file)
2450 ;; Change the line numbers if a header was inserted
2451 (when line-header-offset
2452 (goto-char (point-min))
2453 (while (re-search-forward ":\\([0-9]+\\):[0-9]+" nil t)
2454 (let ((line (1+ (- (string-to-number (match-string-no-properties 1))
2455 line-header-offset))))
2456 (replace-match (number-to-string line) nil nil nil 1))))
2459 ;; avoid leaving these guys lying around
2460 (if (file-exists-p error-file) (delete-file error-file))
2461 ;;(if (file-exists-p config-file) (delete-file config-file))
2463 ;; scan the buffer for error strings
2464 (with-current-buffer error-buffer
2465 ;;(local-set-key [tab] 'tidy-errbuf-forward)
2466 (goto-char (point-min))
2468 (make-local-variable 'widget-button-face)
2469 (setq widget-button-face custom-button)
2470 (set (make-local-variable 'widget-push-button-prefix) "")
2471 (set (make-local-variable 'widget-push-button-suffix) "")
2472 (set (make-local-variable 'widget-link-prefix) "")
2473 (set (make-local-variable 'widget-link-suffix) "")
2474 (widget-create 'push-button
2475 :tag " Show Source "
2476 :keymap (make-sparse-keymap)
2477 :arg-orig orig-buffer
2478 :action (lambda (widget &optional event)
2479 (let ((orig-buf (widget-get widget :arg-orig))
2480 (curr-win (selected-window)))
2481 (switch-to-buffer-other-window orig-buf)
2482 (select-window curr-win))))
2484 (widget-create 'push-button
2485 :tag " Show Tidied "
2486 :keymap (make-sparse-keymap)
2487 :arg-tidy output-buffer
2488 :arg-orig orig-buffer
2489 :action (lambda (widget &optional event)
2490 (let ((tidy-buf (widget-get widget :arg-tidy))
2491 (orig-buf (widget-get widget :arg-orig))
2492 (curr-win (selected-window)))
2493 (tidy-check-is-tidied orig-buf tidy-buf)
2494 (switch-to-buffer-other-window tidy-buf)
2495 (select-window curr-win))))
2499 (widget-create 'push-button
2501 :keymap (make-sparse-keymap)
2502 :arg-tidy output-buffer
2503 :arg-orig orig-buffer
2504 :action (lambda (widget &optional event)
2505 (message "Copying ...")
2506 (let* ((orig-buf (widget-get widget :arg-orig))
2507 (tidy-buf (widget-get widget :arg-tidy))
2510 (with-current-buffer orig-buf
2512 (buffer-substring-no-properties (point-min) (point-max)))))
2515 (with-current-buffer tidy-buf
2517 (buffer-substring-no-properties (point-min) (point-max)))))
2519 (tidy-check-is-tidied orig-buf tidy-buf)
2520 (kill-buffer (current-buffer))
2521 (kill-buffer tidy-buf)
2522 (if (string= orig-buf-str tidy-buf-str)
2523 (message "Original buffer's and tidied buffer's contents are equal")
2524 (with-current-buffer orig-buf
2526 (insert tidy-buf-str)
2527 (goto-char (point-min))
2528 (delete-window (selected-window))
2529 (switch-to-buffer orig-buf)
2530 (message "Copied to %s" orig-buf))))))
2532 (widget-create 'push-button
2534 :keymap (make-sparse-keymap)
2535 :arg-tidy output-buffer
2536 :arg-orig orig-buffer
2537 :action (lambda (widget &optional event)
2539 (let ((orig-buf (widget-get widget :arg-orig))
2540 (tidy-buf (widget-get widget :arg-tidy))
2541 ;; Fix-me: How should ediff-actual-options be set?
2542 (old-ediff-actual-diff-options (default-value 'ediff-actual-diff-options))
2543 (new-ediff-actual-diff-options " -a -b -w "))
2544 (with-current-buffer orig-buf (setq ediff-actual-diff-options " -a -b -w "))
2545 (with-current-buffer tidy-buf (setq ediff-actual-diff-options " -a -b -w "))
2546 (tidy-check-is-tidied orig-buf tidy-buf)
2547 (set-default 'ediff-actual-diff-options new-ediff-actual-diff-options)
2548 (tidy-ediff-buffers orig-buf tidy-buf)
2549 (set-default 'ediff-actual-diff-options old-ediff-actual-diff-options)
2554 (when (re-search-forward (concat
2555 "\\([0-9]+\\) warnings?, "
2556 "\\([0-9]+\\) errors? were found!")
2558 (setq tidy-warnings (string-to-number (match-string 1)))
2559 (setq tidy-errors (string-to-number (match-string 2)))
2560 (setq tidy-message (match-string 0)))
2562 (goto-char (point-min))
2563 ;;(while (re-search-forward "stdin:" nil t) (replace-match (concat filename ":")))
2564 (wab-compilation-mode)
2565 (set-buffer-modified-p nil)
2566 (goto-char (point-min))
2567 ;; Fix-me: How should this be run? Some hook for compilation I
2568 ;; guess, but what is the name of it?
2573 (when (buffer-live-p output-buffer)
2574 ;; Catch segmentation violations
2575 ;; Sometimes get this when editing files from Macs
2576 ;; See the function at the bottom of the file
2577 (with-current-buffer output-buffer
2578 (goto-char (point-min))
2579 (let ((case-fold-search t))
2580 (if (looking-at "Segmentation") ;; might work with XEmacs
2581 (setq seg-error t))))
2582 ;; Fix-me: add parts outside region
2584 (with-current-buffer output-buffer
2585 (goto-char (point-min))
2586 (when (search-forward tidy-beg-mark nil t)
2587 (delete-region (point-min) (point)))
2588 (when region-header (insert region-header))
2589 (when (search-forward tidy-end-mark nil t)
2590 (backward-char (length tidy-end-mark))
2591 (delete-region (point) (point-max)))
2592 (when region-footer (insert region-footer))))
2595 (unless (or (> tidy-errors 0) seg-error)
2596 ;; Do not know if the window stuff is needed?
2597 (let* ((window (get-buffer-window (current-buffer)))
2598 (top (window-start window)))
2600 (unless tidy-markup ;; default is "yes" hence inverted logic
2601 (when (eq system-type 'windows-nt)
2602 (tidy-remove-ctrl-m output-buffer))
2603 (with-current-buffer output-buffer
2604 (setq tidy-tidied-buffer orig-buffer)
2605 (delete-trailing-whitespace)
2606 (indent-region (point-min) (point-max))
2607 (goto-char (point-min))))
2609 ;; Try not to move the window too much when we tidy the whole buffer
2610 (set-window-start window top)))
2612 (switch-to-buffer-other-window error-buffer)
2615 (message (concat "Tidy: Segmentation violation!!!"
2616 " Check your character encoding."))
2617 (message "%s" tidy-message))))
2619 (defun tidy-after-ediff ()
2620 (run-with-idle-timer 0 nil 'remove-hook 'ediff-quit-hook 'tidy-after-ediff)
2621 ;;(lwarn 't :warning "cb=%s, %s, %s" (current-buffer) ediff-buffer-A ediff-buffer-B)
2622 (let ((sw (selected-window))
2624 (select-window ediff-window-B)
2625 (setq nw (split-window))
2626 (set-window-buffer nw (get-buffer-create tidy-control-buffer-name))
2630 (defun tidy-ediff-buffers (buffer-a buffer-b &optional startup-hooks job-name)
2631 (add-hook 'ediff-quit-hook 'tidy-after-ediff)
2632 (ediff-buffers buffer-a buffer-b startup-hooks job-name))
2634 ;; http://sf.net/tracker/index.php?func=detail&aid=1425219&group_id=27659&atid=390963
2635 (defun tidy-remove-ctrl-m (buffer)
2636 (with-current-buffer buffer
2637 (goto-char (point-min))
2638 (let ((control-m (char-to-string ?\r)))
2639 (while (search-forward control-m nil t)
2640 (replace-match "" nil t)))))
2642 (defvar tidy-html-files-re "\.x?html?$")
2643 (defun tidy-is-html-file (filename)
2644 (string-match tidy-html-files-re filename))
2646 (defun tidy-contains (dir file)
2647 (let ((d (file-name-as-directory dir)))
2648 (when (< (length d) (length file))
2649 (string= d (substring file 0 (length d))))))
2653 (defvar tidy-tree-files nil)
2654 (defun tidy-tree-next ()
2655 (let ((next-file (car tidy-tree-files))
2657 ;;(tidy-use-ediff nil)
2660 ;;(setq tidy-batch-buffer nil)
2662 (setq tidy-tree-files (cdr tidy-tree-files))
2663 (if (file-directory-p next-file)
2665 (tidy-batch next-file)))))
2667 (defun tidy-tree (root)
2668 "Run Tidy on all files in the directory ROOT.
2669 The files are first opened in Emacs and then `tidy-buffer' is
2671 (interactive "DDirectory tree: ")
2672 (unless (file-directory-p root)
2673 (error "tidy-tree called with non-directory arg: %s" root))
2674 (setq tidy-tree-files (html-site-get-sub-files root html-site-files-re))
2675 (dolist (f tidy-tree-files)
2676 (let ((b (get-file-buffer f)))
2678 (buffer-modified-p b))
2680 (y-or-n-p (format "Modified buffer %s must be saved. Save it and continue? "
2682 (error "Modified buffers prevent run with Tidy"))
2683 (with-current-buffer b
2684 (basic-save-buffer)))))
2685 (setq tidy-batch-last-file nil)
2688 (defun tidy-html-site ()
2689 "Tidy the whole tree in the current site."
2690 ;; Fix-me: document html-site better.
2692 (unless (featurep 'html-site)
2693 (error "html-site is not loaded"))
2694 (html-site-current-ensure-site-defined)
2695 (tidy-tree (html-site-current-site-dir)))
2697 (defun tidy-batch-sentinel (process event)
2698 (with-current-buffer (process-buffer process)
2699 (let ((inhibit-read-only t))
2700 (insert "PROCESS-EVENT: " event "\n")))
2701 (when (eq (process-status process) 'exit)
2702 (when tidy-batch-last-file
2703 (let ((b (get-file-buffer tidy-batch-last-file)))
2705 (with-current-buffer b
2708 (let ((old (buffer-substring-no-properties (point-min) (point-max)))
2709 (new (with-temp-buffer
2710 ;;(insert-file tidy-batch-last-file)
2711 (insert-file-contents tidy-batch-last-file)
2712 (buffer-substring-no-properties (point-min) (point-max))))
2714 (unless (string= old new)
2719 (defun tidy-batch-output-filter (proc string)
2720 (display-buffer (process-buffer proc))
2721 (with-current-buffer (process-buffer proc)
2722 (let ((moving (= (point) (process-mark proc))))
2724 ;; Insert the text, advancing the process marker.
2725 (goto-char (process-mark proc))
2726 (let ((inhibit-read-only t))
2727 ;; http://sf.net/tracker/index.php?func=detail&aid=1425219&group_id=27659&atid=390963
2728 (setq string (replace-regexp-in-string "\r$" "" string))
2730 (set-marker (process-mark proc) (point)))
2731 (if moving (goto-char (process-mark proc))))))
2733 (defun tidy-batch (filename)
2734 (interactive (list buffer-file-name)) ;; For testing
2735 (setq tidy-batch-last-file filename)
2736 (let* (;;(filename buffer-file-name)
2737 (config-file (tidy-temp-config-file))
2738 (command (list tidy-shell-program
2739 ;; load configuration file first so that
2740 ;; options are overridden by command line
2742 "-config" config-file
2743 ;;"--error-file" error-file
2744 "--write-back" "yes"
2745 ;;"--show-body-only" "no"
2747 "--gnu-emacs-file" filename
2750 (procbuf (noshell-procbuf-setup "subprocess for Tidy"))
2751 (start (with-current-buffer procbuf (point)))
2753 ;; This does not work at the moment (2006-05-16):
2754 (coding-system-for-read 'undecided-dos)
2755 (coding-system-for-write 'undecided-dos)
2757 ;;(setq tidy-batch-buffer procbuf)
2758 (tidy-save-settings config-file)
2760 (setq proc (apply 'noshell-procbuf-run procbuf command))
2761 (with-current-buffer procbuf
2762 (set-process-sentinel proc 'tidy-batch-sentinel)
2763 ;;(set-process-coding-system 'dos)
2764 (set-process-filter proc 'tidy-batch-output-filter)
2765 (let ((win (get-buffer-window procbuf)))
2767 (set-window-point win (point-max))
2775 ;; (with-temp-buffer
2776 ;; (tidy-parse-config-file))
2778 (defun wab-compilation-button-at (pos)
2782 (setq ret (eq 'compilation-button-map
2783 (get-char-property pos 'keymap)))
2787 (defun wab-click (&optional event)
2788 "Do the action that is tighed to the button."
2789 (interactive (list last-input-event))
2790 (if event (posn-set-point (event-end event)))
2791 (let ((button (get-char-property (point) 'button))
2795 (compile-goto-error)
2801 ;;(widget-apply-action button event)
2802 (widget-apply-action button)
2805 (defvar wab-errors-supress
2807 "Moved past last error"
2808 "No buttons or fields found"
2809 "Moved back before first error"
2812 (defun wab-fb-errmsg (err)
2813 (let ((s (error-message-string err)))
2814 (unless (member s wab-errors-supress)
2816 (signal (car err) (cdr err)))))
2818 (defun wab-fb-helper (forward function check-at args)
2820 (len (1+ (- (point-max) (point-min))))
2824 (apply function args)
2825 (when (funcall check-at (point))
2826 (setq ret (point))))
2827 (error (wab-fb-errmsg err)))
2830 (goto-char (point-min))
2831 (goto-char (point-max)))
2834 (apply function args)
2835 (when (funcall check-at (point))
2836 (setq ret (point))))
2837 (error (message "%s" (error-message-string err)))))
2839 (when (and ret (= ret old))
2841 (setq ret (+ ret len))
2842 (setq ret (- ret len))))
2843 ;;(message "function=%s, ret=%s" function ret)
2845 (defvar wab-button-list
2847 (compilation-previous-error (1) compilation-next-error (1) wab-compilation-button-at)
2848 (backward-button (1) forward-button (1) button-at)
2849 (widget-backward (1) widget-forward (1) widget-at)
2851 (defun wab-fb (forward)
2852 ;;(message "==================")
2853 (let* ((pos-list (mapcar (lambda (p)
2854 (let ((prev-fun (nth 0 p))
2855 (prev-arg (nth 1 p))
2856 (next-fun (nth 2 p))
2857 (next-arg (nth 3 p))
2858 (test-fun (nth 4 p)))
2860 (wab-fb-helper t next-fun test-fun next-arg)
2861 (wab-fb-helper nil prev-fun test-fun prev-arg))))
2863 (len (1+ (- (point-max) (point-min))))
2864 (defpos (if forward (* 2 len) (- len)))
2867 ;;(message "pos-list=%s" pos-list)
2868 (mapc (lambda (p) (when (and p
2879 (if (= newpos defpos)
2881 (setq newpos (mod newpos len)))
2882 (goto-char newpos)))
2884 (defun wab-backward ()
2885 "Go to next button or error link."
2889 (defun wab-forward ()
2890 "Go to previous button or error link."
2894 (define-compilation-mode wab-compilation-mode "WAB Compilation"
2895 "Mode for tidy control buffer."
2897 (define-key wab-compilation-mode-map [tab] 'wab-forward)
2898 (define-key wab-compilation-mode-map [(shift tab)] 'wab-backward)
2899 (define-key wab-compilation-mode-map [backtab] 'wab-backward)
2900 (define-key wab-compilation-mode-map "\r" 'wab-click)
2901 (define-key wab-compilation-mode-map [mouse-1] 'wab-click)
2902 (define-key wab-compilation-mode-map [mouse-2] 'wab-click)
2904 (defvar tidy-menu-mode-map
2905 (let ((map (make-sparse-keymap)))
2906 ;; This did not work:
2907 ;;(define-key map [menu-bar tidy-menu] (list 'menu-item "Tidy" '(lambda () (interactive) tidy-menu-symbol)))
2910 (define-minor-mode tidy-menu-mode
2911 "This mode just adds Tidy to the menu bar."
2915 (when tidy-menu-mode
2916 (define-key tidy-menu-mode-map [menu-bar tidy-menu]
2917 (list 'menu-item "Tidy" tidy-menu-symbol))))
2919 (provide 'tidy-xhtml)
2921 ;;; tidy-xhtml.el ends here