legacy-dotfiles/emacs.d/nxhtml/util/majmodpri.el
Tom Willemsen 94d2fc1815 Django, org
* Added nxhtml, mostly for django support.

  * Changed some org settings.
2011-03-07 09:04:49 +01:00

448 lines
16 KiB
EmacsLisp

;;; majmodpri.el --- Major mode priorities handling
;;
;; Author: Lennart Borgman (lennart O borgman A gmail O com)
;; Created: 2008-08-26
(defconst majmodpri:version "0.62") ;;Version:
;; Last-Updated: 2009-04-30 Thu
;; URL:
;; Keywords:
;; Compatibility:
;;
;; Features that might be required by this library:
;;
;; None
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
;;
;; Different elisp libraries may try to handle the same type of files.
;; They normally do that by entering their major mode for a file type
;; in `auto-mode-alist' or the other lists affecting `normal-mode'.
;; Since the libraries may be loaded in different orders in different
;; Emacs sessions this can lead to rather stochastic choices of major
;; mode.
;;
;; This library tries to give the control of which major modes will be
;; used back to the user. It does that by letting the user set up
;; priorities among the major modes. This priorities are used to sort
;; the lists used by `normal-mode'.
;;
;; To setup this libray and get more information do
;;
;; M-x customize-group RET majmodpri RET
;;
;; Or, see the commands `majmodpri-sort-lists'.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Change log:
;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation; either version 2, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
;; Floor, Boston, MA 02110-1301, USA.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Code:
(eval-when-compile (require 'mumamo nil t))
(eval-when-compile (require 'ourcomments-indirect-fun nil t))
;;;; Idle sorting
(defvar majmodpri-idle-sort-timer nil)
(defun majmodpri-cancel-idle-sort ()
"Cancel idle sorting request."
(when majmodpri-idle-sort-timer
(cancel-timer majmodpri-idle-sort-timer)
(setq majmodpri-idle-sort-timer nil)))
(defun majmodpri-start-idle-sort ()
"Request idle sorting."
(majmodpri-cancel-idle-sort)
(setq majmodpri-idle-sort-timer
(run-with-idle-timer 0 nil 'majmodpri-sort-lists-in-timer)))
(defun majmodpri-sort-lists-in-timer ()
(condition-case err
(save-match-data ;; runs in timer
(majmodpri-sort-lists))
(error (message "(majmodpri-sort-lists): %s" err))))
;;;; Sorting
(defvar majmodpri-schwarzian-ordnum nil)
(defun majmodpri-schwarzian-in (rec)
"Transform REC before sorting."
(setq majmodpri-schwarzian-ordnum (1+ majmodpri-schwarzian-ordnum))
(let ((mode (cdr rec)))
(list
(list mode majmodpri-schwarzian-ordnum)
rec)))
(defun majmodpri-schwarzian-out (rec)
"Get original value of REC after sorting."
(cadr rec))
;; Fix-me: default for Emacs 22??
(defcustom majmodpri-no-nxml (< emacs-major-version 23)
"Don't use multi major modes with nxml if non-nil.
The default for Emacs prior to version 23 is to not use this
multi major modes by default since there are some problems.
This gives those multi major mode lower priority, but it does not
prevent use of them."
:type 'boolean
:group 'majmodpri)
;; (majmodpri-priority 'html-mumamo-mode)
;; (majmodpri-priority 'nxhtml-mumamo-mode)
(defsubst majmodpri-priority (mode)
"Return major mode MODE priority."
(if (and majmodpri-no-nxml
;; (symbolp mode)
;; (save-match-data
;; (string-match "nxhtml-mumamo" (symbol-name mode))))
(let* ((real (or (ourcomments-indirect-fun mode)
mode))
(chunk (when real (get real 'mumamo-chunk-family)))
(major-mode (when chunk
(cadr chunk))))
(when major-mode
(derived-mode-p 'nxml-mode))))
0
(length (memq mode majmodpri-mode-priorities))))
(defun majmodpri-compare-auto-modes (rec1 rec2)
"Compare record REC1 and record REC2.
Comparision:
- First check `majmodpri-mode-priorities'.
- Then use old order in list."
(let* ((schw1 (car rec1))
(schw2 (car rec2))
(mod1 (nth 0 schw1))
(mod2 (nth 0 schw2))
(ord1 (nth 1 schw1))
(ord2 (nth 1 schw2))
(pri1 (majmodpri-priority mod1))
(pri2 (majmodpri-priority mod2)))
(cond
((/= pri1 pri2) (> pri1 pri2))
(t (> ord1 ord2)))))
;;(benchmark 100 (quote (majmodpri-sort-lists)))
;;(defvar my-auto-mode-alist nil)
(defun majmodpri-sort-auto-mode-alist ()
"Sort `auto-mode-alist' after users priorities."
(setq majmodpri-schwarzian-ordnum 0)
;; Do not reorder function part, but put it first.
(let (fun-list
mod-list)
(dolist (rec auto-mode-alist)
(if (listp (cdr rec))
(setq fun-list (cons rec fun-list))
(setq mod-list (cons rec mod-list))))
(setq fun-list (nreverse fun-list))
(setq auto-mode-alist
(append
fun-list
(mapcar 'majmodpri-schwarzian-out
(sort
(mapcar 'majmodpri-schwarzian-in mod-list)
'majmodpri-compare-auto-modes))))))
(defun majmodpri-sort-magic-list (magic-mode-list-sym)
"Sort list MAGIC-MODE-LIST-SYM after users priorities."
(let ((orig-ordnum 0))
(set magic-mode-list-sym
;; S out
(mapcar (lambda (rec)
(cadr rec))
;; Sort
(sort
;; S in
(mapcar (lambda (rec)
(setq orig-ordnum (1+ orig-ordnum))
(let ((mode (cdr rec)))
(list
(list mode orig-ordnum)
rec)))
(symbol-value magic-mode-list-sym))
(lambda (rec1 rec2)
(let* ((schw1 (car rec1))
(schw2 (car rec2))
(mod1 (nth 0 schw1))
(mod2 (nth 0 schw2))
(ord1 (nth 1 schw1))
(ord2 (nth 1 schw2))
(pri1 (majmodpri-priority mod1))
(pri2 (majmodpri-priority mod2)))
(cond
((/= pri1 pri2) (> pri1 pri2))
(t (> ord1 ord2))))))))))
;;;###autoload
(defun majmodpri-sort-lists ()
"Sort the list used when selecting major mode.
Only sort those lists choosen in `majmodpri-lists-to-sort'.
Sort according to priorities in `majmodpri-mode-priorities'.
Keep the old order in the list otherwise.
The lists can be sorted when loading elisp libraries, see
`majmodpri-sort-after-load'.
See also `majmodpri-apply-priorities'."
(interactive)
;;(message "majmodpri-sort-lists running ...")
(majmodpri-cancel-idle-sort)
(when (memq 'magic-mode-alist majmodpri-lists-to-sort)
(majmodpri-sort-magic-list 'magic-mode-alist))
(when (memq 'auto-mode-alist majmodpri-lists-to-sort)
(majmodpri-sort-auto-mode-alist))
(when (memq 'magic-fallback-mode-alist majmodpri-lists-to-sort)
(majmodpri-sort-magic-list 'magic-fallback-mode-alist))
;;(message "majmodpri-sort-lists running ... (done)")
)
;;;###autoload
(defun majmodpri-apply ()
"Sort major mode lists and apply to existing buffers.
Note: This function is suitable to add to
`desktop-after-read-hook'. It will restore the multi major modes
in buffers."
(majmodpri-apply-priorities t))
(defun majmodpri-sort-apply-to-current ()
"Sort lists and apply to current buffer."
(majmodpri-sort-lists)
(add-hook 'find-file-hook 'normal-mode t t))
(defun majmodpri-check-normal-mode ()
"Like `normal-mode', but keep major mode if same."
(let ((keep-mode-if-same t)
(old-major-mode major-mode)
(old-mumamo-multi-major-mode (when (boundp 'mumamo-multi-major-mode)
mumamo-multi-major-mode)))
(report-errors "File mode specification error: %s"
(set-auto-mode t))
;;(msgtrc "majmodpri-check %s %s %s" (current-buffer) major-mode mumamo-multi-major-mode)
(unless (and (eq old-major-mode major-mode)
(or (not old-mumamo-multi-major-mode)
(eq old-mumamo-multi-major-mode mumamo-multi-major-mode)))
(msgtrc "majmodpri-check changing")
(report-errors "File local-variables error: %s"
(hack-local-variables))
;; Turn font lock off and on, to make sure it takes account of
;; whatever file local variables are relevant to it.
(when (and font-lock-mode
;; Font-lock-mode (now in font-core.el) can be ON when
;; font-lock.el still hasn't been loaded.
(boundp 'font-lock-keywords)
(eq (car font-lock-keywords) t))
(setq font-lock-keywords (cadr font-lock-keywords))
(font-lock-mode 1))
(message "majmodpri-apply-priorities: buffer=%s, %s,%s => %s,%s"
(current-buffer)
old-major-mode
old-mumamo-multi-major-mode
major-mode
(when (boundp 'mumamo-multi-major-mode)
mumamo-multi-major-mode)))))
;;;###autoload
(defun majmodpri-apply-priorities (change-modes)
"Apply major mode priorities.
First run `majmodpri-sort-lists' and then if CHANGE-MODES is
non-nil apply to existing file buffers. If interactive ask
before applying."
(interactive '(nil))
(message "majmodpri-apply-priorities running ...")
(majmodpri-sort-lists)
(when (or change-modes
(with-no-warnings (called-interactively-p)))
(let (file-buffers)
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(let ((name (buffer-name))
(file buffer-file-name))
(or (string= (substring name 0 1) " ") ;; Internal
(not file)
(setq file-buffers (cons buffer file-buffers))))))
(if (not file-buffers)
(when change-modes
;;(message "majmodpri-apply-priorities: No file buffers to change modes in")
)
(when (with-no-warnings (called-interactively-p))
(setq change-modes
(y-or-n-p "Check major mode in all file visiting buffers? ")))
(when change-modes
(dolist (buffer file-buffers)
(with-current-buffer buffer
(let ((old-major major-mode))
(majmodpri-check-normal-mode)
)))))))
(message "majmodpri-apply-priorities running ... (done)"))
;;;; Custom
;;;###autoload
(defgroup majmodpri nil
"Customization group for majmodpri.el"
:group 'nxhtml
)
(defcustom majmodpri-mode-priorities
'(
cperl-mumamo-mode
csound-sgml-mumamo-mode
django-nxhtml-mumamo-mode
django-html-mumamo-mode
embperl-nxhtml-mumamo-mode
embperl-html-mumamo-mode
eruby-nxhtml-mumamo-mode
eruby-html-mumamo-mode
genshi-nxhtml-mumamo-mode
genshi-html-mumamo-mode
jsp-nxhtml-mumamo-mode
jsp-html-mumamo-mode
laszlo-nxml-mumamo-mode
metapost-mumamo-mode
mjt-nxhtml-mumamo-mode
mjt-html-mumamo-mode
noweb2-mumamo-mode
;;org-mumamo-mode
perl-mumamo-mode
smarty-nxhtml-mumamo-mode
smarty-html-mumamo-mode
;;tt-html-mumamo-mode
nxhtml-mumamo-mode
html-mumamo-mode
nxml-mumamo-mode
nxml-mode
javascript-mode
;;espresso-mode
rhtml-mode
)
"Priority list for major modes.
Modes that comes first have higher priority.
See `majmodpri-sort-lists' for more information."
:type '(repeat symbol)
:set (lambda (sym val)
(set-default sym val)
(when (and (boundp 'majmodpri-sort-after-load)
majmodpri-sort-after-load)
(majmodpri-start-idle-sort)))
:group 'majmodpri)
(defcustom majmodpri-lists-to-sort
'(magic-mode-alist auto-mode-alist magic-fallback-mode-alist)
;;nil
"Which major mode lists to sort.
See `majmodpri-sort-lists' for more information."
:type '(set (const magic-mode-alist)
(const auto-mode-alist)
(const magic-fallback-mode-alist))
:set (lambda (sym val)
(set-default sym val)
(when (and (boundp 'majmodpri-sort-after-load)
majmodpri-sort-after-load)
(majmodpri-start-idle-sort)))
:group 'majmodpri)
(defcustom majmodpri-sort-after-load
'(
chart
gpl
;;nxhtml-autoload
php-mode
rnc-mode
ruby-mode
)
"Sort major mode lists after loading elisp libraries if non-nil.
This should not really be needed since just loading a library
should not change how Emacs behaves. There are however quite a
few thirt party libraries that does change `auto-mode-alist'
\(including some of my own) since that sometimes seems
reasonable. Some of them are in the default value of this
variable.
There are two possibilities for sorting here:
- Value=list of features (default). Sort immediately after loading a
library in the list. Apply to current buffer.
- Value=t. Sort after loading any library. Sorting is then not
done immediately. Instead it runs in an idle timer. This
means that if several elisp libraries are loaded in a command
then the sorting will only be done once, after the command has
finished. After sorting apply to all buffers.
Note that the default does break Emacs rule that loading a
library should not change how Emacs behave. On the other hand
the default tries to compensate for that the loaded libraries
breaks this rule by changing `auto-mode-alist'.
See `majmodpri-sort-lists' for more information."
:type '(choice (const :tag "Never" nil)
(const :tag "After loading any elisp library" t)
(repeat :tag "After loading specified features" symbol))
:set (lambda (sym val)
(set-default sym val)
;; Clean up `after-load-alist' first.
(setq after-load-alist
(delq nil
(mapcar (lambda (rec)
(unless (member (cadr rec)
'((majmodpri-start-idle-sort)
(majmodpri-sort-lists)))
rec))
after-load-alist)))
(when val
;;(message "majmodpri-sort-after-load: val=%s" val)
(let ((sort-and-apply nil))
(if (not (listp val))
(add-to-list 'after-load-alist
(if (eq val t)
'(".*" (majmodpri-start-idle-sort))
'("." (majmodpri-sort-lists))))
(dolist (feat val)
;;(message "feat=%s" feat)
(if (featurep feat)
(setq sort-and-apply t)
(if (eq val t)
(eval-after-load feat '(majmodpri-start-idle-sort))
(eval-after-load feat '(majmodpri-sort-apply-to-current))))))
(when sort-and-apply
;;(message "majmodpri-sort-after-load: sort-and-apply")
(majmodpri-apply-priorities t))
(if (eq val t)
(majmodpri-start-idle-sort)
(majmodpri-apply-priorities t)))))
:group 'majmodpri)
(provide 'majmodpri)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; majmodpri.el ends here