;; -*- emacs-lisp -*-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; $Id: sgml.el,v 1.23 2006/03/06 12:07:06 ole Exp $
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;_+ SGML, HTML and XML setup
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(add-to-list 'load-path (expand-file-name "xslt-process/lisp" emacs-packages-dir))
(require 'sgml-mode)
;; (require 'psgml)

(defvar psgml-etc-dir (expand-file-name "psgml/" emacs-etc-dir)
  "My local directory for sgml help files")

(defvar psgml-dtd-dir (expand-file-name "dtd" psgml-etc-dir)
  "My local directory for sgml help files")

(setq sgml-system-path '("." psgml-dtd-dir "/usr/share/sgml" "/usr/share/xemacs/xemacs-packages/etc/psgml-dtds")
      sgml-catalog-files '("CATALOG" "catalog" "~/emacs/etc/dtd/CATALOG" "~/emacs/etc/psgml/dtd/CATALOG" "/usr/share/sgml/CATALOG" "/usr/share/xemacs/xemacs-packages/etc/psgml-dtds/CATALOG")
      sgml-ecat-files '("ECAT" "~/.xemacs/etc/psgml/dtd/ECAT" "/usr/share/sgml/ECAT" "/usr/share/xemacs/xemacs-packages/etc/psgml-dtds/ECAT")
      sgml-ignore-undefined-elements t
      sgml-indent-step 2
      sgml-live-element-indicator nil
      sgml-validate-command "nsgmls -s -m /usr/share/xemacs/xemacs-packages/etc/psgml-dtds/CATALOG %s %s"
    )  

(setq sgml-custom-dtd 
      '(("XHTML" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\" >" )
        ("HTML 4.01" "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">")
        ("HTML 4.0" <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">)
        ("HTML" "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4//EN\">")
        )
)

(defun my-sgml-mode-hook ()
  (xslt-process-mode)
  (make-variable-buffer-local 'adaptive-fill-regexp)
  (setq tab-width 2
        indent-tabs-mode nil
        sgml-indent-step 2
        sgml-indent-data t
        adaptive-fill-regexp nil
        ispell-skip-sgml t
        )
  (auto-fill-mode t)
  ; increase fillcolumn
  (set-fill-column 90)
)

(add-hook 'sgml-mode-hook 'my-sgml-mode-hook) 

(add-to-list 'file-coding-system-alist '("\\.html\\'" iso-8859-1 iso-8859-1))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;_+ Sgml Mode Keys
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun sgml-indent-complete ()
  "A special sgml indent/complete function"
  (interactive)
  (if (mark-or-region-active)
      (indent-region (mark) (point) nil)
    (if (save-excursion (skip-chars-backward " \t") (not (bolp)))
        (sgml-complete)
      (indent-for-tab-command))))

(defvar ss-sgml-tags-visible t "boolean flag if tags are visible" )
(defvar ss-sgml-attributes-visible t "boolean flag if attributes are visible" )

(defun ss-sgml-toggle-tags ()
  "hide tags or make them visible"
  (interactive)
  (if ss-sgml-tags-visible
      (progn (sgml-hide-tags)
             (setq ss-sgml-tags-visible nil))
    (progn (sgml-show-tags)
           (setq ss-sgml-tags-visible t))))

(defun ss-sgml-toggle-attributes ()
  "hide tags or make them visible"
  (interactive)
  (if ss-sgml-attributes-visible
      (progn (sgml-hide-attributes)
             (setq ss-sgml-attributes-visible nil))
    (progn (sgml-show-attributes)
           (setq ss-sgml-attributes-visible t))))

(define-key sgml-mode-map [(meta o)] 'sgml-insert-element)
(define-key sgml-mode-map [(meta a)] 'sgml-insert-attribute)
(define-key sgml-mode-map [(meta e)] 'sgml-insert-end-tag)
(define-key sgml-mode-map [(meta p)] 'sgml-tag-region)
(define-key sgml-mode-map [(tab)] 'all-indent-complete)
(define-key sgml-mode-map [(control c)(tab)] 'sgml-indent-complete)
(define-key sgml-mode-map [(return)] 'reindent-then-newline-and-indent)

(define-key sgml-mode-map [(f5)] 'ss-sgml-toggle-tags)
(define-key sgml-mode-map [(f6)] 'ss-sgml-toggle-attributes)

;; prefer sgml-mode to html-mode
(add-to-list 'auto-mode-alist '("\\.s?html?$" . sgml-mode))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;_+ nXML mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(add-to-list 'auto-mode-alist
             (cons (concat "\\."
                           (regexp-opt '("xml" "xsd" "sch" "rng"
                           "xslt" "svg" "rss"
                           "html" "jelly" "jnlp" "fo"
                           "xsl" "xslt") t) "\\'")
                   'nxml-mode))

(setq magic-mode-alist (cons '("<\\?xml " . nxml-mode) magic-mode-alist))

(require 'nxml-mode)
(load-library "rng-auto")

(setq nxml-slash-auto-complete-flag t
      nxml-default-buffer-file-coding-system 'utf-8)

(push (expand-file-name "~/emacs/etc/rng/schemas.xml") rng-schema-locating-files-default)

(defun my-nxml-mode-hook ()
  (if (string-match "/oneup/" (buffer-file-name))
      (setq tab-width 4
            indent-tabs-mode nil
            nxml-child-indent 4
            nxml-attribute-indent 4)
    (if (string-match "/workspace/" (buffer-file-name))
        (setq tab-width 2
              indent-tabs-mode t
              nxml-child-indent 2
              nxml-attribute-indent 2)))
  (setq truncate-lines t
        ispell-skip-html t)
  (auto-fill-mode t)
  (set-fill-column 100)
  ;; (xslt-process-mode 1)
  (define-key nxml-mode-map [(tab)] 'nxml-indent-complete)
  (define-key nxml-mode-map [(return)] 'reindent-then-newline-and-indent))

(add-hook 'nxml-mode-hook 'my-nxml-mode-hook)

(defun nxml-indent-complete ()
  "A special nxml indent/complete function"
  (interactive)
  (if (mark-or-region-active)
      (indent-region (mark) (point) nil)
    (if (save-excursion (skip-chars-backward " \t") (not (bolp)))
        (nxml-complete)
      (indent-for-tab-command))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Relaxng compact grammars
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; (require 'rnc-mode)
;; (add-to-list 'auto-mode-alist '("\\.rnc$" . rnc-mode))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;_+ XSL mode --- use nxml mode no
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; (add-to-list 'load-path (expand-file-name "xslide" emacs-packages-dir))
;; (autoload 'xsl-mode "xslide" "Major mode for XSL." t)

;; (add-to-list 'auto-mode-alist '("\\.xsl$" . xsl-mode))
;; (add-to-list 'auto-mode-alist '("\\.xslt$" . xsl-mode))
;; (add-to-list 'auto-mode-alist '("\\.fo$" . xsl-mode))

;; (defun xsl-indent-complete ()
;;   "A special sgml indent/complete function"
;;   (interactive)
;;     (if (save-excursion (skip-chars-backward " \t") (not (bolp)))
;;      (xsl-complete)
;;       (xsl-electric-tab)))

;; (eval-after-load "xslide"
;;   '(progn
;;      (add-hook 'xsl-mode-hook  'turn-on-font-lock)
;;      (define-key xsl-mode-map [(tab)] 'xsl-indent-complete)
;;      ))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;_+ DTD mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(autoload 'dtd-mode "tdtd" "Major mode for SGML and XML DTDs." t)
(autoload 'dtd-etags "tdtd"
  "Execute etags on FILESPEC and match on DTD-specific regular expressions."
  t)
(autoload 'dtd-grep "tdtd" "Grep for PATTERN in files matching FILESPEC." t)

;; Turn on font lock when in DTD mode
(add-hook 'dtd-mode-hooks  'turn-on-font-lock)

(setq auto-mode-alist
      (append
       (list
        '("\\.dcl$" . dtd-mode)
        '("\\.dec$" . dtd-mode)
        '("\\.dtd$" . dtd-mode)
        '("\\.ele$" . dtd-mode)
        '("\\.ent$" . dtd-mode)
        '("\\.mod$" . dtd-mode))
       auto-mode-alist))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;_+ XSLT Process mode
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(add-to-list 'load-path (expand-file-name "xslt-process/lisp" emacs-packages-dir))

;; set up xslt-process minor mode
(autoload 'xslt-process-mode "xslt-process" "Emacs XSLT processing" t)
(autoload 'xslt-process-install-docbook "xslt-process" 
  "Register the DocBook package with XSLT-process" t)

(add-hook 'xml-mode-hook 'xslt-process-mode)
(add-hook 'xsl-mode-hook 'xslt-process-mode)

(defadvice xml-mode (after run-xml-mode-hooks act)
  "Invoke `xml-mode-hook' hooks in the XML mode."
  (run-hooks 'xml-mode-hook))

;; make xml files writeable, they are not by default, why?
(add-hook 'xml-mode-hook (lambda () (toggle-read-only -1)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;_+ HTML stuff
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(add-to-list 'auto-mode-alist '("\\.jsp$" . html-mode))
(add-to-list 'auto-mode-alist '("\\.html$" . html-mode))
(add-to-list 'auto-mode-alist '("\\.shtml$" . html-mode))

;; Stefan Reuter <97j5s5$963$3@kastor.inf.tu-dresden.de> 
;; modified for selfhtml 8.0
(defvar selfhtml-path (expand-file-name "~/html/doc/html/self-html/"))
(defvar selfhtml-html-alist nil)
(defvar selfhtml-css-alist nil)
(defvar selfhtml-xml-alist nil)

(defun selfhtml-get-link-list (what)
  (let ((FILE (shell-command-to-string (concat "cat " selfhtml-path "navigation/quickbar/liste_" what ".htm")))
        (POS 0)
        TMP LIST)
    (while (setq TMP (string-match "option value=\"\\([^\"]+\\.htm[^\"]+\\)\">\\([^<]+\\)</option>" 
                                   FILE POS))
      (setq LIST (cons (cons (match-string 2 FILE) (match-string 1 FILE)) LIST))
      (setq POS (1+ TMP)))
    LIST))

;; (setq selfhtml-html-alist (selfhtml-get-link-list "html"))

(defun selfhtml-get-html-alist ()
  (or selfhtml-html-alist
      (setq selfhtml-html-alist (selfhtml-get-link-list "html"))))

(defun selfhtml-get-css-alist ()
  (or selfhtml-css-alist
      (setq selfhtml-css-alist (selfhtml-get-link-list "css"))))

(defun selfhtml-get-xml-alist ()
  (or selfhtml-xml-alist
      (setq selfhtml-xml-alist (selfhtml-get-link-list "xml"))))

(defun selfhtml-lookup-html (section)
  "Looks up SelfHTML for HTML doc, using your favorite Web browser."
  (interactive
   (list (completing-read "Lookup SelfHTML for: "
                          (selfhtml-get-html-alist) nil t)))
  (let ((filename
         (format "file://%shtml/%s" selfhtml-path (cdr (assoc section (selfhtml-get-html-alist))))))
    (browse-url filename)))

(defun selfhtml-lookup-css (section)
  "Looks up SelfHTML for CSS doc, using your favorite Web browser."
  (interactive
   (list (completing-read "Lookup SelfHTML for: "
                          (selfhtml-get-css-alist) nil t)))
  (let ((filename
         (format "file://%scss/%s" selfhtml-path (cdr (assoc section (selfhtml-get-css-alist))))))
    (browse-url filename)))

(defun selfhtml-lookup-xml (section)
  "Looks up SelfHTML for XML doc, using your favorite Web browser."
  (interactive
   (list (completing-read "Lookup SelfHTML for: "
                          (selfhtml-get-xml-alist) nil t)))
  (let ((filename
         (format "file://%sxml/%s" selfhtml-path (cdr (assoc section (selfhtml-get-xml-alist))))))
    (browse-url filename)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;_+ Cascading Style Sheets
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require 'css-mode)
(add-to-list 'auto-mode-alist '("\\.css\\'" . css-mode))

(setq cssm-indent-function #'cssm-c-style-indenter
      cssm-indent-level 4)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;_* Handling buffer contents
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun cleanup-xml-buffer (&optional dotabify)
  "Delete blank lines and reindent buffer.
This is meant for xml files."
  (interactive "P")
  (goto-char (point-min))
  (flush-lines "^\\s *$")
  (let ((min (point-min)) (max (point-max)))
    (if dotabify (tabify min max) (untabify min max)))
  (indent-region (point-min) (point-max) nil))