From 94d2fc1815a919734353c942f224db1de4b4fcb8 Mon Sep 17 00:00:00 2001 From: Tom Willemsen Date: Mon, 7 Mar 2011 09:04:49 +0100 Subject: Django, org * Added nxhtml, mostly for django support. * Changed some org settings. --- emacs.d/nxhtml/util/anchored-transpose.el | 305 + emacs.d/nxhtml/util/appmenu-fold.el | 79 + emacs.d/nxhtml/util/appmenu.el | 523 ++ emacs.d/nxhtml/util/as-external.el | 310 + emacs.d/nxhtml/util/buffer-bg.el | 89 + emacs.d/nxhtml/util/chartg.el | 844 +++ emacs.d/nxhtml/util/css-color.el | 983 +++ emacs.d/nxhtml/util/css-palette.el | 471 ++ emacs.d/nxhtml/util/css-simple-completion.el | 238 + emacs.d/nxhtml/util/cus-new-user.el | 803 +++ emacs.d/nxhtml/util/custsets.el | 83 + emacs.d/nxhtml/util/ecb-batch-compile.el | 65 + emacs.d/nxhtml/util/ediff-url.el | 188 + emacs.d/nxhtml/util/ffip.el | 304 + emacs.d/nxhtml/util/fold-dwim.el | 466 ++ emacs.d/nxhtml/util/foldit.el | 357 + emacs.d/nxhtml/util/fupd.el | 127 + emacs.d/nxhtml/util/gimpedit.el | 172 + emacs.d/nxhtml/util/gpl.el | 213 + emacs.d/nxhtml/util/hfyview.el | 651 ++ emacs.d/nxhtml/util/hl-needed.el | 402 ++ emacs.d/nxhtml/util/html-write.el | 455 ++ emacs.d/nxhtml/util/idn.el | 151 + emacs.d/nxhtml/util/inlimg.el | 429 ++ emacs.d/nxhtml/util/key-cat.el | 329 + emacs.d/nxhtml/util/majmodpri.el | 448 ++ emacs.d/nxhtml/util/markchars.el | 151 + emacs.d/nxhtml/util/mlinks.el | 1367 ++++ emacs.d/nxhtml/util/mumamo-aspnet.el | 227 + emacs.d/nxhtml/util/mumamo-fun.el | 3333 +++++++++ emacs.d/nxhtml/util/mumamo-regions.el | 311 + emacs.d/nxhtml/util/mumamo-trace.el | 6 + emacs.d/nxhtml/util/mumamo.el | 9100 +++++++++++++++++++++++++ emacs.d/nxhtml/util/n-back.el | 1296 ++++ emacs.d/nxhtml/util/new-key-seq-widget.el | 312 + emacs.d/nxhtml/util/nxml-mode-os-additions.el | 99 + emacs.d/nxhtml/util/ocr-user.el | 86 + emacs.d/nxhtml/util/org-panel.el | 745 ++ emacs.d/nxhtml/util/ourcomments-util.el | 2427 +++++++ emacs.d/nxhtml/util/ourcomments-widgets.el | 141 + emacs.d/nxhtml/util/pause.el | 794 +++ emacs.d/nxhtml/util/pointback.el | 93 + emacs.d/nxhtml/util/popcmp.el | 472 ++ emacs.d/nxhtml/util/readme.txt | 3 + emacs.d/nxhtml/util/rebind.el | 240 + emacs.d/nxhtml/util/rnc-mode.el | 265 + emacs.d/nxhtml/util/rxi.el | 148 + emacs.d/nxhtml/util/search-form.el | 473 ++ emacs.d/nxhtml/util/sex-mode.el | 463 ++ emacs.d/nxhtml/util/sml-modeline.el | 192 + emacs.d/nxhtml/util/tabkey2.el | 1701 +++++ emacs.d/nxhtml/util/tyda.el | 94 + emacs.d/nxhtml/util/udev-ecb.el | 229 + emacs.d/nxhtml/util/udev-rinari.el | 204 + emacs.d/nxhtml/util/udev.el | 456 ++ emacs.d/nxhtml/util/useful-commands.el | 63 + emacs.d/nxhtml/util/viper-tut.el | 1009 +++ emacs.d/nxhtml/util/vline.el | 350 + emacs.d/nxhtml/util/web-vcs-revision.txt | 1 + emacs.d/nxhtml/util/whelp.el | 988 +++ emacs.d/nxhtml/util/winsav.el | 1585 +++++ emacs.d/nxhtml/util/winsize.el | 1173 ++++ emacs.d/nxhtml/util/wrap-to-fill.el | 364 + emacs.d/nxhtml/util/zencoding-mode.el | 801 +++ 64 files changed, 41247 insertions(+) create mode 100644 emacs.d/nxhtml/util/anchored-transpose.el create mode 100644 emacs.d/nxhtml/util/appmenu-fold.el create mode 100644 emacs.d/nxhtml/util/appmenu.el create mode 100644 emacs.d/nxhtml/util/as-external.el create mode 100644 emacs.d/nxhtml/util/buffer-bg.el create mode 100644 emacs.d/nxhtml/util/chartg.el create mode 100644 emacs.d/nxhtml/util/css-color.el create mode 100644 emacs.d/nxhtml/util/css-palette.el create mode 100644 emacs.d/nxhtml/util/css-simple-completion.el create mode 100644 emacs.d/nxhtml/util/cus-new-user.el create mode 100644 emacs.d/nxhtml/util/custsets.el create mode 100644 emacs.d/nxhtml/util/ecb-batch-compile.el create mode 100644 emacs.d/nxhtml/util/ediff-url.el create mode 100644 emacs.d/nxhtml/util/ffip.el create mode 100644 emacs.d/nxhtml/util/fold-dwim.el create mode 100644 emacs.d/nxhtml/util/foldit.el create mode 100644 emacs.d/nxhtml/util/fupd.el create mode 100644 emacs.d/nxhtml/util/gimpedit.el create mode 100644 emacs.d/nxhtml/util/gpl.el create mode 100644 emacs.d/nxhtml/util/hfyview.el create mode 100644 emacs.d/nxhtml/util/hl-needed.el create mode 100644 emacs.d/nxhtml/util/html-write.el create mode 100644 emacs.d/nxhtml/util/idn.el create mode 100644 emacs.d/nxhtml/util/inlimg.el create mode 100644 emacs.d/nxhtml/util/key-cat.el create mode 100644 emacs.d/nxhtml/util/majmodpri.el create mode 100644 emacs.d/nxhtml/util/markchars.el create mode 100644 emacs.d/nxhtml/util/mlinks.el create mode 100644 emacs.d/nxhtml/util/mumamo-aspnet.el create mode 100644 emacs.d/nxhtml/util/mumamo-fun.el create mode 100644 emacs.d/nxhtml/util/mumamo-regions.el create mode 100644 emacs.d/nxhtml/util/mumamo-trace.el create mode 100644 emacs.d/nxhtml/util/mumamo.el create mode 100644 emacs.d/nxhtml/util/n-back.el create mode 100644 emacs.d/nxhtml/util/new-key-seq-widget.el create mode 100644 emacs.d/nxhtml/util/nxml-mode-os-additions.el create mode 100644 emacs.d/nxhtml/util/ocr-user.el create mode 100644 emacs.d/nxhtml/util/org-panel.el create mode 100644 emacs.d/nxhtml/util/ourcomments-util.el create mode 100644 emacs.d/nxhtml/util/ourcomments-widgets.el create mode 100644 emacs.d/nxhtml/util/pause.el create mode 100644 emacs.d/nxhtml/util/pointback.el create mode 100644 emacs.d/nxhtml/util/popcmp.el create mode 100644 emacs.d/nxhtml/util/readme.txt create mode 100644 emacs.d/nxhtml/util/rebind.el create mode 100644 emacs.d/nxhtml/util/rnc-mode.el create mode 100644 emacs.d/nxhtml/util/rxi.el create mode 100644 emacs.d/nxhtml/util/search-form.el create mode 100644 emacs.d/nxhtml/util/sex-mode.el create mode 100644 emacs.d/nxhtml/util/sml-modeline.el create mode 100644 emacs.d/nxhtml/util/tabkey2.el create mode 100644 emacs.d/nxhtml/util/tyda.el create mode 100644 emacs.d/nxhtml/util/udev-ecb.el create mode 100644 emacs.d/nxhtml/util/udev-rinari.el create mode 100644 emacs.d/nxhtml/util/udev.el create mode 100644 emacs.d/nxhtml/util/useful-commands.el create mode 100644 emacs.d/nxhtml/util/viper-tut.el create mode 100644 emacs.d/nxhtml/util/vline.el create mode 100644 emacs.d/nxhtml/util/web-vcs-revision.txt create mode 100644 emacs.d/nxhtml/util/whelp.el create mode 100644 emacs.d/nxhtml/util/winsav.el create mode 100644 emacs.d/nxhtml/util/winsize.el create mode 100644 emacs.d/nxhtml/util/wrap-to-fill.el create mode 100644 emacs.d/nxhtml/util/zencoding-mode.el (limited to 'emacs.d/nxhtml/util') diff --git a/emacs.d/nxhtml/util/anchored-transpose.el b/emacs.d/nxhtml/util/anchored-transpose.el new file mode 100644 index 0000000..3a5464c --- /dev/null +++ b/emacs.d/nxhtml/util/anchored-transpose.el @@ -0,0 +1,305 @@ +;;; anchored-transpose.el --- Transposes a phrase around an anchor phrase + +;; Copyright (C) 2004 Free Software Foundation, Inc. + +;; Author: Rick Bielawski +;; Keywords: tools convenience + +;; This file 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 file 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. + +;;; Commentary: + +;; `anchored-transpose' is an interactive autoload function to transpose +;; portions of a region around an anchor phrase. In other words it swaps +;; two regions. +;; +;; See C-h f anchored-transpose for a complete description. + +;;; Installing: + +;; 1) Put anchored-transpose.el on your load path. +;; 2) Put the following 2 lines in your .emacs +;; (global-set-key [?\C-x ?t] 'anchored-transpose) ;; Just a suggestion... +;; (autoload 'anchored-transpose "anchored-transpose" nil t) + +;;; History: + +;; 2004-09-24 RGB Seems useable enough to release. +;; 2004-10-15 RGB Only comments and doc strings were updated. +;; 2004-10-22 RGB Added support for 2 phrase selection. +;; 2004-12-01 RGB Added secondary selection support. +;; 2005-07-21 RGB Updated help text and comments. +;; Added support for A C B D and C A D B selection. +;; Fixed bug affecting multi line selections. +;; 2005-09-28 RGB Allow swapping regions with no anchor text between. + +;; Changes by Lennart Borgman +;; 2009-11-25 LB Set and clear secondary selection from keyboard. +;; Always use secondary selection. +;; Keep selections right after swapping. +;; Clear them if not used again. +;; Swap between buffers. +;; Check for read-only. +;; Probably broke something... ;-) + +;;; Code: + +(defvar anchored-transpose-anchor () + "begin/end when `anchored-transpose' is in progress else nil") + +;;;###autoload +(defun anchored-transpose (beg1 end1 flg1 &optional beg2 end2 flg2 win2) + "Transpose portions of the region around an anchor phrase. + +`this phrase but not that word' can be transposed into +`that word but not this phrase' + +I want this phrase but not that word. + |----------------------------|. .This is the entire phrase. + |-------|. . . . . . .This is the anchor phrase. + +First select the entire phrase and type \\[anchored-transpose]. +This set the secondary selection. + +Then select the anchor phrase and type \\[anchored-transpose] +again. Alternatively you can do the selections like this: + +I want this phrase but not that word. + |----------| |---------| Separate phrase selection. + +By default the anchor phrase will automatically include +any surrounding whitespace even if you don't explicitly select +it. Also, it won't include certain trailing punctuation. See +`anchored-transpose-do-fuzzy' for details. A prefix arg prior to +either selection means `no fuzzy logic, use selections +literally'. + +You can select the regions to be swapped separately in any +order. + +After swapping both primary and secondary selection are still +active. They will be canceled after second next command if you +do not swap regions again. \(Second because this allow you to +adjust the regions and try again.) + +You can also swap text between different buffers this way. + +Typing \\[anchored-transpose] with nothing selected clears any +prior selection, ie secondary selection." + (interactive `(,(region-beginning) ,(region-end) + ,current-prefix-arg + ,@anchored-transpose-anchor)) + (setq anchored-transpose-anchor nil) + (when (and mouse-secondary-overlay + mark-active + (overlay-buffer mouse-secondary-overlay) + (/= (overlay-start mouse-secondary-overlay) + (overlay-end mouse-secondary-overlay))) + (if (eq (overlay-buffer mouse-secondary-overlay) (current-buffer)) + (progn + (setq beg2 (overlay-start mouse-secondary-overlay)) + (setq end2 (overlay-end mouse-secondary-overlay)) + (setq flg2 flg1) + (delete-overlay mouse-secondary-overlay)) + (let* ((sec-buf (overlay-buffer mouse-secondary-overlay)) + (sec-win (get-buffer-window sec-buf)) + (sec-new nil)) + (unless sec-win + (setq sec-new t) + (setq sec-win (split-window))) + (with-selected-window sec-win + (set-window-buffer (selected-window) sec-buf) + (goto-char (overlay-start mouse-secondary-overlay))) + (if (not (y-or-n-p "Swap between buffers ")) + (when sec-new (delete-window sec-win)) + (setq beg2 (overlay-start mouse-secondary-overlay)) + (setq end2 (overlay-end mouse-secondary-overlay)) + (setq flg2 flg1) + (setq win2 sec-win))))) + (setq win2 (or win2 (selected-window))) + (if mark-active + (if end2 ; then both regions are marked. swap them. + (if (not (eq win2 (selected-window))) + (anchored-transpose-swap beg1 end1 beg2 end2 win2) + (if (and (< beg1 beg2) ;A C B D + (< end1 end2) + (> end1 beg2)) + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg1 beg2 end1 end2 flg1 flg2 flg1 flg2)) + (if (and (> beg1 beg2) ;C A D B + (> end1 end2) + (> end2 beg1)) + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg2 beg1 end2 end1 flg2 flg1 flg2 flg1)) + (if (and (< beg1 beg2) ;A C D B + (> end1 end2)) + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg1 beg2 end2 end1 flg1 flg2 flg2 flg1)) + (if (and (> beg1 beg2) ;C A B D + (< end1 end2)) + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg2 beg1 end1 end2 flg2 flg1 flg1 flg2)) + (if (<= end1 beg2) ;A B C D + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg1 end1 beg2 end2 flg1 flg1 flg2 flg2)) + (if (<= end2 beg1) ;C D A B + (apply 'anchored-transpose-swap + (anchored-transpose-do-fuzzy + beg2 end2 beg1 end1 flg2 flg2 flg1 flg1)) + (error "Regions have invalid overlap")))))))) + ;; 1st of 2 regions. Save it and wait for the other. + ;;(setq anchored-transpose-anchor (list beg1 end1 flg1)) + (if (or buffer-read-only + (get-char-property beg1 'read-only) + (get-char-property end1 'read-only)) + ;; Fix-me: move test, clean up a bit. + (message "Buffer text is readonly") + (set-secondary-selection beg1 end1) + (setq deactivate-mark t) + (message "%s" (this-command-keys)) + (message (propertize "Transpose: Select second region and call again - (without selection to cancel)" + 'face 'secondary-selection)))) + (if (and mouse-secondary-overlay + (overlay-buffer mouse-secondary-overlay)) + (progn + (cancel-secondary-selection) + (message (propertize "Canceled secondary selection" 'face + 'highlight))) + (message (propertize "Command requires a marked region" 'face + 'highlight))))) + +;;;###autoload +(defun set-secondary-selection (beg end) + "Set the secondary selection to the current region. +This must be bound to a mouse drag event." + (interactive "r") + (move-overlay mouse-secondary-overlay beg end (current-buffer)) + (when (called-interactively-p 'interactive) + ;;(deactivate-mark) + ) + (x-set-selection + 'SECONDARY + (buffer-substring (overlay-start mouse-secondary-overlay) + (overlay-end mouse-secondary-overlay)))) + +;;;###autoload +(defun cancel-secondary-selection () + (interactive) + (delete-overlay mouse-secondary-overlay) + (x-set-selection 'SECONDARY nil)) + +(defun anchored-transpose-do-fuzzy (r1beg r1end r2beg r2end + lit1 lit2 lit3 lit4) + "Returns the first 4 arguments after adjusting their value if necessary. + +I want this phrase but not that word. + |----------------------------|. .This is the entire phrase. + |-------|. . . . . . .This is the anchor phrase. + R1BEG R1END R2BEG R2END + +R1BEG and R1END define the first region and R2BEG and R2END the second. + +The flags, LIT1 thru LIT4 indicate if fuzzy logic should be applied to the +beginning of R1BEG, the end of R1END, the beginning of R2BEG, the end of R2END +respectively. If any flag is nil then fuzzy logic will be applied. Otherwise +the value passed should be returned LITerally (that is, unchanged). + +See `anchored-transpose-fuzzy-begin' and `anchored-transpose-fuzzy-end' for +specifics on what adjustments these routines will make when LITx is nil." + (list + (if lit1 r1beg + (anchored-transpose-fuzzy-begin r1beg r1end "[\t ]+")) + (if lit2 r1end + (anchored-transpose-fuzzy-end r1beg r1end "\\s +")) + (if lit3 r2beg + (anchored-transpose-fuzzy-begin r2beg r2end "[\t ]+")) + (if lit4 r2end + (anchored-transpose-fuzzy-end r2beg r2end "\\s *[.!?]")) + nil)) + +(defun anchored-transpose-fuzzy-end (beg end what) + "Returns END or new value for END based on the regexp WHAT. +BEG and END are buffer positions defining a region. If that region ends +with WHAT then the value for END is adjusted to exclude that matching text. + +NOTE: The regexp is applied differently than `looking-back' applies a regexp. + +Example: if (buffer-string beg end) contains `1234' the regexp `432' matches +it, not `234' as `looking-back' would. Also, your regexp never sees the char +at BEG so the match will always leave at least 1 character to transpose. +The reason for not using looking-back is that it's not greedy enough. +\(looking-back \" +\") will only match one space no matter how many exist." + (let ((str (concat + (reverse (append (buffer-substring (1+ beg) end) nil))))) + (if (string-match (concat "`" what) str) + (- end (length (match-string 0 str))) + end))) + +(defun anchored-transpose-fuzzy-begin (beg end what) + "Returns BEG or a new value for BEG based on the regexp WHAT. +BEG and END are buffer positions defining a region. If the region begins +with WHAT then BEG is adjusted to exclude the matching text. + +NOTE: Your regexp never sees the last char defined by beg/end. This insures +at least 1 char is always left to transpose." + (let ((str (buffer-substring beg (1- end)))) + (if (string-match (concat "`" what) str) + (+ beg (length (match-string 0 str))) + beg))) + +(defun anchored-transpose-swap (r1beg r1end r2beg r2end win2) + "Swaps region r1beg/r1end with r2beg/r2end. Flags are currently ignored. +Point is left at r1end." + (let ((reg1 (buffer-substring r1beg r1end)) + (reg2 nil) + (old-buffer (current-buffer))) + (when win2 + (unless (eq (selected-window) win2) + (select-window win2) + (set-buffer (window-buffer (selected-window))))) + (setq reg2 (delete-and-extract-region r2beg r2end)) + (goto-char r2beg) + (let ((new-mark (point))) + (insert reg1) + (push-mark new-mark)) + ;; I want to leave point at the end of phrase 2 in current buffer. + (save-excursion + (with-current-buffer old-buffer + (goto-char r1beg) + (delete-region r1beg r1end) + (let ((here (point))) + (insert reg2) + (set-secondary-selection here (point))))) + (setq deactivate-mark nil) + (when (eq old-buffer (current-buffer)) + (add-hook 'post-command-hook 'anchored-swap-post-command t t)))) + +(defun anchored-swap-post-command () + (condition-case err + (unless mark-active + (cancel-secondary-selection) + (remove-hook 'post-command-hook 'anchored-swap-post-command t)) + (error (message "anchored-swap-post-command: %s" err)))) + +(provide 'anchored-transpose) + +;; Because I like it this way. So there! +;;; fill-column:78 *** +;;; emacs-lisp-docstring-fill-column:78 *** +;;; +;;; Local Variables: *** +;;; End: *** +;;; anchored-transpose.el ends here. diff --git a/emacs.d/nxhtml/util/appmenu-fold.el b/emacs.d/nxhtml/util/appmenu-fold.el new file mode 100644 index 0000000..938ab92 --- /dev/null +++ b/emacs.d/nxhtml/util/appmenu-fold.el @@ -0,0 +1,79 @@ +;;; appmenu-fold.el --- Support form fold-dwim in AppMenu +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Wed Jan 11 21:48:02 2006 +(defconst appmenu-fold:version "0.51") ;; Version: +;; Last-Updated: Mon Jan 15 03:10:59 2007 (3600 +0100) +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(require 'fold-dwim nil t) +(eval-when-compile (require 'appmenu)) + +(when (featurep 'fold-dwim) + + (defun appmenu-fold-no-hs-minor-mode () + t) + (defun appmenu-fold-no-outline-minor-mode () + t) + (defun appmenu-fold-setup () + "Adds some tweaks for using fold-dwim in AppMenu." + (let ((fd-map (make-sparse-keymap))) + (define-key fd-map [fold-dwim-toggle] + (list 'menu-item "Fold Dwin Toggle" 'fold-dwim-toggle)) + (define-key fd-map [fold-dwim-hide-all] + (list 'menu-item "Fold Dwin Hide All" 'fold-dwim-hide-all)) + (define-key fd-map [fold-dwim-show-all] + (list 'menu-item "Fold Dwin Show All" 'fold-dwim-show-all)) + ;;(add-to-list 'appmenu-alist (cons t (cons "Folding" fd-map))) + (appmenu-add 'appmenu-fold nil t "Folding" fd-map) + ) +;;; (add-to-list 'appmenu-minor-modes-exclude +;;; '(hs-minor-mode appmenu-fold-no-hs-minor-mode)) +;;; (add-to-list 'appmenu-minor-modes-exclude +;;; '(outline-minor-mode appmenu-fold-no-outline-minor-mode))) + ) + ) + +(provide 'appmenu-fold) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; appmenu-fold.el ends here diff --git a/emacs.d/nxhtml/util/appmenu.el b/emacs.d/nxhtml/util/appmenu.el new file mode 100644 index 0000000..1f060ef --- /dev/null +++ b/emacs.d/nxhtml/util/appmenu.el @@ -0,0 +1,523 @@ +;;; appmenu.el --- A framework for [apps] popup menus. + +;; Copyright (C) 2008 by Lennart Borgman + +;; Author: Lennart Borgman +;; Created: Thu Jan 05 14:00:26 2006 +(defconst appmenu:version "0.63") ;; Version: +;; Last-Updated: 2010-01-04 Mon +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; appmenu.el is a framework for creating cooperative context +;; sensitive popup menus with commands from different major and minor +;; modes. For more information see `appmenu-mode'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; Version 0.61: +;; - Remove support for minor and major menus. +;; - Add support for text and overlay keymaps. +;; - Add customization options. +;; +;; Version 0.62: +;; - Fix problem with keymap at point. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'flyspell)) +(eval-when-compile (require 'help-mode)) +(eval-when-compile (require 'ourcomments-util nil t)) +(eval-when-compile (require 'mumamo nil t)) +;;(eval-when-compile (require 'mlinks nil t)) + +;;;###autoload +(defgroup appmenu nil + "Customization group for `appmenu-mode'." + :group 'convenience) + +(defcustom appmenu-show-help nil + "Non-nil means show AppMenu help on AppMenu popup." + :type 'boolean + :group 'appmenu) + +(defcustom appmenu-show-point-menu t + "If non-nil show entries fetched from keymaps at point." + :type 'boolean + :group 'appmenu) + +(defvar appmenu-alist nil + "List of additional menu keymaps. +To change this list use `appmenu-add' and `appmenu-remove'. + +The entries in this list are lists: + + \(ID PRIORITY TEST TITLE DEFINITION) + +ID is a unique identity. + +PRIORITY is a number or a variable whose value is a number +telling where to put this entry when showing the menu. + +TEST should be a form to evaluate. The entry is used if \(eval +TEST) returns non-nil. + +DEFINITION should be either a keymap or a function that returns a +keymap. + +The function must take no argument and return a keymap. If the +function returns nil then the entry is not shown in the popup +menu. Using this you can make context sensitive popup menus. + +For an example of use see mlinks.el.") + +(defun appmenu-sort-by-priority () + "Sort `appmenu-alist' entries by priority." + (setq appmenu-alist + (sort appmenu-alist + (lambda (recA recB) + (let ((priA (nth 1 recA)) + (priB (nth 1 recB))) + (when (symbolp priA) (setq priA (symbol-value priA))) + (when (symbolp priB) (setq priB (symbol-value priB))) + (< priA priB)))))) + +;;;###autoload +(defun appmenu-add (id priority test title definition) + "Add entry to `appmenu-alist'. +Add an entry to this list with ID, PRIORITY, TEST, TITLE and +DEFINITION as explained there." + (assert (symbolp id)) + (unless priority (setq priority 100)) + (assert (numberp priority)) + (assert (stringp title)) + (let ((rec (list id priority test title definition))) + (appmenu-remove id) + (add-to-list 'appmenu-alist rec))) + +(defun appmenu-remove (id) + "Remove entry with id ID from `appmenu-alist'." + (setq appmenu-alist (assq-delete-all id appmenu-alist))) + +(defun appmenu-help () + "Show help for minor mode function `appmenu-mode'." + (interactive) + (describe-function 'appmenu-mode)) + +(defun appmenu-keymap-len (map) + "Return length of keymap MAP." + (let ((ml 0)) + (map-keymap (lambda (e f) (setq ml (1+ ml))) map) + ml)) + +(defvar appmenu-mouse-only + '((flyspell-correct-word appmenu-flyspell-correct-word-before-point))) + +(defun appmenu-flyspell-correct-word-before-point () + "Pop up a menu of possible corrections for misspelled word before point. +Special version for AppMenu." + (interactive) + (flyspell-correct-word-before-point)) + +(defcustom appmenu-at-any-point '(ispell-word) + "Commands that may work at any point in a buffer. +Some important but not too often used commands that may be useful +for most points in a buffer." + :group 'appmenu) + +(defvar appmenu-map-fun) ;; dyn var, silence compiler + +(defun appmenu-make-menu-for-point (this-point) + "Construct a menu based on point THIS-POINT. +This includes some known commands for point and keymap at +point." + (let ((point-map (get-char-property this-point 'keymap)) + (funs appmenu-at-any-point) + (map (make-sparse-keymap "At point")) + (num 0) + last-prefix + this-prefix) + ;; Known for any point + (when point-map + (let ((appmenu-map-fun + (lambda (key fun) + (if (keymapp fun) + (map-keymap appmenu-map-fun fun) + (when (and (symbolp fun) + (fboundp fun)) + (let ((mouse-only (assq fun appmenu-mouse-only))) + (when mouse-only + (setq fun (cadr mouse-only))) + (add-to-list 'funs fun))))))) + (map-keymap appmenu-map-fun point-map))) + (dolist (fun funs) + (let ((desc (when fun (documentation fun)))) + (when desc + (setq desc (car (split-string desc "[\n]"))) + ;;(lwarn t :warning "pk: %s, %s" fun desc) + (setq this-prefix + (car (split-string (symbol-name fun) "[-]"))) + (when (and last-prefix + (not (string= last-prefix this-prefix))) + (define-key map + (vector (intern (format "appmenu-point-div-%s" num))) + (list 'menu-item "--"))) + (setq last-prefix this-prefix) + (setq num (1+ num)) + (define-key map + (vector (intern (format "appmenu-point-%s" num))) + (list 'menu-item desc fun))))) + (when (> num 0) map))) + +(defvar appmenu-level) ;; dyn var +(defvar appmenu-funs) ;; dyn var +(defvar appmenu-events) ;; dyn var +(defvar appmenu-this-point) ;; dyn var + +(defun appmenu-keymap-map-fun (ev def) + (if (keymapp def) + (progn + (add-to-list 'appmenu-funs (list appmenu-level ev)) + (setq appmenu-events (cons ev appmenu-events)) + (setq appmenu-level (1+ appmenu-level)) + + (map-keymap 'appmenu-keymap-map-fun def) + + (setq appmenu-events (cdr appmenu-events)) + (setq appmenu-level (1- appmenu-level))) + (when (and (symbolp def) + (fboundp def)) + (let* ((mouse-only (assq def appmenu-mouse-only)) + (fun (if mouse-only (cadr mouse-only) def)) + (doc (when fun + (if (not (eq fun 'push-button)) + (documentation fun) + (concat + "Button: " + (with-current-buffer (marker-buffer appmenu-this-point) + (or (get-char-property appmenu-this-point 'help-echo) + (let ((action-fun (get-char-property appmenu-this-point 'action))) + (if action-fun + (documentation action-fun) + "No action, ignored")) + "No documentation available"))))))) + (add-to-list 'appmenu-funs (list appmenu-level (cons ev appmenu-events) def doc)))))) + +;;(appmenu-as-help (point)) +(defun appmenu-as-help (this-point) + "Show keybindings specific done current point in buffer. +This shows the binding in the help buffer. + +Tip: This may be helpful if you are using `css-color-mode'." + (interactive (list (copy-marker (point)))) + ;; Split this for debugging + (let ((menu-here + (with-current-buffer (or (and (markerp this-point) + (marker-buffer this-point)) + (current-buffer)) + (unless (markerp this-point) (setq this-point (copy-marker this-point))) + (get-char-property this-point 'keymap)))) + ;;(describe-variable 'menu-here) + (appmenu-as-help-1 menu-here this-point))) + +(defun appmenu-as-help-1 (menu-here this-point) + (let ((appmenu-level 0) + (appmenu-funs nil) + (appmenu-events nil) + (appmenu-this-point this-point)) + (when menu-here + (map-keymap 'appmenu-keymap-map-fun menu-here)) + ;;(describe-variable 'appmenu-funs) + ;; Fix-me: collect info first in case we are in help-buffer! + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'appmenu-as-help this-point) (interactive-p)) + (with-current-buffer (help-buffer) + (let ((fmt " %s%15s %-30s\n")) + (insert (propertize + ;;"AppMenu: Keys found at point in buffer\n\n" + (format "Appmenu: Key bindings specific to point %s in buffer %S\n\n" + (+ 0 this-point) + (when (markerp this-point) + (buffer-name (marker-buffer this-point)))) + 'face 'font-lock-comment-face)) + (if (not menu-here) + (insert "\n\nThere are no point specific key bindings there now.") + (insert (propertize (format fmt "" "Key" "Function") 'face 'font-lock-function-name-face)) + (insert (propertize (format fmt "" "---" "--------") 'face 'font-lock-function-name-face)) + (dolist (rec appmenu-funs) + (let* ((lev (nth 0 rec)) + (ev (nth 1 rec)) + (fun (nth 2 rec)) + (doc (nth 3 rec)) + (d1 (when doc (car (split-string doc "[\n]"))))) + (if fun + (insert (format fmt + "" ;;(concat "*" (make-string (* 4 lev) ?\ )) + (key-description (reverse ev)) + d1) + (if nil (format "(%s)" fun) "")) + ;;(insert (format "something else=%S\n" rec)) + ))))))))) + + +(defun appmenu-map () + "Return menu keymap to use for popup menu." + (let* ((map (make-sparse-keymap + "AppMenu" + )) + (map-len (appmenu-keymap-len map)) + (map-init-len map-len) + (num-minor 0) + (id 0) + (point-menu (when appmenu-show-point-menu + (appmenu-make-menu-for-point (point))))) + ;; AppMenu itself + (when appmenu-show-help + (define-key map [appmenu-customize] + (list 'menu-item "Customize AppMenu" + (lambda () (interactive) (customize-group 'appmenu)) + :help "Customize AppMenu" + :visible 'appmenu-show-help)) + (define-key map [appmenu-help] + (list 'menu-item "Help for AppMenu" 'appmenu-help + :help "Help for how to use AppMenu" + :visible 'appmenu-show-help)) + (define-key map [appmenu-separator-1] + (list 'menu-item "--"))) + (setq map-len (appmenu-keymap-len map)) + (appmenu-sort-by-priority) + (dolist (rec appmenu-alist) + (let* ((test (nth 2 rec)) + (title (nth 3 rec)) + (mapdef (nth 4 rec)) + (usedef (if (symbolp mapdef) + (funcall mapdef) + mapdef))) + (when (and usedef + (eval test)) + (setq id (1+ id)) + (define-key map + (vector (intern (format "appmenu-%s" id))) + (list 'menu-item title usedef))) + )) + (when point-menu + (setq map-len (appmenu-keymap-len map)) + (when (> map-len map-init-len) + (define-key map [appmenu-at-point-div] + (list 'menu-item "--"))) + (define-key map [appmenu-at-point] + (list 'menu-item "Bound To Point" + point-menu))) + (setq map-len (appmenu-keymap-len map)) + (when (> map-len map-init-len) + map))) + +;; (defun appmenu-get-submenu (menu-command) +;; (let (subtitle submenumap) +;; (if (eq 'menu-item (car menu-command)) +;; (progn (setq subtitle (cadr menu-command)) +;; (setq submenumap (caddr menu-command))) +;; (setq subtitle (car menu-command)) +;; (setq submenumap (cdr menu-command))) +;; (unless (keymapp submenumap) (error "Submenu not a keymap=%s" submenumap)) +;; (cons subtitle submenumap))) + +(defun appmenu-popup () + "Pops up the AppMenu menu." + (interactive) + (let* ((mod (event-modifiers last-input-event)) + (is-mouse (or (memq 'click mod) + (memq 'down mod) + (memq 'drag mod)))) + (when is-mouse + (goto-char (posn-point (event-start last-input-event))) + (sit-for 0.01)) + (let ((menu (appmenu-map))) + (if menu + (popup-menu-at-point menu) + (message "Appmenu is empty"))))) + +(defvar appmenu-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [apps] 'appmenu-popup) + (define-key map [mouse-3] 'appmenu-popup) + (define-key map [(control apps)] 'appmenu-as-help) + map)) + + +;;(setq appmenu-auto-help 4) +(defcustom appmenu-auto-help 2 + "Automatically show help on keymap at current point. +This shows up after the number of seconds in this variable. +If it it nil this feature is off. + +This feature is only on in `appmenu-mode'." + :type '(choice (number :tag "Number of seconds to wait") + (const :tag "Turned off" nil)) + :set (lambda (sym val) + (set-default sym val) + (if val + (add-hook 'post-command-hook 'appmenu-auto-help-post-command nil t) + (remove-hook 'post-command-hook 'appmenu-auto-help-post-command t))) + :group 'appmenu) + +(defcustom appmenu-auto-match-keymaps + '(css-color) + "Keymaps listed here can be avoided." + :type '(set (const unknown) + (const mlink) + (const css-color)) + :group 'appmenu) + +(defvar appmenu-auto-help-timer nil) + +(defun appmenu-dump-keymap (km) + (let ((fun (lambda (ev def) + (message "ev=%S def=%S" ev def) + (when (keymapp def) + (map-keymap fun def))))) + (map-keymap fun km))) + +(defun appmenu-on-keymap (where) + (setq where (or where (point))) + (let* ((rec (get-char-property-and-overlay where 'keymap)) + (kmp (car rec)) + (ovl (cdr rec))) + (when kmp + (or (memq 'unknown appmenu-auto-match-keymaps) + (and (memq 'css-color appmenu-auto-match-keymaps) + (get-text-property where 'css-color-type)) + (and (memq 'mlinks appmenu-auto-match-keymaps) + (boundp 'mlinks-point-hilighter-overlay) + (eq ovl mlinks-point-hilighter-overlay)) + )))) + +(defsubst appmenu-auto-help-add-wcfg (at-point wcfg) + (mumamo-with-buffer-prepared-for-jit-lock + (add-text-properties at-point (1+ at-point) + (list 'point-left 'appmenu-auto-help-maybe-remove + 'appmenu-auto-help-wcfg wcfg)))) + +(defsubst appmenu-auto-help-remove-wcfg (at-point) + (mumamo-with-buffer-prepared-for-jit-lock + (remove-list-of-text-properties at-point (1+ at-point) + '(appmenu-auto-help-wcfg point-left)))) + +(defun appmenu-auto-help-maybe-remove (at-point new-point) + "Run in 'point-left property. +Restores window configuration." + (let ((old-wcfg (get-text-property at-point 'appmenu-auto-help-wcfg))) + (appmenu-auto-help-remove-wcfg at-point) + (if (appmenu-on-keymap new-point) + (appmenu-auto-help-add-wcfg new-point old-wcfg) + (if old-wcfg + (set-window-configuration old-wcfg) + (help-xref-go-back (help-buffer)))))) + +(defun appmenu-as-help-in-timer (win buf) + (condition-case err + (when (and (eq (selected-window) win) + (eq (current-buffer) buf) + appmenu-auto-help + (appmenu-on-keymap (point))) + (let* ((old-help-win (get-buffer-window (help-buffer))) + (wcfg (unless old-help-win + (current-window-configuration)))) + (unless old-help-win + (display-buffer (help-buffer))) + (appmenu-auto-help-add-wcfg (point) wcfg) + (appmenu-as-help (copy-marker (point))))) + (error (message "appmenu-as-help-in-timer: %s" (error-message-string err))))) + +(defun appmenu-auto-help-cancel-timer () + (when (timerp appmenu-auto-help-timer) + (cancel-timer appmenu-auto-help-timer)) + (setq appmenu-auto-help-timer nil)) + +(defun appmenu-auto-help-post-command () + (when (fboundp 'appmenu-as-help) + (condition-case err + (appmenu-auto-help-post-command-1) + (error (message "css-color-post-command: %s" (error-message-string err)))))) + +;; #fff #c9ff33 +(defun appmenu-auto-help-post-command-1 () + (appmenu-auto-help-cancel-timer) + (and appmenu-auto-help + (appmenu-on-keymap (point)) + (not (get-text-property (point) 'appmenu-auto-help-wcfg)) + (setq appmenu-auto-help-timer + (run-with-idle-timer appmenu-auto-help nil 'appmenu-as-help-in-timer + (selected-window) + (current-buffer))))) + + +;;;###autoload +(define-minor-mode appmenu-mode + "Use a context sensitive popup menu. +AppMenu (appmenu.el) is a framework for creating cooperative +context sensitive popup menus with commands from different major +and minor modes. Using this different modes may cooperate about +the use of popup menus. + +There is also the command `appmenu-as-help' that shows the key +bindings at current point in the help buffer. + +The popup menu and the help buffer version are on these keys: + +\\{appmenu-mode-map} + +The variable `appmenu-alist' is where the popup menu entries +comes from. + +If there is a `keymap' property at point then relevant bindings +from this is also shown in the popup menu. + +You can write functions that use whatever information you want in +Emacs to construct these entries. Since this information is only +collected when the popup menu is shown you do not have to care as +much about computation time as for entries in the menu bar." + :global t + :keymap appmenu-mode-map + :group 'appmenu + (if appmenu-mode + (add-hook 'post-command-hook 'appmenu-auto-help-post-command) + (remove-hook 'post-command-hook 'appmenu-auto-help-post-command))) + +(when (and appmenu-mode + (not (boundp 'define-globa-minor-mode-bug))) + (appmenu-mode 1)) + +(provide 'appmenu) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; appmenu.el ends here diff --git a/emacs.d/nxhtml/util/as-external.el b/emacs.d/nxhtml/util/as-external.el new file mode 100644 index 0000000..b1330c1 --- /dev/null +++ b/emacs.d/nxhtml/util/as-external.el @@ -0,0 +1,310 @@ +;;; as-external.el --- Emacs as an external editor to other apps +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Mon Jun 25 19:02:49 2007 +(defconst as-external:version "0.6") ;;Version: +;; Last-Updated: 2009-08-04 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This little library should make it easier to use Emacs as an +;; external editor in certain cases. One such case is when want to +;; use Emacs as the external editor with the Firefox add-on "It's All +;; Text". +;; +;; See variable `as-external-mode' for more information. +;; +;; +;;; A note on the implementation: +;; +;; You may wonder why this does not use `auto-mode-alist' since it +;; checks the file name in nearly the same way? It is perhaps possible +;; to use that, but there are two things to be aware of: +;; +;; 1. The choice made must override other possible choices. +;; +;; 2. Beside the file name the implementation here also checks if the +;; buffer has clients waiting. That makes the check more reliable. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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 'cl)) +(eval-when-compile (require 'html-write nil t)) +(eval-when-compile (require 'mlinks nil t)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'nxhtml-mode nil t)) +(eval-when-compile (require 'ourcomments-util nil t)) +(eval-when-compile (require 'pause nil t)) +(eval-when-compile (require 'server)) +(eval-when-compile (require 'wikipedia-mode nil t)) +(eval-and-compile (require 'wrap-to-fill nil t)) + +;;;###autoload +(defgroup as-external nil + "Settings related to Emacs as external editor." + :group 'nxhtml + :group 'external) + +(defcustom as-external-its-all-text-regexp "/itsalltext/" + "Regular expression matching It's All Text buffer's file." + :type 'regexp + :group 'as-external) + +(defcustom as-external-alist + '( + ("/itsalltext/.*wiki" as-external-for-wiki) + ("/itsalltext/.*mail" as-external-for-mail-mode) + ("/itsalltext/" as-external-for-xhtml) + ) + "List to determine setup if Emacs is used as an external Editor. +Element in this list should have the form + + \(FILE-REGEXP BUFFER-SETUP) + +where FILE-REGEXP should be a regular expression to match +`buffer-file-name'. If it matches then BUFFER-SETUP should be +called in the buffer. + +* Tip when using Firefox's add-on It's All Text: It looks like + the file name used will be constructed from the host url. For + example if your are editing something on + http://www.emacswiki.org/ the file name may be something like + 'www.emacswiki.org.283b1y212e.html'. + + +The list is processed by `as-external-setup'. Note that the first +match is used! + +The default entries in this list supports for Firefox addon It's +All Text: + +- `as-external-for-xhtml'. For text areas on web pages where you + can enter some XHTML code, for example blog comment fields. + +- `as-external-for-mail-mode', for editing web mail messages. + +- `as-external-for-wiki', for mediawiki. + +See also `as-external-mode'." + :type '(repeat + (list (choice (variable :tag "Regexp variable") + regexp) + command)) + :group 'as-external) + +(defcustom as-external-its-all-text-coding 'utf-8 + "Coding system to use for It's All Text buffers. +See also `as-external-for-xhtml'." + :type '(choice (const :tag "No special coding system" nil) + coding-system) + :group 'as-external) + +(defun as-external-fall-back (msg) + "Fallback to text-mode if necessary." + (text-mode) + (lwarn t :warning "%s. Using text-mode" msg)) + +;;;###autoload +(defun as-external-for-xhtml () + "Setup for Firefox addon It's All Text to edit XHTML. +It's All Text is a Firefox add-on for editing textareas with an +external editor. +See URL `https://addons.mozilla.org/en-US/firefox/addon/4125'. + +In this case Emacs is used to edit textarea fields on a web page. +The text will most often be part of a web page later, like on a +blog. Therefore turn on these: + +- `nxhtml-mode' since some XHTML tags may be allowed. +- `nxhtml-validation-header-mode' since it is not a full page. +- `wrap-to-fill-column-mode' to see what you are writing. +- `html-write-mode' to see it even better. + +Also bypass the question for line end conversion when using +emacsw32-eol." + (interactive) + (if (not (fboundp 'nxhtml-mode)) + (as-external-fall-back "Can't find nXhtml") + (nxhtml-mode) + (nxhtml-validation-header-mode 1) + (set (make-local-variable 'wrap-to-fill-left-marg-modes) + '(nxhtml-mode fundamental-mode)) + (wrap-to-fill-column-mode 1) + ;;(visible-point-mode 1) + (when (fboundp 'html-write-mode) (html-write-mode 1)) + (when (boundp 'emacsw32-eol-ask-before-save) + (make-local-variable 'emacsw32-eol-ask-before-save) + (setq emacsw32-eol-ask-before-save nil)))) + + +(defvar as-external-mail-mode-comment-pattern "^>.*$" + "Regular expression for a comment line.") + +(defvar as-external-mail-mode-email-pattern + (concat "[a-z0-9$%(*-=?[_][^<>\")!;:,{}]*" + "\@" + "\\(?:[a-z0-9\-]+\.\\)+[a-z0-9]\\{2,4\\}") + "Regular expression for a mail address.") + +(defvar as-external-mail-mode-font-lock-keywords + (list + (list as-external-mail-mode-comment-pattern + '(0 font-lock-comment-face)) + ;; (list as-external-mail-mode-email-pattern + ;; '(0 font-lock-keyword-face)) + )) + +;;;###autoload +(define-derived-mode as-external-for-mail-mode text-mode "ExtMail " + "Setup for Firefox addon It's All Text to edit mail. +Set normal mail comment markers in column 1 (ie >). + +Set `fill-column' to 90 and enable `wrap-to-fill-column-mode' so +that it will look similar to how it will look in the sent plain +text mail. + +See also `as-external-mode'." + ;; To-do: Look at http://globs.org/articles.php?lng=en&pg=2 + (set (make-local-variable 'comment-column) 0) + (set (make-local-variable 'comment-start) ">") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'font-lock-defaults) + '((as-external-mail-mode-font-lock-keywords) nil)) + (setq fill-column 90) + (mlinks-mode 1) + (wrap-to-fill-column-mode 1)) + +;;;###autoload +(defun as-external-for-wiki () + "Setup for Firefox addon It's All Text to edit MediaWikis." + (interactive) + (require 'wikipedia-mode nil t) + (if (not (featurep 'wikipedia-mode)) + (as-external-fall-back "Can't find file wikipedia-mode.el") + (wikipedia-mode))) + + +;;;###autoload +(define-minor-mode as-external-mode + "If non-nil check if Emacs is called as external editor. +When Emacs is called as an external editor for example to edit +text areas on a web page viewed with Firefox this library tries +to help to setup the buffer in a useful way. It may for example +set major and minor modes for the buffer. + +This can for example be useful when blogging or writing comments +on blogs. + +See `as-external-alist' for more information." + :global t + :group 'as-external + ;;(modify-coding-system-alist 'file "/itsalltext/" as-external-its-all-text-coding) + (let ((coding-entry + (cons + as-external-its-all-text-regexp + (cons as-external-its-all-text-coding + as-external-its-all-text-coding)))) + ;;(message "as-external-mode=%s" as-external-mode) + (if as-external-mode + (progn + (add-to-list 'file-coding-system-alist coding-entry) + (add-hook 'server-visit-hook 'as-external-setup t)) + (setq file-coding-system-alist + (delq coding-entry file-coding-system-alist)) + (remove-hook 'server-visit-hook 'as-external-setup)))) + +(defun as-external-setup () + "Check if Emacs is used as an external editor. +If so then turn on useful major and minor modes. +This is done by checking `as-external-alist'." + (condition-case err + (as-external-setup-1) + (error (message "as-external-setup error: %s" err)))) + +(defvar as-external-my-frame nil) +(make-variable-buffer-local 'as-external-my-frame) + +(defvar as-external-last-buffer nil) + +(defun as-external-server-window-fix-frames () + (condition-case err + (with-current-buffer as-external-last-buffer + (unless (buffer-live-p pause-buffer) + (remove-hook 'pause-break-exit-hook 'as-external-server-window-fix-frames) + (setq as-external-my-frame (or as-external-my-frame + (make-frame))) + (dolist (f (frame-list)) + (unless (eq f as-external-my-frame) + (lower-frame f))) + (raise-frame as-external-my-frame))) + (error (message "%s" (error-message-string err))))) + +(defun as-external-server-window (buffer) + (setq server-window nil) + (with-current-buffer buffer + (setq as-external-last-buffer (current-buffer)) + (run-with-idle-timer 2 nil 'as-external-server-window-fix-frames) + (add-hook 'pause-break-exit-hook 'as-external-server-window-fix-frames) + (add-hook 'kill-buffer-hook 'as-external-delete-my-frame nil t))) + +(defun as-external-delete-my-frame () + (let ((win (and (frame-live-p as-external-my-frame) + (get-buffer-window nil as-external-my-frame)))) + (when (and win + (= 1 (length (window-list as-external-my-frame 'no-mini)))) + (delete-frame as-external-my-frame) + (lower-frame)))) + +(defun as-external-setup-1 () + ;; Fix-me: How does one know if the file names are case sensitive? + (unless (when (boundp 'nowait) nowait) ;; dynamically bound in `server-visit-files' + (unless server-window + ;; `server-goto-toplevel' has been done here. + ;; Setup to use a new frame + (setq server-window 'as-external-server-window)) + (catch 'done + (dolist (rec as-external-alist) + (let ((file-regexp (car rec)) + (setup-fun (cadr rec))) + (when (symbolp file-regexp) + (setq file-regexp (symbol-value file-regexp))) + (when (string-match file-regexp (buffer-file-name)) + (funcall setup-fun) + (throw 'done t))))))) + +(provide 'as-external) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; as-external.el ends here diff --git a/emacs.d/nxhtml/util/buffer-bg.el b/emacs.d/nxhtml/util/buffer-bg.el new file mode 100644 index 0000000..d6459d6 --- /dev/null +++ b/emacs.d/nxhtml/util/buffer-bg.el @@ -0,0 +1,89 @@ +;;; buffer-bg.el --- Changing background color of windows +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-05-22T19:06:23+0200 Thu +;; Version: 0.5 +;; Last-Updated: 2008-05-22T23:19:55+0200 Thu +;; URL: http://www.emacswiki.org/cgi-bin/wiki/buffer-bg.el +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; There is currently no way to change background colors of Emacs +;; windows. This library implements a workaround using overlays. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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: + +(defvar buffer-bg-overlay nil) +(put 'buffer-bg-overlay 'permanent-local t) + +;;;###autoload +(defun buffer-bg-set-color (color buffer) + "Add an overlay with background color COLOR to buffer BUFFER. +If COLOR is nil remove previously added overlay." + (interactive + (let* ((prompt (if buffer-bg-overlay + "Background color (empty string to remove): " + "Background color: ")) + (color (read-color prompt nil t))) + (when (= 0 (length color)) + (setq color nil)) + (list color (current-buffer)) + )) + (if (not color) + (when buffer-bg-overlay + (delete-overlay buffer-bg-overlay) + (setq buffer-bg-overlay nil)) + (save-restriction + (widen) + (setq buffer-bg-overlay + (make-overlay (point-min) (point-max) nil nil t)) + ;; Fix-me: Let the overlay have priority 0 which is the + ;; lowest. Change this to below char properties if this is ever + ;; allowed in Emacs. + (overlay-put buffer-bg-overlay 'priority 0) + (let* ((bg-face (list :background color)) + (bg-after (propertize (make-string 10 ?\n) + 'face bg-face + 'intangible t))) + (overlay-put buffer-bg-overlay 'face bg-face) + ;; This is just confusing, don't use it: + ;;(overlay-put buffer-bg-overlay 'after-string bg-after) + ) + ))) + + +(provide 'buffer-bg) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; buffer-bg.el ends here diff --git a/emacs.d/nxhtml/util/chartg.el b/emacs.d/nxhtml/util/chartg.el new file mode 100644 index 0000000..7470710 --- /dev/null +++ b/emacs.d/nxhtml/util/chartg.el @@ -0,0 +1,844 @@ +;;; chartg.el --- Google charts (and maybe other) +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-04-06 Sun +(defconst chart:version "0.2") ;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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 'cl)) + +(defconst chartg-types + '((line-chartg-x lc) + (line-chartg-xy lxy) + (line-chart ls) + + (bar-chartg-horizontal bhs) + (bar-chartg-vertical bvs) + (bar-chartg-horizontal-grouped bhg) + (bar-chartg-vertical-grouped bvg) + + (pie-2-dimensional p) + (pie-3-dimensional p3) + + (venn-diagram v) + (scatter-plot s) + + (radar-chart r) + (radar-chartg-w-splines rs) + + (geographical-map t) + (meter gom))) + +(defconst chartg-types-keywords + (mapcar (lambda (rec) + (symbol-name (car rec))) + chartg-types)) + +(defvar chartg-mode-keywords-and-states + '(("Output-file:" (accept file-name)) + ("Size:" (accept number)) + ("Data:" (accept number)) + ("Type:" (accept chartg-type)) + )) + +(defvar chartg-mode-keywords + (mapcar (lambda (rec) + (car rec)) + chartg-mode-keywords-and-states)) + +;; Fix-me: I started to implement a parser, but I think I will drop it +;; and wait for Semantic to be easily available instead. Or just use +;; Calc/Org Tables. + +(defvar chartg-intermediate-states + '((end-or-label (or end-of-file label)) + )) + +(defvar chartg-extra-keywords-and-states + '( + ;;("Provider:") + ("Colors:") + ("Solid-fill:") + ("Linear-gradient:") + ("Linear-stripes:") + ("Chartg-title:" (and string end-or-label)) + ("Legends:" (accept string)) + ("Axis-types:") + ("Axis-labels:") + ("Axis-ranges:") + ("Axis-styles:") + ("Bar-thickness:") + ("Bar-chartg-zero-line:") + ("Bar-chartg-zero-line-2:") + ("Line-styles-1:") + ("Line-styles-2:") + ("Grid-lines:") + ("Shape-markers:") + ("Range-markers:") + )) + +(defvar chartg-extra-keywords + (mapcar (lambda (rec) + (car rec)) + chartg-extra-keywords-and-states)) + +(defvar chartg-raw-keywords-and-states + '( + ("Google-chartg-raw:" (accept string)) + )) + +(defvar chartg-raw-keywords + (mapcar (lambda (rec) + (car rec)) + chartg-raw-keywords-and-states)) + +(defvar chartg-mode-keywords-re (regexp-opt chartg-mode-keywords)) +(defvar chartg-extra-keywords-re (regexp-opt chartg-extra-keywords)) +(defvar chartg-types-keywords-re (regexp-opt chartg-types-keywords)) +(defvar chartg-raw-keywords-re (regexp-opt chartg-raw-keywords)) + +(defvar chartg-font-lock-keywords + `((,chartg-mode-keywords-re . font-lock-keyword-face) + (,chartg-extra-keywords-re . font-lock-variable-name-face) + (,chartg-types-keywords-re . font-lock-function-name-face) + (,chartg-raw-keywords-re . font-lock-preprocessor-face) + )) + +(defvar chartg-font-lock-defaults + '(chartg-font-lock-keywords nil t)) + +(defvar chartg-mode-syntax-table + (let ((table (make-syntax-table))) + (modify-syntax-entry ?\n "> " table) + (modify-syntax-entry ?\; "< " table) + table)) + +(defun chartg-create (provider out-file size data type + title legends &optional extras) + "Create a chart image. +PROVIDER is what to use for creating the chart. Currently only +`google' for Google's chart API is supported. + +OUT-FILE is where the image goes. + +SIZE is a cons cell with pixel width and height. + +DATA is the data to draw the chart from. It is a list of data +sets where each data set has the form: + + (list (list NUMBERS ...) (MIN . MAX))) + +TYPE can be the following: + +* Line charts + + - lc: Line chart with only y values. Each dataset is a new + line. + + - lxy: Line chart with both x and y values. For each line there + should be a pair of datasets, the first for x and the second + for y. If the x dataset just contains a single -1 then values + are evenly spaced along the x-axis. + + - ls: Like above, but axis are not drawn. + +* Bar charts: + + - bhs: horizontal bars. + - bvs: vertical bars. + - bhg, bvg: dito grouped. + +* Pie charts: + + - cht=p: one dimensional + - cht=p3: three dimensional + +* Venn diagrams + + - cht=v: data should be specified as + * the first three values specify the relative sizes of three + circles, A, B, and C + * the fourth value specifies the area of A intersecting B + * the fifth value specifies the area of A intersecting C + * the sixth value specifies the area of B intersecting C + * the seventh value specifies the area of A intersecting B + intersecting C + +* Scatter plots + + - cht=s: Supply a pair of datasets, first for x and second for + y coordinates. + +* Radar charts + + - cht=r: straight lines. + - cht=rs: splines. + + You will have to find out the format of the datasets + yourself, I don't understand it ;-) + + Or perhaps mail google? + +* Maps + + - cht=t + + together with + + - chtm=AREA: AREA for provider `google' is currently one of + * africa + * asia + * europe + * middle_east + * south_america + * usa + * world + +* Meter + + - cht=gom: A speed meter type meter. Takes a single value. + +TITLE is a string to use as title. + +LEGENDS is a list of labels to put on the data. + +EXTRAS is a list of extra arguments with the form + + (EXTRA-TYPE EXTRA-VALUE) + +Where EXTRA-TYPE is the extra argument type and EXTRA-VALUE the +value. The following EXTRA-TYPEs are supported: + +* COLORS: value is a list of colors corresponding to the list of + DATA. Each color have the format RRGGBB or RRGGBBTT where the + first form is the normal way to specify colors in rgb-format + and the second has an additional TT for transparence. TT=00 + means completely transparent and TT=FF means completely opaque. + +FILL-AREA are fill colors for data sets in line charts. It should +be a list + + (list COLOR START-INDEX END-INDEX) + +" + (message "(chartg-create %s %s %s %s %s %s %s" provider out-file size data type + title legends) + (unless (symbolp type) + (error "Argument TYPE should be a symbol")) + (unless (assoc type chartg-types) + (error "Unknown chart type: %s" type)) + (cond + ((eq provider 'google) + (let* ((g-type (nth 1 (assoc type chartg-types))) + (width (car size)) + (height (cdr size)) + ;;(size-par (format "&chs=%sx%s" width height)) + ;; + numbers + scales + colors-par + ;; + url + content + ) + (setq url + (format + "http://chart.apis.google.com/chart?cht=%s&chs=%dx%d" g-type width height)) + ;;(setq url (concat url size-par)) + ;; Data and scales + (unless data + (error "No data")) + (dolist (rec data) + (let* ((rec-numbers (car rec)) + (number-str + (let (str) + (dolist (num rec-numbers) + (setq str + (if (not str) + (number-to-string num) + (concat str "," (number-to-string num))))) + str)) + (rec-scale (cadr rec)) + (rec-min (car rec-scale)) + (rec-max (cdr rec-scale)) + (scale-str (when rec-scale (format "%s,%s" rec-min rec-max))) + ) + (if (not numbers) + (progn + (setq numbers (concat "&chd=t:" number-str)) + (when (or scale-str + (memq g-type '(p p3 gom))) + (setq scales (concat "&chds=" scale-str)))) + (setq numbers (concat numbers "|" number-str)) + (when scale-str + (setq scales (concat scales "," scale-str)))))) + (setq url (concat url numbers)) + (when scales (setq url (concat url scales))) + ;; fix-me: encode the url + (when title (setq url (concat url "&chtt=" (url-hexify-string title)))) + (when legends + (let ((url-legends (mapconcat 'url-hexify-string legends "|")) + (arg (if (memq g-type '(p p3 gom)) + "&chl=" + "&chdl="))) + (setq url (concat url arg url-legends)))) + (dolist (extra extras) + (let ((extra-type (car extra)) + (extra-value (cdr extra))) + (cond + ((eq extra-type 'GOOGLE-RAW) + (setq url (concat url extra-value))) + ((eq extra-type 'colors) + ;; Colors + (dolist (color extra-value) + (if (not colors-par) + (setq colors-par (concat "&chco=" color)) + (setq colors-par (concat colors-par "," color)))) + (when colors-par (setq url (concat url colors-par)))) + (t (error "Unsupported extra type: %s" extra-type))))) + + ;;(lwarn t :warning "url=%s" url)(top-level) + ;;(setq url (concat url "&chxt=y")) + (message "Sending %s" url) + (setq content + (with-current-buffer (url-retrieve-synchronously url) + (goto-char (point-min)) + (if (search-forward "\n\n" nil t) + (buffer-substring-no-properties (point) (point-max)) + (view-buffer-other-window (current-buffer)) + (error "Bad content")))) + (let* ((is-html (string-match-p "" content)) + (fname (progn + (when is-html + (setq out-file (concat (file-name-sans-extension out-file) ".html"))) + (expand-file-name out-file) + )) + (do-it (or (not (file-exists-p fname)) + (y-or-n-p + (concat "File " fname " exists. Replace it? ")))) + (buf (find-buffer-visiting fname)) + (this-window (selected-window))) + (when do-it + (when buf (kill-buffer buf)) + (with-temp-file fname + (insert content)) + (if (not is-html) + (view-file-other-window fname) + (chartg-show-last-error-file fname)) + (select-window this-window))))) + (t (error "Unknown provider: %s" provider))) + ) + +(defun chartg-show-last-error-file (fname) + (interactive) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'chartg-show-last-error-file fname) (interactive-p)) + (with-current-buffer (help-buffer) + (insert "Error, see ") + (insert-text-button "result error page" + 'action + `(lambda (btn) + (browse-url ,fname)))))) + +(defvar chartg-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(meta tab)] 'chartg-complete) + (define-key map [(control ?c) (control ?c)] 'chartg-make-chart) + map)) + +(defun chartg-missing-keywords () + (let ((collection (copy-sequence chartg-mode-keywords))) + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (while (re-search-forward chartg-mode-keywords-re nil t) + (setq collection + (delete (match-string-no-properties 0) + collection))))) + collection)) + +;;;###autoload +(defun chartg-complete () + (interactive) + (let* ((here (point)) + (partial (when (looking-back (rx word-start + (optional ?\") + (0+ (any "[a-z]")))) + (match-string-no-properties 0))) + (part-pos (if partial + (match-beginning 0) + (setq partial "") + (point))) + (state (catch 'pos-state (chartg-get-state (point)))) + (msg "No completions") + collection + all + prompt + res) + (when state + (cond + ((or (= (current-column) 0) + (equal state 'need-label)) + (setq collection (append (chartg-missing-keywords) + chartg-extra-keywords + chartg-raw-keywords + nil)) + (setq prompt "Label: ")) + ((equal state '(accept number)) + (setq res nil) + (setq msg (propertize "Needs a number here!" + 'face 'secondary-selection))) + ((equal state '(accept chartg-type)) + (setq collection chartg-types-keywords) + (setq prompt "Chart type: ")) + ((equal state '(accept file-name)) + (setq res + (concat "\"" (read-file-name "Output-file: " + nil + ;; fix-me: handle partial + partial) + "\"")))) + (when collection + (let ((all (if partial + (all-completions partial collection) + collection))) + (setq res (when all + (if (= (length all) 1) + (car all) + (completing-read prompt collection nil t partial))))))) + (if (not res) + (message "%s" msg) + (insert (substring res (length partial)))))) + + +(defun chartg-get-state (want-pos-state) + (let* (par-output-file + par-provider + par-size + par-data par-data-temp + par-data-min par-data-max + par-type + par-title + par-legends + par-google-raw + (here (point)) + token-before-pos + pos-state + (state 'need-label) + (problems + (catch 'problems + (save-restriction + ;;(widen) + (if want-pos-state + (unless (re-search-backward chartg-mode-keywords-re nil t) + (goto-char (point-min))) + (goto-char (point-min))) + (let (this-keyword + this-start + this-end + params + token + token-pos + next-token + found-labels + current-label) + (while (or token + (progn + (setq pos-state state) + (setq token-before-pos (point)) + (condition-case err + (setq token (read (current-buffer))) + (error + (if (eq (car err) 'end-of-file) + (unless (or (eq state 'need-label) + (member '(quote |) state)) + (throw 'problems (format "Unexpected end, state=%s" state))) + (throw 'problems + (error-message-string err))))))) + (message "token=%s, label=%s, state=%s" token current-label state) + (when (and want-pos-state + (>= (point) want-pos-state)) + (when (= (point) want-pos-state) + ;; right after item + (setq pos-state nil)) + (goto-char here) + (throw 'pos-state pos-state)) + (when (and (listp state) (memq 'number state)) + (unless (numberp token) + (save-match-data + (let ((token-str (format "%s" token))) + (setq token-str (replace-regexp-in-string "\\([0-9]\\),\\([0-9]\\)" "\\1\\2" token-str)) + (when (string-match-p "^[0-9]+$" token-str) + (setq token (string-to-number token-str))))))) + (cond ;; state + ;; Label + ((eq state 'need-label) + (unless (symbolp token) + (throw 'problems (format "Expected label, got %s" token))) + (unless (member (symbol-name token) + (append chartg-mode-keywords + chartg-extra-keywords + chartg-raw-keywords + nil)) + (throw 'problems (format "Unknown label %s" token))) + (when (member (symbol-name token) found-labels) + (throw 'problems (format "Label %s defined twice" token))) + (setq current-label token) + (setq found-labels (cons current-label found-labels)) + (setq token nil) + ;;(setq state 'need-value) + (case current-label + ('Output-file: + (setq state '(accept file-name))) + ('Size: + (setq state '(accept number))) + ('Data: + (setq state '(accept number))) + ('Type: + (setq state '(accept chartg-type))) + ('Chartg-title: + (setq state '(accept string))) + ('Legends: + (setq state '(accept string))) + ('Google-chartg-raw: + (setq state '(accept string))) + )) + ;;;; Values + ;; Alt + ((equal state '(accept '| symbol)) + (if (eq '| token) + (case current-label + ('Legends: + (setq token nil) + (setq state '(accept string))) + (t (error "internal error, current-label=%s, state=%s" current-label state))) + (if (symbolp token) + (progn + ;;(setq token nil) + (setq state 'need-label)) + (throw 'problems (format "Expected | or label, got %s" token))))) + ;; Strings + ((equal state '(accept string)) + (unless (stringp token) + (throw 'problems "Expected string")) + (case current-label + ('Chartg-title: + (setq par-title token) + (setq token nil) + (setq state 'need-label)) + ('Legends: + (setq par-legends (cons token par-legends)) + (setq token nil) + (setq state '(accept '| symbol))) + ('Google-chartg-raw: + (setq par-google-raw token) + (setq token nil) + (setq state 'need-label)) + (t (error "internal error, current-label=%s, state=%s" current-label state)))) + ;; Output file + ((equal state '(accept file-name)) + (unless (stringp token) + (throw 'problems "Expected file name string")) + (assert (eq current-label 'Output-file:)) + (setq par-output-file token) + (setq token nil) + (setq state 'need-label)) + ;; Numbers + ((equal state '(accept number)) + (unless (numberp token) + (throw 'problems "Expected number")) + (case current-label + ('Size: + (if (not par-size) + (progn + (setq par-size token) + (setq token nil) + (setq state '(accept number 'x 'X))) + (setq par-size (cons par-size token)) + (setq token nil) + (setq state 'need-label))) + ('Data: + ;;(assert (not par-data-temp)) + (setq par-data-temp (cons token par-data-temp)) + (setq par-data-min token) + (setq par-data-max token) + (setq token nil) + (setq state '(accept number ', '| symbol)) + ) + (t (error "internal error, state=%s, current-label=%s" state current-label))) + ) + ;; Numbers or | + ((equal state '(accept number ', '| symbol)) + (if (numberp token) + (progn + (setq par-data-min (if par-data-min (min par-data-min token) token)) + (setq par-data-max (if par-data-max (max par-data-max token) token)) + (setq par-data-temp (cons token par-data-temp)) + (message "par-data-min/max=%s/%s, token=%s -- %s" par-data-min par-data-max token par-data-temp) + (setq token nil)) + (if (eq ', token) + (setq token nil) + (if (or (eq '| token) + (symbolp token)) + (progn + (unless par-data-temp + (throw 'problems "Empty data set")) + (setq par-data (cons (list (reverse par-data-temp) (cons par-data-min par-data-max)) par-data)) + (setq par-data-temp nil) + (setq par-data-min nil) + (setq par-data-max nil) + (if (not (eq '| token)) + (setq state 'need-label) + (setq state '(accept number)) + (setq token nil))) + (throw 'problems "Expected | or EOF") + )))) + ;; Numbers or x/X + ((equal state '(accept number 'x 'X)) + (assert (eq current-label 'Size:)) + (let ((is-n (numberp token)) + (is-x (memq token '(x X)))) + (unless (or is-n is-x) + (throw 'problems "Expected X or number")) + (if is-x + (progn + (setq token nil) + (setq state '(accept number))) + (setq par-size (cons par-size token)) + (setq token nil) + (setq state 'need-label)))) + ;; Chart type + ((equal state '(accept chartg-type)) + (setq par-type token) + (unless (assoc par-type chartg-types) + (throw 'problems (format "Unknown chart type: %s" par-type))) + (setq token nil) + (setq state 'need-label)) + (t (error "internal error, state=%s" state)))))) + ;; fix-me here + + nil))) + (when want-pos-state + (goto-char here) + (throw 'pos-state state)) + (unless problems + (let ((missing-lab (chartg-missing-keywords))) + (when missing-lab + (setq problems (format "Missing required labels: %s" missing-lab))))) + (if problems + (let ((msg (if (listp problems) + (nth 1 problems) + problems)) + (where (if (listp problems) + (nth 0 problems) + token-before-pos))) + (goto-char where) + (skip-chars-forward " \t") + (error msg)) + (goto-char here) + ;;(defun chartg-create (out-file provider size data type &rest extras) + (setq par-provider 'google) + (setq par-legends (nreverse par-legends)) + (let ((extras nil)) + (when par-google-raw + (setq extras (cons (cons 'GOOGLE-RAW par-google-raw) extras))) + (chartg-create par-provider par-output-file par-size + par-data par-type par-title par-legends extras)) + nil))) + +;;;###autoload +(defun chartg-make-chart () + "Try to make a new chart. +If region is active then make a new chart from data in the +selected region. + +Else if current buffer is in `chartg-mode' then do it from the +chart specifications in this buffer. Otherwise create a new +buffer and initialize it with `chartg-mode'. + +If the chart specifications are complete enough to make a chart +then do it and show the resulting chart image. If not then tell +user what is missing. + +NOTE: This is beta, no alpha code. It is not ready. + +Below are some examples. To test them mark an example and do + + M-x chartg-make-chart + +* Example, simple x-y chart: + + Output-file: \"~/temp-chart.png\" + Size: 200 200 + Data: 3 8 5 | 10 20 30 + Type: line-chartg-xy + +* Example, pie: + + Output-file: \"~/temp-depression.png\" + Size: 400 200 + Data: + 2,160,000 + 3,110,000 + 1,510,000 + 73,600 + 775,000 + 726,000 + 8,180,000 + 419,000 + Type: pie-3-dimensional + Chartg-title: \"Depression hits on Google\" + Legends: + \"SSRI\" + | \"Psychotherapy\" + | \"CBT\" + | \"IPT\" + | \"Psychoanalysis\" + | \"Mindfulness\" + | \"Meditation\" + | \"Exercise\" + + +* Example, pie: + + Output-file: \"~/temp-panic.png\" + Size: 400 200 + Data: + 979,000 + 969,000 + 500,000 + 71,900 + 193,000 + 154,000 + 2,500,000 + 9,310,000 + Type: pie-3-dimensional + Chartg-title: \"Depression hits on Google\" + Legends: + \"SSRI\" + | \"Psychotherapy\" + | \"CBT\" + | \"IPT\" + | \"Psychoanalysis\" + | \"Mindfulness\" + | \"Meditation\" + | \"Exercise\" + + +* Example using raw: + + Output-file: \"~/temp-chartg-slipsen-kostar.png\" + Size: 400 130 + Data: 300 1000 30000 + Type: bar-chartg-horizontal + Chartg-title: \"Vad killen i slips tjänar jämfört med dig och mig\" + Google-chartg-raw: \"&chds=0,30000&chco=00cd00|ff4500|483d8b&chxt=y,x&chxl=0:|Killen+i+slips|Partiledarna|Du+och+jag&chf=bg,s,ffd700\" + + +" + (interactive) + (if mark-active + (let* ((rb (region-beginning)) + (re (region-end)) + (data (buffer-substring-no-properties rb re)) + (buf (generate-new-buffer "*Chart from region*"))) + (switch-to-buffer buf) + (insert data) + (chartg-mode)) + (unless (eq major-mode 'chartg-mode) + (switch-to-buffer (generate-new-buffer "*Chart*")) + (chartg-mode))) + (chartg-get-state nil)) + +;; (defun chartg-from-region (min max) +;; "Try to make a new chart from data in selected region. +;; See `chartg-mode' for examples you can test with this function." +;; (interactive "r") +;; (unless mark-active (error "No region selected")) +;; (let* ((rb (region-beginning)) +;; (re (region-end)) +;; (data (buffer-substring-no-properties rb re)) +;; (buf (generate-new-buffer "*Chart from region*"))) +;; (switch-to-buffer buf) +;; (insert data) +;; (chartg-mode) +;; (chartg-get-state nil))) + +(define-derived-mode chartg-mode fundamental-mode "Chart" + "Mode for specifying charts. +\\{chartg-mode-map} + +To make a chart see `chartg-make-chart'. + +" + (set (make-local-variable 'font-lock-defaults) chartg-font-lock-defaults) + (set (make-local-variable 'comment-start) ";") + ;; Look within the line for a ; following an even number of backslashes + ;; after either a non-backslash or the line beginning. + (set (make-local-variable 'comment-start-skip) + "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\);+ *") + ;; Font lock mode uses this only when it KNOWS a comment is starting. + (set (make-local-variable 'font-lock-comment-start-skip) ";+ *") + (set (make-local-variable 'comment-add) 1) ;default to `;;' in comment-region + (set (make-local-variable 'comment-column) 40) + ;; Don't get confused by `;' in doc strings when paragraph-filling. + (set (make-local-variable 'comment-use-global-state) t) + (set-syntax-table chartg-mode-syntax-table) + (when (looking-at (rx buffer-start (0+ whitespace) buffer-end)) + (insert ";; Type C-c C-c to make a chart, M-Tab to complete\n")) + (let ((missing (chartg-missing-keywords))) + (when missing + (save-excursion + (goto-char (point-max)) + (dolist (miss missing) + (insert "\n" miss " ")))))) + +;; Tests +;;(chartg-create 'google "temp.png" '(200 . 150) '(((90 70) . nil)) 'pie-3-dimensional "test title" nil '((colors "FFFFFF" "00FF00"))) + +;; Fix-me +(add-to-list 'auto-mode-alist '("\\.mx-chart\\'" . chartg-mode)) + +(provide 'chartg) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; chartg.el ends here diff --git a/emacs.d/nxhtml/util/css-color.el b/emacs.d/nxhtml/util/css-color.el new file mode 100644 index 0000000..38d400c --- /dev/null +++ b/emacs.d/nxhtml/util/css-color.el @@ -0,0 +1,983 @@ +;;; css-color.el --- Highlight and edit CSS colors + +(defconst css-color:version "0.03") +;; Copyright (C) 2008 Niels Giesen + +;; Author: Niels Giesen +;; Keywords: processes, css, extensions, tools +;; Some smaller changes made by Lennart Borgman + +;; Last-Updated: 2009-10-19 Mon + +;; 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 3 of the License, 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. If not, see . + +;;; Commentary: + +;; Edit css-colors in hex, rgb or hsl notation in-place, with +;; immediate feedback by font-locking. Cycle between color-spaces. + +;; Usage: + +;; (autoload 'css-color-mode "css-color" "" t) +;; (add-hook 'css-mode-hook 'css-color-mode-turn-on) + +;; Css-Css-color.el propertizes colours in a CSS stylesheet found by +;; font-locking code with a keymap. From that keymap, you can easily +;; adjust values such as red green and blue, hue, saturation and +;; value, or switch between different color (space) notations. + +;; It supports all 'css-colors', so hex, rgb(), hsl() and even HTML +;; color names (although I wouldn't use them myself, it is nice to be +;; able to quickly convert those), can be used and switched between. + +;; The rgb() notation can be expressed either in percentages or in +;; values between 0-255. + +;; You can cycle between the different formats (with SPACE), so that +;; it is possible to edit the color in hsl mode (which is more +;; intuitive than hsv, although hsv has its merits too), and switch +;; back to rgb or hex if so desired. + +;; With point on a color, the keys - and = to are bound to the down +;; and up functions for channels (or 'fields'). Toggling percentage +;; in rgb() is done with the % key (not sure if that is wise +;; though). The TAB key is bound to go to the next channel, cycling +;; when at the end. color.el propertizes the longhand hexcolours +;; found by the + +;; Caveats: + +;; Notation cycling can often introduce small errors inherent to +;; switching color spaces. Currently there is no check nor a warning +;; for that. + +;; ToDo: + +;; Try and fix those conversion inaccuracies. This cannot be done +;; completely I guess. But maybe we can check whether this has +;; occured, and then warn. + +;;; Change log: + +;; 2009-01-11 Lennart Borgman +;; - Minor code clean up. +;; 2009-05-23 Lennart Borgman +;; - Let bound m1 and m2. + +;;; Code: +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'mumamo nil t)) + +;;;###autoload +(defgroup css-color () + "Customization group for library `css-color'." + :group 'css + :group 'nxhtml) + +(defconst css-color-hex-chars "0123456789abcdefABCDEF" + "Composing chars in hexadecimal notation, save for the hash (#) sign.") + +(defconst css-color-hex-re + "#\\([a-fA-F[:digit:]]\\{6\\}\\|[a-fA-F[:digit:]]\\{3\\}\\)") + +(defconst css-color-hsl-re + "hsla?(\\([[:digit:]]\\{1,3\\}\\),[[:space:]]*\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*\\)\\)%,[[:space:]]*\\([[:digit:]]\\{1,3\\}\\)\\(?:\.?[[:digit:]]*\\)%)") + +(defconst css-color-rgb-re + "rgba?(\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*%\\)?\\),[[:space:]]*\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*%\\)?\\),[[:space:]]*\\([[:digit:]]\\{1,3\\}\\(?:\.?[[:digit:]]*%\\)?\\)\\(:?,[[:space:]]*\\(0\.[0-9]+\\|1\\)\\)?)") + +(defconst css-color-html-colors + '(("AliceBlue" "#F0F8FF") + ("AntiqueWhite" "#FAEBD7") + ("Aqua" "#00FFFF") + ("Aquamarine" "#7FFFD4") + ("Azure" "#F0FFFF") + ("Beige" "#F5F5DC") + ("Bisque" "#FFE4C4") + ("Black" "#000000") + ("BlanchedAlmond" "#FFEBCD") + ("Blue" "#0000FF") + ("BlueViolet" "#8A2BE2") + ("Brown" "#A52A2A") + ("BurlyWood" "#DEB887") + ("CadetBlue" "#5F9EA0") + ("Chartreuse" "#7FFF00") + ("Chocolate" "#D2691E") + ("Coral" "#FF7F50") + ("CornflowerBlue" "#6495ED") + ("Cornsilk" "#FFF8DC") + ("Crimson" "#DC143C") + ("Cyan" "#00FFFF") + ("DarkBlue" "#00008B") + ("DarkCyan" "#008B8B") + ("DarkGoldenRod" "#B8860B") + ("DarkGray" "#A9A9A9") + ("DarkGrey" "#A9A9A9") + ("DarkGreen" "#006400") + ("DarkKhaki" "#BDB76B") + ("DarkMagenta" "#8B008B") + ("DarkOliveGreen" "#556B2F") + ("Darkorange" "#FF8C00") + ("DarkOrchid" "#9932CC") + ("DarkRed" "#8B0000") + ("DarkSalmon" "#E9967A") + ("DarkSeaGreen" "#8FBC8F") + ("DarkSlateBlue" "#483D8B") + ("DarkSlateGray" "#2F4F4F") + ("DarkSlateGrey" "#2F4F4F") + ("DarkTurquoise" "#00CED1") + ("DarkViolet" "#9400D3") + ("DeepPink" "#FF1493") + ("DeepSkyBlue" "#00BFFF") + ("DimGray" "#696969") + ("DimGrey" "#696969") + ("DodgerBlue" "#1E90FF") + ("FireBrick" "#B22222") + ("FloralWhite" "#FFFAF0") + ("ForestGreen" "#228B22") + ("Fuchsia" "#FF00FF") + ("Gainsboro" "#DCDCDC") + ("GhostWhite" "#F8F8FF") + ("Gold" "#FFD700") + ("GoldenRod" "#DAA520") + ("Gray" "#808080") + ("Grey" "#808080") + ("Green" "#008000") + ("GreenYellow" "#ADFF2F") + ("HoneyDew" "#F0FFF0") + ("HotPink" "#FF69B4") + ("IndianRed" "#CD5C5C") + ("Indigo" "#4B0082") + ("Ivory" "#FFFFF0") + ("Khaki" "#F0E68C") + ("Lavender" "#E6E6FA") + ("LavenderBlush" "#FFF0F5") + ("LawnGreen" "#7CFC00") + ("LemonChiffon" "#FFFACD") + ("LightBlue" "#ADD8E6") + ("LightCoral" "#F08080") + ("LightCyan" "#E0FFFF") + ("LightGoldenRodYellow" "#FAFAD2") + ("LightGray" "#D3D3D3") + ("LightGrey" "#D3D3D3") + ("LightGreen" "#90EE90") + ("LightPink" "#FFB6C1") + ("LightSalmon" "#FFA07A") + ("LightSeaGreen" "#20B2AA") + ("LightSkyBlue" "#87CEFA") + ("LightSlateGray" "#778899") + ("LightSlateGrey" "#778899") + ("LightSteelBlue" "#B0C4DE") + ("LightYellow" "#FFFFE0") + ("Lime" "#00FF00") + ("LimeGreen" "#32CD32") + ("Linen" "#FAF0E6") + ("Magenta" "#FF00FF") + ("Maroon" "#800000") + ("MediumAquaMarine" "#66CDAA") + ("MediumBlue" "#0000CD") + ("MediumOrchid" "#BA55D3") + ("MediumPurple" "#9370D8") + ("MediumSeaGreen" "#3CB371") + ("MediumSlateBlue" "#7B68EE") + ("MediumSpringGreen" "#00FA9A") + ("MediumTurquoise" "#48D1CC") + ("MediumVioletRed" "#C71585") + ("MidnightBlue" "#191970") + ("MintCream" "#F5FFFA") + ("MistyRose" "#FFE4E1") + ("Moccasin" "#FFE4B5") + ("NavajoWhite" "#FFDEAD") + ("Navy" "#000080") + ("OldLace" "#FDF5E6") + ("Olive" "#808000") + ("OliveDrab" "#6B8E23") + ("Orange" "#FFA500") + ("OrangeRed" "#FF4500") + ("Orchid" "#DA70D6") + ("PaleGoldenRod" "#EEE8AA") + ("PaleGreen" "#98FB98") + ("PaleTurquoise" "#AFEEEE") + ("PaleVioletRed" "#D87093") + ("PapayaWhip" "#FFEFD5") + ("PeachPuff" "#FFDAB9") + ("Peru" "#CD853F") + ("Pink" "#FFC0CB") + ("Plum" "#DDA0DD") + ("PowderBlue" "#B0E0E6") + ("Purple" "#800080") + ("Red" "#FF0000") + ("RosyBrown" "#BC8F8F") + ("RoyalBlue" "#4169E1") + ("SaddleBrown" "#8B4513") + ("Salmon" "#FA8072") + ("SandyBrown" "#F4A460") + ("SeaGreen" "#2E8B57") + ("SeaShell" "#FFF5EE") + ("Sienna" "#A0522D") + ("Silver" "#C0C0C0") + ("SkyBlue" "#87CEEB") + ("SlateBlue" "#6A5ACD") + ("SlateGray" "#708090") + ("SlateGrey" "#708090") + ("Snow" "#FFFAFA") + ("SpringGreen" "#00FF7F") + ("SteelBlue" "#4682B4") + ("Tan" "#D2B48C") + ("Teal" "#008080") + ("Thistle" "#D8BFD8") + ("Tomato" "#FF6347") + ("Turquoise" "#40E0D0") + ("Violet" "#EE82EE") + ("Wheat" "#F5DEB3") + ("White" "#FFFFFF") + ("WhiteSmoke" "#F5F5F5") + ("Yellow" "#FFFF00") + ("YellowGreen" "#9ACD32"))) + +(defvar css-color-html-re + (concat "\\<\\(" + (funcall 'regexp-opt + (mapcar 'car css-color-html-colors)) + "\\)\\>")) + +(defconst + css-color-color-re + "\\(?:#\\(?:[a-fA-F[:digit:]]\\{6\\}\\|[a-fA-F[:digit:]]\\{3\\}\\)\\|hsl(\\(?:[[:digit:]]\\{1,3\\}\\),[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}\\)%,[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}\\)%)\\|rgba?(\\(?:[[:digit:]]\\{1,3\\}%?\\),[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}%?\\),[[:space:]]*\\(?:[[:digit:]]\\{1,3\\}%?\\)\\(?:,[[:space:]]*\\(?:0.[0-9]+\\|1\\)\\)?)\\)" + "Regular expression containing only shy groups matching any type of CSS color") + +;; (defconst css-color-color-re +;; (concat "\\(?1:" +;; (mapconcat +;; 'identity +;; (list css-color-hex-re +;; css-color-hsl-re +;; css-color-rgb-re) "\\|") +;; "\\)")) + +(defvar css-color-keywords + `((,css-color-hex-re + (0 + (progn + (when (= 7 (- (match-end 0) + (match-beginning 0))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-map)) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'hex) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + (match-string-no-properties 0) + :foreground + (css-color-foreground-color + (match-string-no-properties 0))))))) + (,css-color-html-re + (0 + (let ((color + (css-color-string-name-to-hex (match-string-no-properties 0)))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-generic-map) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'name) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + color + :foreground + (css-color-foreground-color + color)))))) + (,css-color-hsl-re + (0 + (let ((color (concat "#" (apply 'css-color-hsl-to-hex + (mapcar 'string-to-number + (list + (match-string-no-properties 1) + (match-string-no-properties 2) + (match-string-no-properties 3))))))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-generic-map) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'hsl) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + color + :foreground + (css-color-foreground-color + color)))))) + (,css-color-rgb-re + (0 + (let ((color (css-color-string-rgb-to-hex (match-string-no-properties 0)))) + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap css-color-generic-map) + (put-text-property (match-beginning 0) + (match-end 0) + 'css-color-type 'rgb) + (put-text-property (match-beginning 0) + (match-end 0) + 'rear-nonsticky t) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + color + :foreground + (css-color-foreground-color + color)))))))) + + +;;;###autoload +(define-minor-mode css-color-mode + "Show hex color literals with the given color as background. +In this mode hexadecimal colour specifications like #6600ff are +displayed with the specified colour as background. + +Certain keys are bound to special colour editing commands when +point is at a hexadecimal colour: + +\\{css-color-map}" + :initial-value nil + :group 'css-color + (unless font-lock-defaults + (error "Can't use css-color-mode for this major mode")) + (if css-color-mode + (progn + (unless font-lock-mode (font-lock-mode 1)) + (css-color-font-lock-hook-fun) + (add-hook 'font-lock-mode-hook 'css-color-font-lock-hook-fun nil t)) + (remove-hook 'font-lock-mode-hook 'css-color-font-lock-hook-fun t) + (font-lock-remove-keywords nil css-color-keywords)) + ;;(font-lock-fontify-buffer) + (save-restriction + (widen) + (mumamo-mark-for-refontification (point-min) (point-max)))) + +(put 'css-color-mode 'permanent-local t) + +(defun css-color-turn-on-in-buffer () + "Turn on `css-color-mode' in `css-mode'." + (when (derived-mode-p 'css-mode) + (css-color-mode 1))) + +;;;###autoload +(define-globalized-minor-mode css-color-global-mode css-color-mode + css-color-turn-on-in-buffer + :group 'css-color) + +(defun css-color-font-lock-hook-fun () + "Add css-color pattern to font-lock's." + (if font-lock-mode + (font-lock-add-keywords nil css-color-keywords t) + (css-color-mode -1))) + +(defvar css-color-map + (let ((m (make-sparse-keymap "css-color"))) + (define-key m "=" 'css-color-up) + (define-key m "-" 'css-color-down) + (define-key m "h" 'css-color-hue-up) + (define-key m "H" 'css-color-hue-down) + (define-key m "s" 'css-color-saturation-up) + (define-key m "S" 'css-color-saturation-down) + (define-key m "v" 'css-color-value-up) + (define-key m "V" 'css-color-value-down) + (define-key m "\t" 'css-color-next-channel) + (define-key m " " 'css-color-cycle-type) + m) + "Mode map for `css-color-minor-mode'") + +(defvar css-color-generic-map + (let ((m (make-sparse-keymap "css-color"))) + (define-key m "=" 'css-color-num-up) + (define-key m "-" 'css-color-num-down) + (define-key m " " 'css-color-cycle-type) + (define-key m "%" 'css-color-toggle-percentage) + (define-key m "\t" 'css-color-next-channel) + m) + "Mode map for simple numbers in `css-color-minor-mode'") + +(defun css-color-pal-lumsig (r g b) + "Return PAL luminance signal, but in range 0-255." + (+ + (* 0.3 r) + (* 0.59 g) + (* 0.11 b))) + +(defun css-color-foreground-color (hex-color) + (multiple-value-bind (r g b) (css-color-hex-to-rgb hex-color) + (if (< (css-color-pal-lumsig r g b) 128) + "#fff" + "#000"))) + +;; Normalizing funs +(defun css-color-normalize-hue (h) + (mod (+ (mod h 360) 360) 360)) + +(defun css-color-within-bounds (num min max) + (min (max min num) max)) + +;; Source: hex +(defun css-color-hex-to-rgb (str) + (cond + ((not (string-match "^#?[a-fA-F[:digit:]]*$" str)) + (error "No valid hexadecimal: %s" str)) + ((= 0 (length str)) + nil) + ((= (aref str 0) 35) + (css-color-hex-to-rgb (substring str 1))) + (;;(oddp (length str)) + (= (mod (length str) 2) 1) + (css-color-hex-to-rgb (mapconcat (lambda (c) + (make-string 2 c)) + (string-to-list str) ""))) + (t (cons (string-to-number (substring str 0 2) 16) + (css-color-hex-to-rgb (substring str 2)))))) + +(defun css-color-hex-to-hsv (hex) + (multiple-value-bind (r g b) (css-color-hex-to-rgb hex) + (css-color-rgb-to-hsv r g b))) + +;; Source: rgb +(defun css-color-rgb-to-hex (r g b) + "Return r g b as #rrggbb in hexadecimal, propertized to have +the keymap `css-color-map'" + (format "%02x%02x%02x" r g b)) ;val + +(defun css-color-rgb-to-hsv (r g b) + "Return list of (hue saturation value). +Arguments are: R = red; G = green; B = blue. +Measure saturation and value on a scale from 0 - 100. +GIMP-style, that is." + (let* ((r (float r)) + (g (float g)) + (b (float b)) + (max (max r g b)) + (min (min r g b))) + (values + (round + (cond ((and (= r g) (= g b)) 0) + ((and (= r max) + (>= g b)) + (* 60 (/ (- g b) (- max min)))) + ((and (= r max) + (< g b)) + (+ 360 (* 60 (/ (- g b) (- max min))))) + ((= max g) + (+ 120 (* 60 (/ (- b r) (- max min))))) + ((= max b) + (+ 240 (* 60 (/ (- r g) (- max min))))))) ;hue + (round (* 100 (if (= max 0) 0 (- 1 (/ min max))))) ;sat + (round (/ max 2.55))))) + +(defun css-color-rgb-to-hsl (r g b) + "Return R G B (in range 0-255) converted to HSL (0-360 for hue, rest in %)" + (let* ((r (/ r 255.0)) + (g (/ g 255.0)) + (b (/ b 255.0)) + (h 0) + (s 0) + (l 0) + (v (max r g b)) + (m (min r g b)) + (l (/ (+ m v) 2.0)) + (vm 0) + (r2 0) + (g2 0) + (b2 0)) + (multiple-value-bind (h s v) + (if (<= l 0) + (values h s l) + (setq vm (- v m) + s vm) + (if (>= 0 s) + (values h s l) + (setq s (/ s (if (<= l 0.5) + (+ v m) + (- 2.0 v m)))) + (if (not (= 0 vm)) + (setq r2 (/ (- v r) vm) + g2 (/ (- v g) vm) + b2 (/ (- v b) vm))) + (cond ((= r v) + (setq h (if (= g m) + (+ 5.0 b2) + (- 1.0 g2)))) + ((= g v) + (setq h (if (= b m) + (+ 1.0 r2) + (- 3.0 b2)))) + (t + (setq h (if (= r m) + (+ 3.0 g2) + (- 5.0 r2))))) + (values (/ h 6.0) s l))) + (list (round(* 360 h)) + (* 100 s) + (* 100 l))))) + +;; Source: hsv +(defun css-color-hsv-to-hsl (h s v) + (multiple-value-bind (r g b) (css-color-hsv-to-rgb h s v) + (css-color-rgb-to-hsl r g b))) + +(defun css-color-hsv-to-hex (h s v) + (apply 'css-color-rgb-to-hex (css-color-hsv-to-rgb h s v))) + +(defun css-color-hsv-to-rgb (h s v) + "Convert a point in the Hue, Saturation, Value (aka Brightness) +color space to list of normalized Red, Green, Blue values. + +HUE is an angle in the range of 0 degrees inclusive to 360 +exclusive. The remainder of division by 360 is used for +out-of-range values. +SATURATION is in the range of 0 to 100. +VALUE is in the range of 0 to 100. +Returns a list of values in the range of 0 to 255. +" + ;; Coerce to float and get hue into range. + (setq h (mod h 360.0) + s (/ (float s) 100) + v (/ (float v) 100)) + (let* ((hi (floor h 60.0)) + (f (- (/ h 60.0) hi)) + (p (* v (- 1.0 s))) + (q (* v (- 1.0 (* f s)))) + ;; cannot use variable t, obviously. + (u (* v (- 1.0 (* (- 1.0 f) s)))) + r g b) + (case hi + (0 (setq r v g u b p)) + (1 (setq r q g v b p)) + (2 (setq r p g v b u)) + (3 (setq r p g q b v)) + (4 (setq r u g p b v)) + (5 (setq r v g p b q))) + (mapcar (lambda (color) (round (* 255 color))) (list r g b)))) + +(defun css-color-hsv-to-prop-hexstring (color-data) + (propertize + (apply 'css-color-hsv-to-hex color-data) + 'keymap css-color-map + 'css-color color-data)) + +;; Source: hsl +(defun css-color-hsl-to-rgb-fractions (h s l) + (let (m1 m2) + (if (<= l 0.5) + (setq m2 (* l (+ s 1))) + (setq m2 (- (+ l s) (* l s)))) + (setq m1 (- (* l 2) m2)) + (values (css-color-hue-to-rgb m1 m2 (+ h (/ 1 3.0))) + (css-color-hue-to-rgb m1 m2 h) + (css-color-hue-to-rgb m1 m2 (- h (/ 1 3.0)))))) + +(defun css-color-hsl-to-rgb (h s l) + (multiple-value-bind (r g b) + (css-color-hsl-to-rgb-fractions + (/ h;; (css-color-normalize-hue h) + 360.0) + (/ s 100.0) + (/ l 100.0)) + (values (css-color-within-bounds (* 256 r) 0 255) + (css-color-within-bounds (* 256 g) 0 255) + (css-color-within-bounds (* 256 b) 0 255)))) + +(defun css-color-hsl-to-hex (h s l) + (apply 'css-color-rgb-to-hex + (css-color-hsl-to-rgb h s l))) + +(defun css-color-hue-to-rgb (x y h) + (when (< h 0) (incf h)) + (when (> h 1) (decf h)) + (cond ((< h (/ 1 6.0)) + (+ x (* (- y x) h 6))) + ((< h 0.5) y) + ((< h (/ 2.0 3.0)) + (+ x (* (- y x) (- (/ 2.0 3.0) h) 6))) + (t x))) + +(defun css-color-parse-hsl (str) + (string-match + css-color-hsl-re + str) + (mapcar 'string-to-number + (list + (match-string 1 str) + (match-string 2 str) + (match-string 3 str)))) + +(defun css-color-inchue (color incr) + (multiple-value-bind (h s v) color + (css-color-hsv-to-prop-hexstring + (list (+ incr h) s v)))) + +(defun css-color-incsat (color incr) + (multiple-value-bind (h s v) color + (css-color-hsv-to-prop-hexstring + (list h (css-color-within-bounds (+ incr s) 0 100) v)))) + +(defun css-color-incval (color incr) + (multiple-value-bind (h s v) color + (css-color-hsv-to-prop-hexstring + (list h s (css-color-within-bounds (+ incr v) 0 100))))) + +(defun css-color-hexval-beginning () + (skip-chars-backward css-color-hex-chars) + (if (= (char-after) 35) + (forward-char 1))) + +(defun css-color-replcolor-at-p (fun increment) + (let ((pos (point))) + (css-color-hexval-beginning) + (insert + (funcall fun + (css-color-get-color-at-point) + increment)) + (delete-region (point) (+ (point) 6)) + (goto-char pos))) + +(defun css-color-get-color-at-point () + (save-excursion + (css-color-hexval-beginning) + (let ((saved-color (get-text-property (point) 'css-color))) + (or saved-color + (css-color-hex-to-hsv + (buffer-substring-no-properties (point) (+ (point) 6))))))) + +(defun css-color-adj-hue-at-p (increment) + (interactive "p") + (css-color-replcolor-at-p 'css-color-inchue increment)) + +(defun css-color-adj-saturation-at-p (increment) + (interactive "p") + (css-color-replcolor-at-p 'css-color-incsat increment)) + +(defun css-color-adj-value-at-p (increment) + (interactive "p") + (css-color-replcolor-at-p 'css-color-incval increment)) + +(defun css-color-what-channel () + (let ((pos (point))) + (prog1 + (/ (skip-chars-backward css-color-hex-chars) -2) + (goto-char pos)))) + +(defun css-color-adjust-hex-at-p (incr) + (interactive "p") + (let ((pos (point)) + (channel (css-color-what-channel))) + (css-color-hexval-beginning) + (let ((rgb + (css-color-hex-to-rgb + (buffer-substring-no-properties (point) + (+ 6 (point)))))) + (setf (nth channel rgb) + (css-color-within-bounds + (+ incr (nth channel rgb)) + 0 255)) + (delete-region (point) (+ 6 (point))) + (insert + (propertize + (apply 'format "%02x%02x%02x" rgb) + 'keymap css-color-map + 'css-color nil + 'rear-nonsticky t))) + (goto-char pos))) + +;; channels (r, g, b) +(defun css-color-up (val) + "Adjust R/G/B up." + (interactive "p") + (css-color-adjust-hex-at-p val)) + +(defun css-color-down (val) + "Adjust R/G/B down." + (interactive "p") + (css-color-adjust-hex-at-p (- val))) +;; hue +(defun css-color-hue-up (val) + "Adjust Hue up." + (interactive "p") + (css-color-adj-hue-at-p val)) + +(defun css-color-hue-down (val) + "Adjust Hue down." + (interactive "p") + (css-color-adj-hue-at-p (- val))) +;; saturation +(defun css-color-saturation-up (val) + "Adjust Saturation up." + (interactive "p") + (css-color-adj-saturation-at-p val)) + +(defun css-color-saturation-down (val) + "Adjust Saturation down." + (interactive "p") + (css-color-adj-saturation-at-p (- val))) +;; value +(defun css-color-value-up (val) + "Adjust Value up." + (interactive "p") + (css-color-adj-value-at-p val)) + +(defun css-color-value-down (val) + "Adjust Value down." + (interactive "p") + (css-color-adj-value-at-p (- val))) + +(defun css-color-num-up (arg) + "Adjust HEX number up." + (interactive "p") + (save-excursion + (let ((digits "1234567890")) + (skip-chars-backward digits) + (when + (looking-at "[[:digit:]]+") + (replace-match + (propertize + (let ((num (+ (string-to-number (match-string 0)) arg))) + ;max = 100 when at percentage + (save-match-data + (cond ((looking-at "[[:digit:]]+%") + (setq num (min num 100))) + ((looking-back "hsla?(") + (setq num (css-color-normalize-hue num))) + ((memq 'css-color-type (text-properties-at (point))) + (setq num (min num 255))))) + (number-to-string num)) + 'keymap + css-color-generic-map)))))) + +(defun css-color-num-down (arg) + "Adjust HEX number down." + (interactive "p") + (save-excursion + (let ((digits "1234567890")) + (skip-chars-backward digits) + (when + (looking-at "[[:digit:]]+") + (replace-match + (propertize + (let ((num (- (string-to-number (match-string 0)) arg))) + ;max = 100 when at percentage + (save-match-data + (cond ((looking-back "hsla?(") + (setq num (css-color-normalize-hue num))) + (t (setq num (max 0 num))))) + (number-to-string num)) + 'keymap css-color-generic-map)))))) + + +(defun css-color-beginning-of-color () + "Skip to beginning of color. + +Return list of point and color-type." + (while (memq 'css-color-type (text-properties-at (point))) + (backward-char 1)) + (forward-char 1) + (cons (point) (plist-get (text-properties-at (point)) 'css-color-type))) + +(defun css-color-end-of-color () + "Skip to beginning of color. + +Return list of point and color-type." + (while (plist-get (text-properties-at (point)) 'css-color-type) + (forward-char 1)) + (cons (point) (plist-get (text-properties-at (1- (point))) 'css-color-type))) + +(defun css-color-color-info () + (destructuring-bind ((beg . type) + (end . type)) + (list + (css-color-beginning-of-color) + (css-color-end-of-color)) + (list beg end type (buffer-substring-no-properties beg end)))) + +(defconst css-color-type-circle '#1=(hex hsl rgb name . #1#)) + +(defun css-color-next-type (sym) + (cadr (member sym css-color-type-circle))) + +(defun css-color-cycle-type () + "Cycle color type." + (interactive) + (destructuring-bind (beg end type color) (css-color-color-info) + (if (or (= 0 (length color)) (null type)) + (error "Not at color")) + (delete-region beg end) + (insert + (propertize (funcall + (intern-soft (format "css-color-string-%s-to-%s" + type + (css-color-next-type type))) + color) + 'keymap (if (eq (css-color-next-type type) 'hex) + css-color-map + css-color-generic-map) 'rear-nonsticky t)) + (goto-char beg))) + +(defun css-color-string-hex-to-hsl (str) + (multiple-value-bind (h s l) + (apply 'css-color-rgb-to-hsl + (css-color-hex-to-rgb str)) + (format "hsl(%d,%d%%,%d%%)" + h s l))) + +(defun css-color-string-hsl-to-rgb (str) + (multiple-value-bind (h s l) + (css-color-parse-hsl str) + (apply 'format + "rgb(%d,%d,%d)" + (mapcar 'round (css-color-hsl-to-rgb h s l))))) + +(defun css-color-string-rgb-to-name (str) + (let ((color (css-color-string-rgb-to-hex str))) + (or (car (rassoc (list (upcase color)) css-color-html-colors)) ;if name ok + color))) ;else return hex + +(defun css-color-string-name-to-hex (str) + (let ((str (downcase str))) + (cadr (assoc-if + (lambda (a) + (string= + (downcase a) + str)) + css-color-html-colors)))) + +(defun css-color-string-rgb-to-hex (str) + (save-match-data + (string-match css-color-rgb-re str) + (concat "#" + (apply 'css-color-rgb-to-hex + (mapcar + ;;'string-to-number + (lambda (s) + (if (= (aref s (1- (length s))) ?\%) + (round (* (string-to-number s) 2.55)) + (string-to-number s))) + (list + (match-string-no-properties 1 str) + (match-string-no-properties 2 str) + (match-string-no-properties 3 str))))))) + +(defun css-color-string-hsl-to-hex (str) + (concat "#" (apply 'css-color-hsl-to-hex (css-color-parse-hsl str)))) + +(defun css-color-next-channel () + "Cycle color channel." + (interactive) + (multiple-value-bind (beg end type color) + (save-excursion (css-color-color-info)) + (case type + ((hsl rgb) + (if (not (re-search-forward ",\\|(" end t)) + (goto-char (+ beg 4)))) + (hex + (cond ((> (point) (- end 3)) + (goto-char (+ 1 beg))) + ((= (char-after) 35) + (forward-char 1)) + ((evenp (- (point) beg)) + (forward-char 1)) + (t (forward-char 2))))))) + +(defun css-color-hexify-anystring (str) + (cond ((string-match "^hsl" str) + (css-color-string-hsl-to-hex str)) + ((string-match "^rgb" str) + (css-color-string-rgb-to-hex str)) + (t str))) + +(defun css-color-toggle-percentage () + "Toggle percent ??" + (interactive) + (let ((pos (point))) + (if (eq (nth 2 (save-excursion (css-color-color-info))) 'rgb) + (let ((chars "%1234567890.")) + (skip-chars-backward chars) + (when + (looking-at "[[:digit:]]+\\(?:\.?[[:digit:]]*%\\)?%?") + (let ((s (match-string 0))) + (replace-match + (propertize + (if (= (aref s (1- (length s))) ?\%) + (number-to-string (round (* (string-to-number s) 2.55))) + (format "%d%%" (/ (string-to-number s) 2.55))) + 'keymap css-color-generic-map + 'rear-nonsticky t))) + ;;(goto-char pos) + )) + (message "No toggling at point.")))) + +;; provide some backwards-compatibility to hexcolor.el: +(defvar css-color-fg-history nil) +(defvar css-color-bg-history nil) + +;;;###autoload +(defun css-color-test (fg-color bg-color) + "Test colors interactively. +The colors are displayed in the echo area. You can specify the +colors as any viable css color. Example: + + red + #f00 + #0C0 + #b0ff00 + hsla(100, 50%, 25%) + rgb(255,100,120)" + (interactive (list (completing-read "Foreground color: " + css-color-html-colors + nil nil nil nil css-color-fg-history) + (completing-read "Background color: " + css-color-html-colors + nil nil nil nil css-color-bg-history))) + (let* ((s (concat " Foreground: " fg-color ", Background: " bg-color " "))) + (put-text-property 0 (length s) + 'face (list + :foreground (css-color-hexify-anystring fg-color) + :background (css-color-hexify-anystring bg-color)) + s) + (message "Here are the colors: %s" s))) + +(defun css-color-run-tests () + (interactive) + (unless + (progn + (assert + (string= (css-color-string-hex-to-hsl "#ffff00") "hsl(60,100%,50%)")) + (assert + (string= (css-color-string-rgb-to-hex "rgb(255, 50%, 0)")"#ff7f00")) + (assert + (string= (css-color-string-hsl-to-rgb "hsl(60, 100%, 50%)") "rgb(255,255,0)")) + (assert + (string= (css-color-string-hsl-to-hex "hsl(60, 100%, 50%)") "#ffff00"))) + (message "All tests passed"))) + +(provide 'css-color) +;;; css-color.el ends here diff --git a/emacs.d/nxhtml/util/css-palette.el b/emacs.d/nxhtml/util/css-palette.el new file mode 100644 index 0000000..44287be --- /dev/null +++ b/emacs.d/nxhtml/util/css-palette.el @@ -0,0 +1,471 @@ +;;; css-palette.el + +(defconst css-palette:version "0.02") +;; Copyright (C) 2008 Niels Giesen + +;; Author: Niels Giesen +;; Keywords: processes, css, multimedia, extensions, tools +;; Homepage: http://niels.kicks-ass.org/ + +;; 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 3 of the License, 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. If not, see . + +;;; Commentary: + +;; css-palette defines commands to have "palettes" inside a block +;; comment to circumvent the absence of (color or other) variable +;; definitions in the CSS specification. It can import and export GIMP +;; color palettes. See the documentation of `css-palette-mode' +;; for details of usage. + +;;; Installation: + +;; Something like: + +;; put it in your load-path. + +;; (autoload 'css-palette-mode "css-palette" "" t) +;; (add-hook 'css-mode-hook +;; (lambda () +;; (css-palette-mode t))) + +;; Notes: + +;; css-palette depends on css-color.el to do font-locking. + +;; ccs-palette is orthogonal to css-mode, so it could probably be used +;; inside other language modes, provided they support multiline block +;; comments. + +;;; Change log: + +;; 2009-01-11 Lennart Borgman +;; - Minor code clean up. + +;;; Code: +(require 'css-color) +(eval-when-compile (require 'cl)) ;i'm a bad bad boy... + +(defconst css-palette-hex-chars "0123456789abcdefABCDEF" + "Composing chars in hexadecimal notation, save for the hash (#) sign.") + +(defvar css-palette-mode-map + (let ((m (make-sparse-keymap))) + (define-key m "\C-c\C-c" 'css-palette-update-all) + (define-key m "\C-c\C-i" 'css-palette-insert-reference) + (define-key m "\C-c\C-p" 'css-palette-import-from-GIMP) + (define-key m "\C-c\C-f" 'css-palette-insert-files) + m) + "Mode map for `css-palette-mode'") + +;;;###autoload +(define-minor-mode css-palette-mode + "Minor mode for palettes in CSS. + +The mode `css-palette-mode' acts on the first COLORS declaration in your + file of the form: + +COLORS: +\( +c0 \"#6f5d25\" ;tainted sand +c1 \"#000000\" ;Black +c2 \"#cca42b\" ;goldenslumber +c3 \"#6889cb\" ;far off sky +c4 \"#fff\" ;strange aeons +) + +Such declarations should appear inside a block comment, in order + to be parsed properly by the LISP reader. + +Type \\[css-palette-update-all], and any occurence of + + color: #f55; /*[c3]*/ + +will be updated with + + color: #6899cb; /*[c3]*/ + +The following commands are available to insert key-value pairs + and palette declarations: + \\{css-palette-mode-map} + +You can extend or redefine the types of palettes by defining a + new palette specification of the form (PATTERN REGEXP + REF-FOLLOWS-VALUE), named according to the naming scheme + css-palette:my-type, where + +PATTERN is a pattern containing two (%s) format directives which + will be filled in with the variable and its value, + +REGEXP is a regular expression to match a value - variable + pattern, + +and REF-FOLLOWS-VALUE defined whether or not the reference comes + after the value. This allows for more flexibility. + +Note that, although the w3c spec at URL + `http://www.w3.org/TR/CSS2/syndata.html#comments' says that + comments \" may occur anywhere between tokens, and their + contents have no influence on the rendering\", Internet + Explorer does not think so. Better keep all your comments after + a \"statement\", as per the default. This means `css-palette' + is ill-suited for use within shorthands. + +See variable `css-palette:colors' for an example of a palette + type. + +The extension mechanism means that palette types can be used to + contain arbitrary key-value mappings. + +Besides the colors palette, css-palette defines the palette + definition variables `css-palette:colors-outside' and + `css-palette:files', for colors with the reference outside and + for file url()'s respectively. + +You can fine-control which palette types css-palette should look + at via the variable `css-palette-types'. + +" + nil + "-palette" + css-palette-mode-map + (css-color-mode +1)) + +;;;###autoload +(defgroup css-palette nil + "Customization group for css-palette library. + +See function `css-palette-mode' for documentation" + :group 'css-color) + +(defcustom css-palette:colors + `("%s; /*[%s]*/ " + ,(concat "\\(" + css-color-color-re +;; (mapconcat +;; 'identity +;; (list css-color-hex-re +;; css-color-hsl-re +;; css-color-rgb-re) "\\|") + "\\)" + "[[:space:]]*;[[:space:]]*\/\\*\\[\\([^[:space:]]+\\)\\]\\*\/") + t) + "Color palette specification. + +See function `css-palette-mode' for documentation" + :group 'css-palette + :type '(list + (string :tag "Pattern") + (regexp :tag "Regexp") + (boolean :tag "Reversed"))) + +(defcustom css-palette:files + '("url(%s); /*[%s]*/ " + "url(\\([^)]+\\))[[:space:]]*;[[:space:]]*\/\\*\\[\\([^[:space:]]+\\)\\]\\*\/" + t) + "File palette specification. + +See function `css-palette-mode' for documentation" + :group 'css-palette + :type '(list + (string :tag "Pattern") + (regexp :tag "Regexp") + (boolean :tag "Reversed"))) + +(defcustom css-palette-types + '(colors) + "List of palette types to check for in buffer. + +See function `css-palette-mode' for documentation" + :group 'css-palette + :type '(repeat (symbol :tag "Palette type"))) +(make-variable-buffer-local 'css-palette-types) + +;; (defun css-palette-mode-turn-on () +;; "Turn on `css-palette-mode'." +;; (css-palette-mode 1)) + +;; ;;;###autoload +;; (defcustom css-palette-mode-activate-p nil +;; "Start `css-palette-mode' when `css-mode' is activated." +;; :group 'css-palette +;; :set (lambda (sym val) +;; (set-default sym val) +;; (if val +;; (add-hook 'css-mode-hook 'css-palette-mode-turn-on) +;; (remove-hook 'css-mode-hook 'css-palette-mode-turn-on))) +;; :type 'boolean) + +(defun css-palette-turn-on-in-buffer () + "Turn on `css-palette-mode' in `css-mode'." + (when (derived-mode-p 'css-mode) + (message "turn-on-in-b:before (css-palette-mode 1) cb=%s" (current-buffer)) + (css-palette-mode 1) + (message "turn-on-in-b:after (css-palette-mode 1)") + )) + +;;;###autoload +(define-globalized-minor-mode css-palette-global-mode css-palette-mode + css-palette-turn-on-in-buffer + :group 'css-color) + +(defun css-palette-get (key spec) + (plist-get + (css-palette-spec-to-plist + (symbol-value + (intern-soft + (format "css-palette:%s" spec)))) key)) + +(defun css-palette-spec-to-plist (palette) + (destructuring-bind (pattern regexp ref-follows-value) palette + (list :regexp regexp + :pattern pattern + :ref-follows-value ref-follows-value))) + +(defun css-palette-choose-type () + (intern-soft + (if (null (cdr css-palette-types)) + (car css-palette-types) + (completing-read "Type: " + (mapcar 'symbol-name css-palette-types))))) + +(defun css-palette-get-declaration (type) + "Return `css-palette' declaration of TYPE in current buffer. + +If none is found, throw an error." + (let ((type (symbol-name type))) + (save-excursion + (goto-char (point-min)) + (or (re-search-forward (format "%s:" + (upcase type)) nil t) + (error "No %s declaration found in buffer; check value of variable + `css-palette-types'" type)) + (let ((palette (read (current-buffer)))) + ;; Check (could be better..) + (if (not (and + (listp palette) + (= 0 (% (length palette) 2)))) + (error "Invalid %s " type)) + palette)))) + +(defun css-palette-update (type) +"Update buffer references for palette of TYPE." + (interactive (list + (css-palette-choose-type))) + (let ((palette (css-palette-get-declaration type)) + (regexp (css-palette-get :regexp type)) + (ref-follows-value (css-palette-get :ref-follows-value type))) + (flet ((getval (key palette) + (let ((value (plist-get palette (intern-soft key)))) + (if (null value) + (error + "%S not specified in %S palette " + key + type + ;; (signal 'css-palette-not-found-error nil) + ) + value)))) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward + regexp + (point-max) t) + (replace-match + (getval (match-string-no-properties (if ref-follows-value 2 1)) palette) + nil nil nil (if ref-follows-value 1 2)))))) + (css-color-mode 1)) + +(defun css-palette-update-all () + "Update all references for palettes in `css-palette-types'" + (interactive) + (catch 'err + (mapc (lambda (type) + (condition-case err + (css-palette-update type) + (if (y-or-n-p (format "%s, skip? " err)) + nil))) + css-palette-types))) + +;; Reference Insertion +(defun css-palette-insert-reference (type) + "Insert `css-palette' reference of TYPE at point." + (interactive + (list (css-palette-choose-type))) + (let* ((palette (css-palette-get-declaration type)) + (ref-follows-value (css-palette-get :ref-follows-value type)) + (pattern (css-palette-get :pattern type)) + (var + (completing-read (format "%s variable: " + (capitalize + (substring (symbol-name type) + 0 -1))) + (loop for i on + palette + by 'cddr + collect + (css-palette-colorify + (symbol-name (car i)) + (cadr i))))) + (val (plist-get palette (read var)))) + (insert (apply 'format + pattern + (if ref-follows-value + (list val var) + (list var val)))) + (css-color-mode +1))) + +(defun css-palette-hex-color-p (str) + (string-match "#\\([a-fA-F[:digit:]]\\{6\\}\\|[a-fA-F[:digit:]]\\{3\\}\\)" str)) + +(defun css-palette-colorify (string color) + (let ((color (if (css-palette-hex-color-p color) + color + "#000"))) + (propertize string + 'font-lock-face + (list :background color + :foreground (css-color-foreground-color color) + string) + 'fontified t))) + +;; Imports +(defun css-palette-from-existing-colors () + (interactive) + (let ((palette) + (count -1)) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "#[[:digit:]a-fA-F]\\{6\\}\\>" nil t) + (if (not (member (match-string-no-properties 0) palette)) + (setq palette (append (list + (match-string-no-properties 0) + (intern(format "c%d" (incf count)))) + palette))) + (save-match-data (re-search-forward ";" nil t)) + (insert (format "/*[%S]*/" (cadr (member (match-string-no-properties 0) palette)))))) + (insert (format "COLORS:\n%S" (nreverse palette))) + (forward-sexp -1) + (forward-char 1) + (while + (not (looking-at ")")) + (forward-sexp 2) + (newline) + (indent-for-tab-command)))) + +(defun css-palette-newest-GIMP-dir () + "Return newest (version-wise) ~/.gimp-n.n/palettes directory on disk. + +Return `nil' if none such directory is found." + (catch 'none + (concat + (or + (car + (last + (directory-files "~/" t "^.gimp-[[:digit:].]\\{3,\\}"))) + (throw 'none ())) + "/palettes/"))) + +(defun css-palette-import-from-GIMP () + "Import GIMP palette file as a `css-palette' palette. + +GIMP palettes can be made with the GIMP or on-line tools such as +found at URL `http://colourlovers.com'." + (interactive) + (let ((file (read-file-name "File: " (css-palette-newest-GIMP-dir))) + (this-buffer (current-buffer)) + (count -1)) + (insert "\nCOLORS:\n(\n") + (with-temp-buffer + (insert-file-contents file) + (goto-char (point-min)) + (while (re-search-forward + (concat + "^" + "[[:space:]]*\\([[:digit:]]+\\)" ;red + "[[:space:]]+\\([[:digit:]]+\\)" ;green + "[[:space:]]+\\([[:digit:]]+\\)" ;blue + "[[:space:]]+\\(.*\\)$") ;name (=> used as comment) + nil t) + (destructuring-bind (rb re gb ge bb be nb ne &rest ignore) + (cddr (match-data t)) + (let ((color + (apply 'format "c%d \"#%02x%02x%02x\" ;%s\n" + (incf count) + (append + (mapcar 'string-to-number + (list + (buffer-substring-no-properties rb re) + (buffer-substring-no-properties gb ge) + (buffer-substring-no-properties bb be))) + (list (buffer-substring-no-properties nb ne)))))) + (with-current-buffer this-buffer + (insert color)))))) + (insert ")") + (message "C-c C-c to update colors"))) + +(defun css-palette-insert-files (dir) + "Insert a `css-palette' declaration for all files in DIR. + +Filenames are relative. +Main use-case: an image directory." + (interactive "DDirectory: ") + (save-excursion + (let ((image-count -1)) + (insert "\nFILES:\n(\n") + (mapc + (lambda (f) + (insert + (format "file-%d %S\n" + (incf image-count) + (file-relative-name + f + (file-name-directory (buffer-file-name)))))) + (directory-files dir t "...+")) + (insert ")\n\n")))) + +;; Exports +(defun css-palette-export-to-GIMP (type name columns) + "Export the COLORS declaration to a GIMP (.gpl) palette. + +See also `gpl-mode' at URL +`http://niels.kicks-ass.org/public/elisp/gpl.el'." + (interactive + (list + (css-palette-choose-type) + (read-string "Name: ") + (read-number "Number of columns: " 2))) + (let ((palette (css-palette-get-declaration type))) + (find-file + (concat (css-palette-newest-GIMP-dir) + name + ".gpl")) + (insert + (format "GIMP Palette +Name: %s +Columns: %d +# +" name columns)) + (loop for i on palette + by 'cddr + do + (multiple-value-bind (r g b)(css-color-hex-to-rgb + (css-color-hexify-anystring (cadr i))) + (insert (format "%3d %3d %3d\t%s\n" + r g b + (car i)))))) + (if (featurep 'gpl) + (gpl-mode))) + +(provide 'css-palette) +;; css-palette.el ends here diff --git a/emacs.d/nxhtml/util/css-simple-completion.el b/emacs.d/nxhtml/util/css-simple-completion.el new file mode 100644 index 0000000..95bf27b --- /dev/null +++ b/emacs.d/nxhtml/util/css-simple-completion.el @@ -0,0 +1,238 @@ +;;; css-simple-completion.el --- Partly context aware css completion +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-11-22 Sun +;; Version: +;; Last-Updated: 2009-11-22 Sun +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Simple partly context aware completion. Context is based on +;; guessing mainly. +;; +;; This can be combined with with flymake-css.el that can check the +;; syntax. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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 3, 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: + +;; Fix-me: bad structure, does not fit completion frameworks +(defun css-simple-completing-w-pred (regexp matnum prompt collection) + (let (pre start len) + (when (looking-back regexp (line-beginning-position) t) + (setq pre (downcase (match-string matnum))) + (setq len (length pre)) + (setq start (match-beginning matnum)) + (unless (try-completion pre collection) + (throw 'result nil)) + (throw 'result (list start + (completing-read prompt + collection + (lambda (alt) + (and (>= (length alt) len) + (string= pre + (substring alt 0 len)))) + t + pre)))))) + +(defun css-simple-complete () + "Try to complete at current point. +This tries to complete keywords, but no CSS values. + +This is of course a pity since the value syntax is a bit +complicated. However you can at least check the syntax with +flymake-css if you want to." + (interactive) + (let ((context (css-simple-guess-context)) + result + cur + pre + start) + (setq result + (catch 'result + + (case context + + ( 'css-media-ids + (css-simple-completing-w-pred "\\<[a-z0-9-]*" 0 "Media type: " css-media-ids)) + + ( 'css-at-ids + (css-simple-completing-w-pred "@\\([a-z0-9-]*\\)" 1 "At rule: @" css-at-ids)) + + ( 'css-property-ids + (css-simple-completing-w-pred "\\<[a-z-]*" 0 "CSS property name: " css-property-ids)) + + ( 'css-simple-selectors + + ;; Fix-me: Break out the first two + (when (looking-back "\\W#\\([a-z0-9-]*\\)") + (setq cur (match-string 1)) + (setq start (match-beginning 1)) + (throw 'result (list (point) + (read-string (concat "Html tag Id: " cur))))) + (when (looking-back "\\W\\.\\([a-z0-9-]*\\)") + (setq cur (match-string 1)) + (setq start (match-beginning 1)) + (throw 'result (list (point) + (read-string (concat "CSS class name: " cur))))) + + (css-simple-completing-w-pred "[a-z0-9]:\\([a-z0-9-]*\\)" 1 "Pseudo id: " css-pseudo-ids) + + (css-simple-completing-w-pred "[a-z0-9-]+" 0 "HTML tag: " (cddr css-simple-selectors)) + + (when (looking-back "\\<\\(?:#\\|\\.\\)") + (setq pre nil) + (while t + (setq pre (completing-read "HTML tag, id or CSS class: " css-simple-selectors nil nil pre)) + (if (string= (substring pre 0 1) "#") + (if (or (= 1 (length pre)) + (and (> (length pre) 2) + (string= (substring pre 0 3) "# ("))) + (throw 'result (list (point) (concat "#" (read-string "Html tag id: #")))) + (throw 'result (list (point) pre))) + (if (string= (substring pre 0 1) ".") + (if (or (= 1 (length pre)) + (and (> (length pre) 2) + (string= (substring pre 0 3) ". ("))) + (throw 'result (list (point) (concat "." (read-string "CSS class name: .")))) + (throw 'result (list (point) pre))) + (when (member pre css-simple-selectors) + (throw 'result (list (point) pre))))) + )))))) + (message "result=%S" result) + (if result + (let ((str (cadr result)) + (len (- (point) (car result)))) + (insert (substring str len))) + (message "No matching alternatives")))) + +(defun css-simple-guess-context () + "Try to find a context matching none constant. +Return the symbol corresponding to the context or nil if none +could be found. + +The symbols are the names of the defconst holding the possibly +matching ids. + +* Note: This function assumes that comments are fontified before + point." + ;; Kind of hand-written backward parser ... ;-) + (let ((ignore-case t) ;; fix-me + (here (point)) + (after-colon (and (not (bobp)) (eq (char-before) ?:))) + ret) + (prog1 + (catch 'return + ;; No completion in comments. + (when (eq (get-text-property (point) 'face) + 'font-lock-comment-face) + (throw 'return nil)) + + ;; If we are not on whitespace then don't complete + (css-simple-skip-backwards-to-code) + (unless (or (eobp) + (= (char-syntax (char-after)) ?\ ) + (< (point) here)) + (throw 'return nil)) + + ;; Skip backwards to see if after first selector + (let ((here2 (1+ (point)))) + (while (/= here2 (point)) + (setq here2 (point)) + (css-simple-skip-backwards-to-code) + (when (and (not (bobp)) + (eq (char-before) ?,)) + (backward-char)) + (skip-chars-backward "#.:a-z0-9-"))) + ;; Selector + (when (or (bobp) + (eq (char-before) ?})) + (throw 'return 'css-simple-selectors)) + + ;; Property names + (when (memq (char-before) '( ?{ ?\; )) + (throw 'return 'css-property-ids)) + + ;; If we are in the value we can't complete there yet. + (when (eq (char-before) ?:) + (throw 'return nil)) + + + ;; @ + (goto-char here) + (skip-chars-backward "a-z0-9-") + (when (eq (char-before) ?@) + (throw 'return 'css-at-ids)) + + ;; @media ids + (when (looking-back "@media\\W+") + (throw 'return 'css-media-ids)) + + ) + (goto-char here)))) +;;; Fix-me: complete these ... +;;css-descriptor-ids ;; Removed or? + +(defun css-simple-skip-backwards-to-code () + "Skip backwards until we reach code. +Requires that comments are fontified." + (let ((here (1+ (point)))) + (while (/= here (point)) + (setq here (point)) + (skip-syntax-backward " ") + (unless (bobp) + (when (memq (get-text-property (1- (point)) 'face) + '(font-lock-comment-face font-lock-comment-delimiter-face)) + (goto-char (or (previous-single-property-change (1- (point)) 'face) + (point-min)))))))) + +(defconst css-simple-selectors + '(". (for class)" + "# (for id)" + ;; HTML 4.01 tags + "a" "abbr" "acronym" "address" "applet" "area" "b" "base" "basefont" "bdo" "big" + "blockquote" "body" "br" "button" "caption" "center" "cite" "code" "col" + "colgroup" "dd" "del" "dfn" "dir" "div" "dl" "dt" "em" "fieldset" "font" "form" + "frame" "frameset" "head" "h1" "h2" "h3" "h4" "h5" "h6" "hr" "html" "i" "iframe" "img" + "input" "ins" "kbd" "label" "legend" "li" "link" "map" "menu" "meta" "noframes" + "noscript" "object" "ol" "optgroup" "option" "p" "param" "pre" "q" "s" "samp" + "script" "select" "small" "span" "strike" "strong" "style" "sub" "sup" "table" + "tbody" "td" "textarea" "tfoot" "th" "thead" "title" "tr" "tt" "u" "ul" "var" + )) + +(provide 'css-simple-completion) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; css-simple-completion.el ends here diff --git a/emacs.d/nxhtml/util/cus-new-user.el b/emacs.d/nxhtml/util/cus-new-user.el new file mode 100644 index 0000000..c727425 --- /dev/null +++ b/emacs.d/nxhtml/util/cus-new-user.el @@ -0,0 +1,803 @@ +;;; cus-new-user.el --- Customize some important options +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-07-10 Fri +;; Version: 0.2 +;; Last-Updated: 2009-07-10 Fri +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Customize significant options for which different user +;; environment expectations might dictate different defaults. +;; +;; After an idea of Scot Becker on Emacs Devel. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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 3, 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: + +(defvar cusnu-my-skin-widget nil) + +(defvar cusnu-insert-os-spec-fun nil) + +;;(customize-for-new-user) +;;;###autoload +(defun customize-for-new-user (&optional name) + "Show special customization page for new user. +" + (interactive) + ;;(setq debug-on-error t) + ;;(setq buffer-read-only t) + (require 'cus-edit) + (let ((inhibit-read-only t) + fill-pos) + (pop-to-buffer (custom-get-fresh-buffer (or name "*Customizations for New Users*"))) + (buffer-disable-undo) + (Custom-mode) + (erase-buffer) + (widget-insert (propertize "Easy Customization for New Users\n" 'face '(:weight bold :height 1.5))) + (setq fill-pos (point)) + (widget-insert + "Below are some custom options that new users often may want to +tweak since they may make Emacs a bit more like what they expect from +using other software in their environment. + +After this, at the bottom of this page, is a tool for exporting your own specific options. +You choose which to export, make a description and give the group of options a new and click a button. +Then you just mail it or put it on the web for others to use. + +Since Emacs runs in many environment and an Emacs user may use +several of them it is hard to decide by default what a user +wants/expects. Therefor you are given the possibility to easily +do those changes here. + +Note that this is just a collection of normal custom options. +There are no new options here. + + +") + (fill-region fill-pos (point)) + + ;; Normal custom buffer header + (let ((init-file (or custom-file user-init-file))) + ;; Insert verbose help at the top of the custom buffer. + (when custom-buffer-verbose-help + (widget-insert "Editing a setting changes only the text in this buffer." + (if init-file + " +To apply your changes, use the Save or Set buttons. +Saving a change normally works by editing your init file." + " +Currently, these settings cannot be saved for future Emacs sessions, +possibly because you started Emacs with `-q'.") + "\nFor details, see ") + (widget-create 'custom-manual + :tag "Saving Customizations" + "(emacs)Saving Customizations") + (widget-insert " in the ") + (widget-create 'custom-manual + :tag "Emacs manual" + :help-echo "Read the Emacs manual." + "(emacs)Top") + (widget-insert ".")) + (widget-insert "\n") + ;; The custom command buttons are also in the toolbar, so for a + ;; time they were not inserted in the buffer if the toolbar was in use. + ;; But it can be a little confusing for the buffer layout to + ;; change according to whether or nor the toolbar is on, not to + ;; mention that a custom buffer can in theory be created in a + ;; frame with a toolbar, then later viewed in one without. + ;; So now the buttons are always inserted in the buffer. (Bug#1326) +;;; (when (not (and (bound-and-true-p tool-bar-mode) (display-graphic-p))) + (if custom-buffer-verbose-help + (widget-insert "\n + Operate on all settings in this buffer that are not marked HIDDEN:\n")) + (let ((button (lambda (tag action active help icon) + (widget-insert " ") + (if (eval active) + (widget-create 'push-button :tag tag + :help-echo help :action action)))) + (commands custom-commands)) + (apply button (pop commands)) ; Set for current session + (apply button (pop commands)) ; Save for future sessions + (if custom-reset-button-menu + (progn + (widget-insert " ") + (widget-create 'push-button + :tag "Reset buffer" + :help-echo "Show a menu with reset operations." + :mouse-down-action 'ignore + :action 'custom-reset)) + (widget-insert "\n") + (apply button (pop commands)) ; Undo edits + (apply button (pop commands)) ; Reset to saved + (apply button (pop commands)) ; Erase customization + (widget-insert " ") + (pop commands) ; Help (omitted) + (apply button (pop commands)))) ; Exit + (widget-insert "\n\n") + + (widget-insert (propertize "\nThis part is for your own use\n" 'face '(:weight bold :height 1.5))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Editor emulator level + + (widget-insert "\n") + (setq fill-pos (point)) + (widget-insert +"Emacs can emulate some common editing behaviours (and some uncommon too). +For the most common ones you can decide if you want to use them here: +") + (fill-region fill-pos (point)) + (cusnu-mark-part-desc fill-pos (point)) + + ;; CUA Mode + (cusnu-insert-options '((cua-mode custom-variable))) + + ;; Viper Mode + (widget-insert "\n") + (widget-insert (propertize "Viper" 'face 'custom-variable-tag)) + (widget-insert ":") + (setq fill-pos (point)) + (widget-insert " + Viper is currently set up in a special way, please see the + command `viper-mode'. You can use custom to set up most of + it. However if you want to load Viper at startup you must + explicitly include \(require 'viper) in your .emacs. +") + (fill-region fill-pos (point)) + + ;; Viper Mode + (backward-delete-char 1) + (cusnu-insert-options '((viper-mode custom-variable))) + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; OS specific + + (widget-insert "\n") + (setq fill-pos (point)) + (widget-insert (format "OS specific options (%s): \n" system-type)) + (fill-region fill-pos (point)) + (cusnu-mark-part-desc fill-pos (point)) + + (if cusnu-insert-os-spec-fun + (funcall cusnu-insert-os-spec-fun) + (widget-insert "No OS specific customizations.\n")) + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;; Disputed settings + + (widget-insert "\n") + (setq fill-pos (point)) + (widget-insert +"Some old time Emacs users want to change the options below: +") + (fill-region fill-pos (point)) + (cusnu-mark-part-desc fill-pos (point)) + + (cusnu-insert-options '((global-visual-line-mode custom-variable))) + (cusnu-insert-options '((word-wrap custom-variable))) + (cusnu-insert-options '((blink-cursor-mode custom-variable))) + (cusnu-insert-options '((tool-bar-mode custom-variable))) + (cusnu-insert-options '((tooltip-mode custom-variable))) + ;;(cusnu-insert-options '((initial-scratch-message custom-variable))) + + (widget-insert "\n") + (widget-insert (propertize "\n\nThis part is for exporting to others\n\n" 'face '(:weight bold :height 1.5))) + (setq fill-pos (point)) + (widget-insert +"My skin options - This is for exporting custom options to other users +\(or maybe yourself on another computer). +This works the following way: + +- You add a description of your options and the options you want to export below. +Then you click on `Export my skin options'. +This creates a file that you can send to other Emacs users. +They simply open that file in Emacs and follow the instructions there to test your options +and maybe save them for later use if they like them. +\(You can follow the instructions yourself to see how it works.) + +Please change the group symbol name to something specific for you. +") + (fill-region fill-pos (point)) + (cusnu-mark-part-desc fill-pos (point)) + + (widget-insert "\n") + (set (make-local-variable 'cusnu-my-skin-widget) + (car + (cusnu-insert-options '((cusnu-my-skin-options custom-variable))))) + (widget-insert "\n") + (widget-create 'push-button + :tag "Export my skin options " + :action (lambda (&rest ignore) + (let ((use-dialog-box nil)) + (call-interactively 'cusnu-export-my-skin-options)))) + (widget-insert "\n") + (widget-create 'push-button + :tag "Customize my skin options " + :action (lambda (&rest ignore) + (let ((use-dialog-box nil)) + (call-interactively 'cusnu-customize-my-skin-options)))) + (widget-insert "\n") + (widget-create 'push-button + :tag "Reset those options to saved values" + :action (lambda (&rest ignore) + (let ((use-dialog-box nil)) + (call-interactively 'cusnu-reset-my-skin-options)))) + + ;; Finish setup buffer + (mapc 'custom-magic-reset custom-options) + (cusnu-make-xrefs) + (widget-setup) + (buffer-enable-undo) + (goto-char (point-min))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Example on Emacs+Emacw32 +(eval-when-compile (require 'emacsw32 nil t)) +(when (fboundp 'emacsw32-version) + (defun cusnu-emacsw32-show-custstart (&rest args) + (emacsw32-show-custstart)) + (setq cusnu-insert-os-spec-fun 'cusnu-insert-emacsw32-specific-part) + (defun cusnu-insert-emacsw32-specific-part () + (cusnu-insert-options '((w32-meta-style custom-variable))) + (widget-insert "\n") + (widget-insert (propertize "EmacsW32" 'face 'custom-variable-tag)) + (widget-insert " + Easy setup for Emacs+EmacsW32.") + (widget-insert "\n ") + (widget-create 'push-button :tag "Customize EmacsW32" + ;;:help-echo help + :action 'cusnu-emacsw32-show-custstart) + (widget-insert "\n"))) +;; End example +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun cusnu-mark-part-desc (beg end) + (let ((ovl (make-overlay beg end))) + (overlay-put ovl 'face 'highlight))) + +(defun cusnu-make-xrefs (&optional beg end) + (save-restriction + (when (or beg end) + (unless beg (setq beg (point-min))) + (unless end (setq end (point-max))) + (narrow-to-region beg end)) + (let ((here (point))) + (goto-char (point-min)) + (cusnu-help-insert-xrefs 'cusnu-help-xref-button) + (goto-char here)))) + +(defun widget-info-link-action (widget &optional event) + "Open the info node specified by WIDGET." + (info-other-window (widget-value widget))) + +(defun widget-documentation-string-value-create (widget) + ;; Insert documentation string. + (let ((doc (widget-value widget)) + (indent (widget-get widget :indent)) + (shown (widget-get (widget-get widget :parent) :documentation-shown)) + (start (point))) + (if (string-match "\n" doc) + (let ((before (substring doc 0 (match-beginning 0))) + (after (substring doc (match-beginning 0))) + button) + (when (and indent (not (zerop indent))) + (insert-char ?\s indent)) + (insert before ?\s) + (widget-documentation-link-add widget start (point)) + (setq button + (widget-create-child-and-convert + widget (widget-get widget :visibility-widget) + :help-echo "Show or hide rest of the documentation." + :on "Hide Rest" + :off "More" + :always-active t + :action 'widget-parent-action + shown)) + (when shown + (setq start (point)) + (when (and indent (not (zerop indent))) + (insert-char ?\s indent)) + (insert after) + (widget-documentation-link-add widget start (point)) + (cusnu-make-xrefs start (point)) + ) + (widget-put widget :buttons (list button))) + (when (and indent (not (zerop indent))) + (insert-char ?\s indent)) + (insert doc) + (widget-documentation-link-add widget start (point)))) + (insert ?\n)) +(defun cusnu-help-xref-button (match-number type what &rest args) + (let ((beg (match-beginning match-number)) + (end (match-end match-number))) + (if nil + (let ((ovl (make-overlay beg end))) + (overlay-put ovl 'face 'highlight)) + (let* ((tag (match-string match-number)) + (value what) + (wid-type (cond + ((eq type 'help-variable) + 'variable-link) + ((eq type 'help-function) + 'function-link) + ((eq type 'help-info) + 'custom-manual) + (t nil))) + ) + (when wid-type + (delete-region beg end) + (backward-char) + ;;(tag action active help icon) + (widget-create wid-type + ;;tag + :value value + :tag tag + :keymap custom-mode-link-map + :follow-link 'mouse-face + :button-face 'custom-link + :mouse-face 'highlight + :pressed-face 'highlight + ;;:help-echo help + ))))) + ) + +;; Override default ... ;-) +(define-widget 'documentation-link 'link + "Link type used in documentation strings." + ;;:tab-order -1 + :help-echo "Describe this symbol" + :button-face 'custom-link + :action 'widget-documentation-link-action) + +(defun cusnu-xref-niy (&rest ignore) + (message "Not implemented yet")) + +(defun cusnu-describe-function (wid &rest ignore) + (let ((fun (widget-get wid :what)) + ) + (describe-function fun))) + +(defun cusnu-help-insert-xrefs (help-xref-button) + ;; The following should probably be abstracted out. + (unwind-protect + (progn + ;; Info references + (save-excursion + (while (re-search-forward help-xref-info-regexp nil t) + (let ((data (match-string 2))) + (save-match-data + (unless (string-match "^([^)]+)" data) + (setq data (concat "(emacs)" data)))) + (funcall help-xref-button 2 'help-info data)))) + ;; URLs + (save-excursion + (while (re-search-forward help-xref-url-regexp nil t) + (let ((data (match-string 1))) + (funcall help-xref-button 1 'help-url data)))) + ;; Mule related keywords. Do this before trying + ;; `help-xref-symbol-regexp' because some of Mule + ;; keywords have variable or function definitions. + (if help-xref-mule-regexp + (save-excursion + (while (re-search-forward help-xref-mule-regexp nil t) + (let* ((data (match-string 7)) + (sym (intern-soft data))) + (cond + ((match-string 3) ; coding system + (and sym (coding-system-p sym) + (funcall help-xref-button 6 'help-coding-system sym))) + ((match-string 4) ; input method + (and (assoc data input-method-alist) + (funcall help-xref-button 7 'help-input-method data))) + ((or (match-string 5) (match-string 6)) ; charset + (and sym (charsetp sym) + (funcall help-xref-button 7 'help-character-set sym))) + ((assoc data input-method-alist) + (funcall help-xref-button 7 'help-character-set data)) + ((and sym (coding-system-p sym)) + (funcall help-xref-button 7 'help-coding-system sym)) + ((and sym (charsetp sym)) + (funcall help-xref-button 7 'help-character-set sym))))))) + ;; Quoted symbols + (save-excursion + (while (re-search-forward help-xref-symbol-regexp nil t) + (let* ((data (match-string 8)) + (sym (intern-soft data))) + (if sym + (cond + ((match-string 3) ; `variable' &c + (and (or (boundp sym) ; `variable' doesn't ensure + ; it's actually bound + (get sym 'variable-documentation)) + (funcall help-xref-button 8 'help-variable sym))) + ((match-string 4) ; `function' &c + (and (fboundp sym) ; similarly + (funcall help-xref-button 8 'help-function sym))) + ((match-string 5) ; `face' + (and (facep sym) + (funcall help-xref-button 8 'help-face sym))) + ((match-string 6)) ; nothing for `symbol' + ((match-string 7) +;;; this used: +;;; #'(lambda (arg) +;;; (let ((location +;;; (find-function-noselect arg))) +;;; (pop-to-buffer (car location)) +;;; (goto-char (cdr location)))) + (funcall help-xref-button 8 'help-function-def sym)) + ((and + (facep sym) + (save-match-data (looking-at "[ \t\n]+face\\W"))) + (funcall help-xref-button 8 'help-face sym)) + ((and (or (boundp sym) + (get sym 'variable-documentation)) + (fboundp sym)) + ;; We can't intuit whether to use the + ;; variable or function doc -- supply both. + (funcall help-xref-button 8 'help-symbol sym)) + ((and + (or (boundp sym) + (get sym 'variable-documentation)) + (or + (documentation-property + sym 'variable-documentation) + (condition-case nil + (documentation-property + (indirect-variable sym) + 'variable-documentation) + (cyclic-variable-indirection nil)))) + (funcall help-xref-button 8 'help-variable sym)) + ((fboundp sym) + (funcall help-xref-button 8 'help-function sym))))))) + ;; An obvious case of a key substitution: + (save-excursion + (while (re-search-forward + ;; Assume command name is only word and symbol + ;; characters to get things like `use M-x foo->bar'. + ;; Command required to end with word constituent + ;; to avoid `.' at end of a sentence. + "\\= (current-column) col) + (looking-at "\\(\\sw\\|\\s_\\)+$")) + (let ((sym (intern-soft (match-string 0)))) + (if (fboundp sym) + (funcall help-xref-button 0 'help-function sym)))) + (forward-line)))))) + ;;(set-syntax-table stab) + )) + +(defun cusnu-insert-options (options) + (widget-insert "\n") + (setq custom-options + (append + (if (= (length options) 1) + (mapcar (lambda (entry) + (widget-create (nth 1 entry) + ;;:documentation-shown t + :custom-state 'unknown + :tag (custom-unlispify-tag-name + (nth 0 entry)) + :value (nth 0 entry))) + options) + (let ((count 0) + (length (length options))) + (mapcar (lambda (entry) + (prog2 + (message "Creating customization items ...%2d%%" + (/ (* 100.0 count) length)) + (widget-create (nth 1 entry) + :tag (custom-unlispify-tag-name + (nth 0 entry)) + :value (nth 0 entry)) + (setq count (1+ count)) + (unless (eq (preceding-char) ?\n) + (widget-insert "\n")) + (widget-insert "\n"))) + options))) + custom-options)) + (unless (eq (preceding-char) ?\n) + (widget-insert "\n")) + custom-options + ) + +(defun cusnu-is-custom-obj (sym) + "Return non-nil if symbol SYM is customizable." + (or (get sym 'custom-type) + (get sym 'face) + (get sym 'custom-group) + )) + +(define-widget 'custom-symbol 'symbol + "A customizable symbol." + :prompt-match 'cusnu-is-custom-obj + :prompt-history 'widget-variable-prompt-value-history + :complete-function (lambda () + (interactive) + (lisp-complete-symbol 'cusnu-is-custom-obj)) + :tag "Custom option") + +(defun cusnu-set-my-skin-options (sym val) + (set-default sym val) + (let ((group (nth 0 val)) + (doc (nth 1 val)) + (members (nth 2 val))) + (custom-declare-group group nil doc) + (put group 'custom-group nil) + (dolist (opt members) + (let ((type (cusnu-get-opt-main-type opt))) + (when type + (custom-add-to-group group opt type)))))) + +(defun cusnu-get-opt-main-type (opt) + (when opt + (cond ((get opt 'face) 'custom-face) + ((get opt 'custom-type) 'custom-variable) + ((get opt 'custom-group) 'custom-group)))) + +(defgroup all-my-loaded-skin-groups nil + "All your loaded skin groups." + :group 'environment + :group 'convenience) + +(defun cusnu-custom-group-p (symbol) + (and (intern-soft symbol) + (or (and (get symbol 'custom-loads) + (not (get symbol 'custom-autoload))) + (get symbol 'custom-group)))) + +(defcustom cusnu-my-skin-options '(my-skin-group "My skin group.\n\n\n\n\n" nil) + "Your custom skin-like options. +The purpose of this variable is to provide for easy export a +selection of variables you choose to set to other users. + +To send these values to other users you export them to a file +with `cusnu-export-my-skin-options'." + :type '(list (symbol :tag "My custom group symbol name (should be specific to you)") + (string :tag "My custom group description") + (repeat :tag "Add your custom options below" + (custom-symbol :tag "My custom option"))) + :set 'cusnu-set-my-skin-options + :group 'all-my-loaded-skin-groups) + +;;(cusnu-ring-bell "bell") +(defun cusnu-ring-bell (format-string &rest args) + (message "%s" (propertize (apply + 'format format-string args) 'face 'secondary-selection)) + (ding) + (throw 'bell nil)) + +;;;###autoload +(defun cusnu-export-my-skin-options (file) + "Export to file FILE custom options in `cusnu-my-skin-options'. +The options is exported to elisp code that other users can run to +set the options that you have added to `cusnu-my-skin-options'. + +For more information about this see `cusnu-export-cust-group'." + (interactive '(nil)) + (catch 'bell + (let ((grp (nth 0 cusnu-my-skin-options)) + buf) + (let ((state (plist-get (cdr cusnu-my-skin-widget) :custom-state))) + (case state + ((set saved) nil) ;;(error "test, state=%s" state)) + (standard (cusnu-ring-bell "Please enter your options first")) + (t (cusnu-ring-bell "My Skin Options must be saved or set, use the State button, %s" state)))) + (unless (nth 2 cusnu-my-skin-options) + (cusnu-ring-bell "You have not added any of your options")) + (unless file + (setq file (read-file-name "Save to file: "))) + (when (file-exists-p file) + (cusnu-ring-bell "File %s already exists, choose another file name" file)) + (setq buf (find-file-other-window file)) + (with-current-buffer buf + (unless (eq major-mode 'emacs-lisp-mode) (emacs-lisp-mode)) + (unless (file-exists-p (buffer-file-name)) + (erase-buffer))) + (cusnu-export-cust-group grp buf)))) + +(defun cusnu-customize-my-skin-options () + (interactive) + (customize-group-other-window (nth 0 cusnu-my-skin-options))) + +(defun cusnu-reset-my-skin-options () + "Reset to my defaults for those options. +" + (interactive) + (cusnu-reset-group-options-to-my-defaults (nth 0 cusnu-my-skin-options))) + +(defun cusnu-reset-group-options-to-my-defaults (group) + (dolist (sym-typ (get group 'custom-group)) + (let ((symbol (nth 0 sym-typ)) + ;;(type (cusnu-get-opt-main-type symbol)) + (type (nth 1 sym-typ)) + defval) + (cond + ((eq type 'custom-variable) + ;; First try reset to saved. + (let* ((set (or (get symbol 'custom-set) 'set-default)) + (value (get symbol 'saved-value)) + (comment (get symbol 'saved-variable-comment))) + (cond ((or comment value) + (put symbol 'variable-comment comment) + (custom-push-theme 'theme-value symbol 'user 'set (car-safe value)) + (condition-case err + (funcall set symbol (eval (car value))) + (error (message "%s" err)))) + ;; If symbol was not saved then reset to standard. + (t + (unless (get symbol 'standard-value) + (error "No standard setting known for %S" symbol)) + (put symbol 'variable-comment nil) + (put symbol 'customized-value nil) + (put symbol 'customized-variable-comment nil) + (custom-push-theme 'theme-value symbol 'user 'reset) + (custom-theme-recalc-variable symbol) + (put symbol 'saved-value nil) + (put symbol 'saved-variable-comment nil) + )))) + ((eq type 'custom-face) + ;; First try reset to saved + (let* ((value (get symbol 'saved-face)) + (comment (get symbol 'saved-face-comment))) + (cond ((or value comment) + (put symbol 'customized-face nil) + (put symbol 'customized-face-comment nil) + (custom-push-theme 'theme-face symbol 'user 'set value) + (face-spec-set symbol value t) + (put symbol 'face-comment comment)) + ;; If symbol was not saved then reset to standard. + (t + (setq value (get symbol 'face-defface-spec)) + (unless value + (error "No standard setting for this face")) + (put symbol 'customized-face nil) + (put symbol 'customized-face-comment nil) + (custom-push-theme 'theme-face symbol 'user 'reset) + (face-spec-set symbol value t) + (custom-theme-recalc-face symbol) + ;; Do this later. + (put symbol 'saved-face nil) + (put symbol 'saved-face-comment nil) + )))) + (t (error "not iy")))))) + +(defun cusnu-export-cust-group (group buf) + "Export custom group GROUP to end of buffer BUF. +Only the options that has been customized will be exported. + +The group is exported as elisp code. Running the code will +create a group with just those members. After this it opens a +customization buffer with the new group. + +The code will also set the options to the customized values, but +it will not save them in the users init file. + +See also the comment in the exported file." + (let (start + (doc (get group 'group-documentation)) + groups options faces + (members (mapcar (lambda (rec) + (car rec)) + (get group 'custom-group)))) + (with-current-buffer buf + (insert (format-time-string ";; Here is my skin custom group %Y-%m-%d.\n")) + (font-lock-mode 1) + (insert (format ";;;;;; Customization group name: %s\n" group)) + (insert ";;\n") + (let ((here (point))) + (insert doc "\n") + (comment-region here (point)) + (fill-region here (point))) + (cusnu-get-options-and-faces members 'groups 'options 'faces) + (unless (or options faces) + (cusnu-ring-bell "There are no options or faces in %s customized by you" group)) + (insert " +;; This file defines the group and sets the options in it, but does +;; not save the values to your init file. +;; +;; To set the values evaluate this file. To do that open this file in Emacs and to +;; +;; M-x eval-buffer +;; +;; To go back to your default evaluate next line (place point at the end and to C-x C-e): +") + (insert (format ";; (cusnu-reset-group-options-to-my-defaults '%s)\n\n" group)) + (insert (format "(let ((grp '%s))\n" group)) + (insert (format " (custom-declare-group grp nil %S)\n" doc)) + (insert " (put grp 'custom-group nil)\n") + (insert (format " (custom-add-to-group 'all-my-loaded-skin-groups '%s 'custom-group)\n" group)) + (dolist (opt members) + (let ((type (cusnu-get-opt-main-type opt))) + (when type + (insert (format " (custom-add-to-group grp '%s '%s)\n" + opt type))))) + (insert " (custom-set-variables\n") + (dolist (opt options) + (let ((my-val (or (get opt 'saved-value) + (get opt 'customized-value)))) + (when my-val + (insert (format " '(%s %S)\n" opt (custom-quote (symbol-value opt))))))) + (insert " )\n") + (insert " (custom-set-faces\n") + (dolist (opt faces) + (let ((my-val (get opt 'customized-face))) + (when my-val + (insert (format " '(%s %S)\n" opt my-val))))) + (insert " ))\n") + (insert (format "\n(customize-group '%s)\n" group)) + ))) + +(defun cusnu-get-options-and-faces (members groups-par options-par faces-par) + (dolist (sym members) + (insert (format ";; sym=%s\n" sym)) + (cond ((and (get sym 'custom-type) + (or (get sym 'saved-value) + (get sym 'customize-value))) + (add-to-list options-par sym)) + ((and (get sym 'face) + (get sym 'customized-face)) + (add-to-list faces-par sym)) + ((get sym 'custom-group) + (unless (memq sym groups-par) ;; Don't loop + (cusnu-get-options-and-faces groups-par options-par faces-par))) + (t (insert ";; Not a custom variable or face: %s\n" sym))))) + +(provide 'cus-new-user) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; cus-new-user.el ends here diff --git a/emacs.d/nxhtml/util/custsets.el b/emacs.d/nxhtml/util/custsets.el new file mode 100644 index 0000000..0495dd8 --- /dev/null +++ b/emacs.d/nxhtml/util/custsets.el @@ -0,0 +1,83 @@ +;;; custsets.el --- Sets of named customizations +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-03-25T00:17:06+0100 Mon +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; After an idea expressed by among other Stephen Turnbull on the +;; emacs devel list. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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: + +(defcustom custsets-sets + '( + ("Windows" + (cua-mode t) + ) + ) + "Sets of customizations." + :group 'custsets) + +(defun custsets-turn-on (set-name) + (interactive "sCustomization set: ") + (let ((set (assoc-string set-name custsets-sets t))) + (unless set + (error "Can't find customization set %s" set-name)) + (dolist (opt-rec (cdr set)) + (let* ((opt (car opt-rec)) + (val (cdr opt-rec)) + (saved-opt (get opt 'saved-value)) + (saved-val saved-opt) ;; fix-me + (ask (if saved-opt + (format "You have currently customized %s to %s. Change this to %s? " + opt saved-opt val) + (format "Customize %s to %s? " opt val))) + ) + (when (y-or-n-p ask) + (customize-set-variable opt val) + (customize-set-value opt val) + (customize-mark-to-save opt)) + ) + ) + (custom-save-all))) + + +(provide 'custsets) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; custsets.el ends here diff --git a/emacs.d/nxhtml/util/ecb-batch-compile.el b/emacs.d/nxhtml/util/ecb-batch-compile.el new file mode 100644 index 0000000..bdd86c6 --- /dev/null +++ b/emacs.d/nxhtml/util/ecb-batch-compile.el @@ -0,0 +1,65 @@ +;;; ecb-batch-compile.el --- Compile ecb in batch mode +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-08-25T04:46:35+0200 Mon +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Batch byte compile ecb: +;; +;; emacs -Q -l ecb-batch-compile +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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 'cl)) +(eval-and-compile (require 'udev-ecb nil t)) + +(let* ((this-file load-file-name) + (this-dir (file-name-directory this-file)) + ) + (add-to-list 'load-path this-dir)) + +;;(require 'udev-cedet) +;;(udev-cedet-load-cedet t) + +(eval-when (eval) + (udev-ecb-load-ecb) + (ecb-byte-compile)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; ecb-batch-compile.el ends here diff --git a/emacs.d/nxhtml/util/ediff-url.el b/emacs.d/nxhtml/util/ediff-url.el new file mode 100644 index 0000000..12329bd --- /dev/null +++ b/emacs.d/nxhtml/util/ediff-url.el @@ -0,0 +1,188 @@ +;;; ediff-url.el --- Diffing buffer against downloaded url +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Sat Nov 24 2007 +;; Version: 0.56 +;; Last-Updated: 2010-03-18 Thu +;; URL: http://bazaar.launchpad.net/~nxhtml/nxhtml/main/annotate/head%3A/util/ediff-url.el +;; +;; Features that might be required by this library: +;; + ;; `mail-prsvr', `mm-util', `timer', `url-parse', `url-util', + ;; `url-vars'. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This file contains a simple function, `ediff-url', to help you +;; update a single file from the web. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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: + +(require 'url-util) +(eval-when-compile (require 'cl)) + +(defvar ediff-url-read-url-history nil) + +(defun ediff-url-redir-launchpad (url) + "Check if bazaar list page on Launchpad. +If URL is a description page for a file uploaded to EmacsWiki +suggest to use the download URL instead." + (let* ((bazaar-url "http://bazaar.launchpad.net/") + (bazaar-len (length bazaar-url))) + (if (and (< bazaar-len (length url)) + (string= bazaar-url (substring url 0 bazaar-len))) + (let* ((url-show-status nil) ;; just annoying showing status here + (buffer (url-retrieve-synchronously url)) + (handle nil) + (http-status nil) + ;; Fix-me: better more flexible pattern? + (dl-patt "download file") + dl-url) + (unless buffer + (message "Got empty buffer for %s" url) + (throw 'command-level nil)) + (with-current-buffer buffer + (if (= 0 (buffer-size)) + (progn + (message "Got empty page for %s" url) + (throw 'command-level nil)) + (require 'url-http) + (setq http-status (url-http-parse-response)) + (if (memq http-status '(200 201)) + (progn + (goto-char (point-min)) + (unless (search-forward "\n\n" nil t) + (error "Could not find header end in buffer for %s" url)) + (unless (re-search-forward dl-patt nil t) + (error "Could not find download link")) + (setq dl-url (match-string 1)) + (set-buffer-modified-p nil) + (kill-buffer buffer) + dl-url) + (kill-buffer buffer) + (setq buffer nil) + (setq http-status + (concat (number-to-string http-status) + (case http-status + (401 " (unauthorized)") + (403 " (forbidden)") + (404 " (not found)") + (408 " (request timeout)") + (410 " (gone)") + (500 " (internal server error)") + (503 " (service unavailable)") + (504 " (gateway timeout)") + (530 " (user access denied)") + ))) + (message "Got status %s for %s" http-status url) + (throw 'command-level nil))))) + url))) + +(defun ediff-url-redir-emacswiki-description-page (url) + "Check if description page on EmacsWiki. +If URL is a description page for a file uploaded to EmacsWiki +suggest to use the download URL instead." + ;;(let* ((desc-url "http://www.emacswiki.org/emacs/") + (let* ((emacswiki-url "http://www.emacswiki.org/") + (emacswiki-len (length emacswiki-url))) + (if (and (< emacswiki-len (length url)) + (string= emacswiki-url (substring url 0 emacswiki-len)) + (not (string-match-p "/download/" url))) + (let ((prompt + (concat "This seem to be the description page on EmacsWiki," + "\n\tdo you want the download url instead? "))) + (when (y-or-n-p prompt) + ;;(let ((start (+ 6 (string-match "/wiki/" url)))) + (let ((start (+ 7 (string-match "/emacs/" url)))) + (concat (substring url 0 start) + "download/" + (substring url start))))) + ;; Not on the wiki, just return the url: + url))) + +(defcustom ediff-url-redirects '(ediff-url-redir-emacswiki-description-page + ediff-url-redir-launchpad + ) + "List of functions checking url given to `ediff-url'. +Each function should take an URL as argument and return this URL +or a new URL." + :type '(repeat function) + :group 'ediff) + +;;;###autoload +(defun ediff-url (url) + "Compare current buffer to a web URL using `ediff-buffers'. +Check URL using `ediff-url-redirects' before fetching the file. + +This is for checking downloaded file. A the file may have a comment +telling the download URL of thise form in the header: + + ;; URL: http://the-server.net/the-path/the-file.el + +If not the user is asked for the URL." + (interactive (let ((url-init (url-get-url-at-point))) + (unless url-init + (when (eq major-mode 'emacs-lisp-mode) + (save-excursion + (goto-char (point-min)) + (when (re-search-forward "URL:[ \t]*" nil t) + (setq url-init (url-get-url-at-point)))))) + (list (read-from-minibuffer "Url for download file: " + (cons (or url-init "") 1) ;nil + nil nil + 'ediff-url-read-url-history + ;;url-init + )))) + (catch 'command-level ;; Fix-me: remove and let go to top later + (unless (> (length url) 0) + (message "No URL given, aborted by user") + (throw 'command-level nil)) + ;; Check if URL seems reasonable + (dolist (fun ediff-url-redirects) + (setq url (funcall fun url))) + ;; Fetch URL and run ediff + (let* ((url-buf-name (concat "URL=" url)) + (url-buf (get-buffer url-buf-name))) + (when url-buf + (unless (y-or-n-p "Use previously downloaded url? ") + (kill-buffer url-buf) + (setq url-buf nil))) + (unless url-buf + (setq url-buf (get-buffer-create url-buf-name)) + (let ((current-major major-mode)) + (with-current-buffer url-buf + (url-insert-file-contents url) + ;; Assume same modes: + (funcall current-major)))) + (ediff-buffers url-buf (current-buffer))))) + +(provide 'ediff-url) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; ediff-url.el ends here diff --git a/emacs.d/nxhtml/util/ffip.el b/emacs.d/nxhtml/util/ffip.el new file mode 100644 index 0000000..42d1893 --- /dev/null +++ b/emacs.d/nxhtml/util/ffip.el @@ -0,0 +1,304 @@ +;;; ffip.el --- Find files in project +;; +;; Authors: extracted from rinari by Phil Hagelberg and Doug Alcorn +;; Changed by Lennart Borgman +;; Created: 2008-08-14T23:46:22+0200 Thu +;; Version: 0.3 +;; Last-Updated: 2008-12-28 Sun +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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 'cl)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Project data + +;; Fix-me: Change the inner structure of ffip projects +(defvar ffip-project-name nil "Project name.") +(defvar ffip-project-roots nil "Project directory roots.") +(defvar ffip-project-type nil "Project type, `ffip-project-file-types'.") +(defcustom ffip-project-file-types + (list + '(ruby "\\(\\.el$\\|\\.rb$\\|\\.js$\\|\\.emacs\\)") + (list 'nxhtml (concat + (regexp-opt '(".html" ".htm" ".xhtml" + ".css" + ".js" + ".png" ".gif" + )) + "\\'")) + ) + "Project types and file types. +The values in this list are used to determine if a file belongs +to the current ffip project. Entries have the form + + \(TYPE FILE-REGEXP) + +TYPE is the parameter set by `ffip-set-current-project'. Files +matching FILE-REGEXP within the project roots are members of the +project." + :type '(repeat (list + (symbol :tag "Type") + (regexp :tag "File regexp"))) + :group 'ffip) + +(defvar ffip-project-file-matcher nil "Project file matcher.") +(defvar ffip-project-files-table nil "Project file cache.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Project handling + +(defun ffip-reset-project () + "Clear project data." + (remove-hook 'after-save-hook 'ffip-after-save) + (setq ffip-project-name nil) + (setq ffip-project-roots nil) + (setq ffip-project-files-table nil) + (setq ffip-project-type nil) + (setq ffip-project-file-matcher nil)) +;;(ffip-reset-project) + +(defun ffip-is-current (name root type) + "Return non-nil if NAME, ROOT and TYPE match current ffip project. +See `ffip-set-current-project'." + (and name + (string= ffip-project-name name) + (eq ffip-project-type type) + (equal ffip-project-roots root))) + +;;;###autoload +(defun ffip-set-current-project (name root type) + "Setup ffip project NAME with top directory ROOT of type TYPE. +ROOT can either be just a directory or a list of directory where +the first used just for prompting purposes and the files in the +rest are read into the ffip project. + +Type is a type in `ffip-project-file-types'." + (unless (ffip-is-current name root type) + (ffip-reset-project) + (setq ffip-project-name name) + (setq ffip-project-type type) + (setq ffip-project-roots root) + (message "Project %s with %s files setup for find-files-in-project" + name (length ffip-project-files-table)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; File cache handling + +(defun ffip-cache-project-files (file-regexp) + "Read files and cache their names within the ffip project." + (let ((root ffip-project-roots)) + (message "... reading files in %s ..." root) + (add-hook 'after-save-hook 'ffip-after-save) + (if (not (listp root)) + (ffip-populate-files-table root file-regexp) + (setq root (cdr root)) + (dolist (r root) + (ffip-populate-files-table r file-regexp))))) + +(defun ffip-file-matcher () + (when ffip-project-type + (cadr (assoc ffip-project-type ffip-project-file-types)))) + +(defun ffip-project-files () + "Get a list of all files in ffip project. +The members in the list has the format + + \(SHORT-NAME . FULL-NAME) + +where SHORT-NAME is a unique name (normally file name without +directory) and FULL-NAME is the full file name." + (unless ffip-project-files-table + (let ((file-regexp (ffip-file-matcher))) + (ffip-cache-project-files file-regexp))) + ffip-project-files-table) + +;; Fix-me: Seems better to rewrite this to use +;; project-find-settings-file. +(defun ffip-project-root (&optional dir) + (setq dir (or dir + ffip-project-roots + default-directory)) + ;;(locate-dominating-file "." "\\`\\find-file-in-project.el\\'") + (let ((root (locate-dominating-file dir + ;;"\\`\\.emacs-project\\'" + "\\`\\.dir-settings\\.el\\'" + ))) + (if root + (file-name-directory root) + dir))) + +(defun ffip-populate-files-table (file file-regexp) + ;;(message "ffip-populate-files-table.file=%s" file) + (if (file-directory-p file) + (mapc (lambda (file) + (ffip-populate-files-table file file-regexp)) + (directory-files (expand-file-name file) t "^[^\.]")) + (let* ((file-name (file-name-nondirectory file)) + (existing-record (assoc file-name ffip-project-files-table)) + (unique-parts (ffip-get-unique-directory-names file + (cdr existing-record)))) + (when (or (not file-regexp) + (string-match file-regexp file-name)) + (if existing-record + (let ((new-key (concat file-name " - " (car unique-parts))) + (old-key (concat (car existing-record) " - " + (cadr unique-parts)))) + (setf (car existing-record) old-key) + (setq ffip-project-files-table + (acons new-key file ffip-project-files-table))) + (setq ffip-project-files-table + (acons file-name file ffip-project-files-table))))))) + +(defun ffip-get-unique-directory-names (path1 path2) + (let* ((parts1 (and path1 (split-string path1 "/" t))) + (parts2 (and path2 (split-string path2 "/" t))) + (part1 (pop parts1)) + (part2 (pop parts2)) + (looping t)) + (while (and part1 part2 looping) + (if (equal part1 part2) + (setq part1 (pop parts1) part2 (pop parts2)) + (setq looping nil))) + (list part1 part2))) + +(defun ffip-file-is-in-project (file-name) + "Return non-nil if file is in current ffip project." + (save-match-data + (let ((file-regexp (ffip-file-matcher)) + (roots ffip-project-roots) + regexp) + (if (not (listp roots)) + (setq roots (list roots)) + (setq roots (cdr roots))) + (catch 'found + (dolist (root roots) + (setq file-regexp (concat root ".*" file-regexp)) + (when (string-match file-regexp file-name) + (throw 'found t))))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Updating on file changes + +(defun ffip-add-file-if-in-project (file-name) + "Add file to cache if it in ffip project." + (when (ffip-file-is-in-project file-name) + ;; We have already checked so just use nil for the matcher. + (ffip-populate-files-table file-name nil))) + +;; For after-save-hook +(defun ffip-after-save () + "Check if a file should be added to cache." + (condition-case err + (ffip-add-file-if-in-project buffer-file-name) + (error (message "%s" (error-message-string err))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Interactive functions + +;;;###autoload +(defun ffip-find-file-in-dirtree (root) + "Find files in directory tree ROOT." + (interactive "DFind file in directory tree: ") + ;; Setup a temporary + (let ((ffip-project-name nil) + (ffip-project-roots nil) + (ffip-project-files-table nil) + (ffip-project-type nil) + (ffip-project-file-matcher nil)) + (ffip-set-current-project "(temporary)" root nil) + (call-interactively 'ffip-find-file-in-project))) + +(defun ffip-find-file-in-project (file) + "Find files in current ffip project." + (interactive + (list + (let* ((prompt (format "Find file in project %s: " + ffip-project-name))) + (if (memq ido-mode '(file 'both)) + (ido-completing-read prompt + (mapcar 'car (ffip-project-files))) + (let ((files (mapcar 'car (ffip-project-files)))) + (completing-read prompt + files + (lambda (elem) (member elem files)) + t)))))) + (find-file (cdr (assoc file ffip-project-files-table)))) + +;;(global-set-key (kbd "C-x C-M-f") 'find-file-in-project) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Fix-me: This part should go somewhere else +(eval-after-load 'ruby-mode + '(progn + (defun ffip-rails-project-files (&optional file) + (let ((default-directory (or file (rails-root)))) + (unless (and ffip-project-roots + (string= default-directory ffip-project-roots)) + (ffip-set-current-project + "Rails proj" + root + (list default-directory + (expand-file-name "app") + (expand-file-name "lib") + (expand-file-name "test")) + 'ruby + ))) + (ffip-project-files)) + + (defun ffip-find-file-in-rails (file) + (interactive + (list (if (memq ido-mode '(file 'both)) + (ido-completing-read + "Find file in project: " + (mapcar 'car (ffip-rails-project-files))) + (completing-read "Find file in project: " + (mapcar 'car (rails-project-files)))))) + (find-file (cdr (assoc file ffip-project-files-table)))) + + (define-key ruby-mode-map (kbd "C-x C-M-f") 'find-file-in-rails) + (eval-after-load 'nxhtml-mode + '(define-key nxhtml-mode-map (kbd "C-x C-M-f") 'find-file-in-rails)))) + +(provide 'ffip) +;;; ffip.el ends here diff --git a/emacs.d/nxhtml/util/fold-dwim.el b/emacs.d/nxhtml/util/fold-dwim.el new file mode 100644 index 0000000..11b3a3d --- /dev/null +++ b/emacs.d/nxhtml/util/fold-dwim.el @@ -0,0 +1,466 @@ +;;; fold-dwim.el -- Unified user interface for Emacs folding modes +;; +;; Copyright (C) 2004 P J Heslin +;; +;; Author: Peter Heslin +;; URL: http://www.dur.ac.uk/p.j.heslin/Software/Emacs/Download/fold-dwim.el +(defconst fold-dwim:version "1.4") +;; +;; 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. +;; +;; If you do not have a copy of the GNU General Public License, you +;; can obtain one by writing to the Free Software Foundation, Inc., 59 +;; Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;;; Overview: +;; +;; DWIM stands for "do what I mean", as in the idea that one keystroke +;; can do different things depending on the context. In this package, +;; it means that, if the cursor is in a currently hidden folded +;; construction, we want to show it; if it's not, we want to hide +;; whatever fold the cursor is in. +;; +;; Some editors other than Emacs provide a single mechanism for +;; folding text which various file types can exploit. The advantage +;; of this arrangement is that the user only has to know one set of +;; folding commands; the disadvantage is that the various file types +;; are limited to using whatever functionality is provided centrally. +;; Emacs by contrast provides a very general and powerful framework +;; for hiding text, which major modes can use as they see fit. The +;; advantage of this is that each major mode can deal with folding in +;; the way that is suitable for that type of file; the disadvantage is +;; that different major modes have different styles of folding, and +;; provide different key bindings. +;; +;; In practice, matters are simpler than that, since most major modes +;; delegate the task of folding to packages like outline.el and +;; hideshow.el. The key bindings for these two packages alone, +;; however, are numerous and for some people hard to type. Another +;; usability complication arises when a package like AucTeX uses +;; outline-minor-mode for some folds, and provides its own +;; key-bindings for other kinds of folds. Likewise, nXML-mode +;; provides its own style of folding for certain types of files, but +;; for files that don't fit that paradigm (such as XHTML), you may +;; want to use outline-minor-mode instead. +;; +;; The goal of this package is to reduce this complexity to three +;; globally-defined keystrokes: one to toggle the state of the fold at +;; point, whatever its type may be, one to hide all folds of all types +;; in the buffer, and one to show all folds. +;; +;; This package currently knows about folding-mode (from folding.el), +;; hs-minor-mode (from hideshow.el), outline-minor-mode (from +;; outline.el), TeX-fold-mode (from AUCTeX), and nXML-mode outlining. +;; More could be added. It is not necessary to have folding.el, +;; AUCTeX or nXML-mode installed, if you just want to use it with the +;; built-in modes. + +;;; Usage: +;; +;; You will need to have one or more of following minor modes switched +;; on: hs-minor-mode, outline-minor-mode, TeX-fold-mode, folding-mode. +;; Otherwise no folds may be found. There are three functions to try: +;; +;; fold-dwim-toggle: try to show any hidden text at the cursor; if no +;; hidden text is found, try to hide the text at the cursor. +;; +;; fold-dwim-hide-all: hide all folds in the buffer. +;; +;; fold-dwim-show-all: show all folds in the buffer. + +;;; Configuration +;; +;; This package binds no keys by default, so you need to find three +;; free and convenient key-bindings. This is what I use: +;; +;; (global-set-key (kbd "") 'fold-dwim-toggle) +;; (global-set-key (kbd "") 'fold-dwim-hide-all) +;; (global-set-key (kbd "") 'fold-dwim-show-all) +;; + +;;; Advanced Configuration +;; +;; With respect to outline-minor-mode (or outline-mode), dwim-fold +;; provides two different styles of usage. The first is a "nested" +;; style which only shows top-level headings when you fold the whole +;; buffer, and then allows you to drill down progressively through the +;; other levels. The other is a "flat" style, whereby folding the +;; entire buffer shows all headings at every level. +;; +;; The default is "flat", but if you want to change the default, you +;; can set the value of fold-dwim-outline-style-default to be 'flat or +;; 'nested. If you wish to override the default for a particular +;; major mode, put a value of either 'flat or 'nested for the +;; fold-dwim-outline-style property of the major-mode symbol, like so: +;; +;; (put 'org-mode 'fold-dwim-outline-style 'nested) +;; +;; At present, there is no way to customize nXML-mode outlining to use +;; the nested style, since it is not really supported by that mode +;; (there is no function to hide all text and subheadings in the +;; buffer). + +;;; Compatibility +;; +;; Tested with GNU Emacs CVS (from Sept. 10, 2004), AUCTeX version +;; 11.53, nxml-mode version 20041004, folding.el version 2.97. +;; +;; If there are any other important major or minor modes that do +;; folding and that could usefully be handled in this package, please +;; let me know. + +;;; Bugs +;; +;; It is possible that some of the various folding modes may interact +;; badly if used together; I have not tested all permutations. +;; +;; The function fold-dwim-hide tries various folding modes in +;; succession, and stops when it finds one that successfully makes a +;; fold at point. This means that the order in which those modes are +;; tried is significant. I have not spent a lot of time thinking +;; about what the optimal order would be; all I care about is that +;; hideshow and TeX-fold have priority over outline-minor-mode (since +;; for me they usually fold smaller chunks of the file). +;; +;; I don't use folding.el myself, so that functionality is not well +;; tested. + +;;; Changes +;; +;; 1.0 Initial release +;; 1.1 Bugfix: test if folding-mode is bound +;; 1.2 fold-dwim-hide-all and -show-all operate only on active region +;; in transient-mark-mode. +;; 1.3 Added outline-mode (Lennart Borgman) +;; 1.4 Removed nxml-mode style folding (Lennart Borgman) +;; + some functions used by nXhtml. + +(require 'outline) +(require 'hideshow) + +;;;###autoload +(defgroup fold-dwim nil + "Unified interface to folding commands" + :prefix "fold-dwim-" + :group 'editing) + +(defcustom fold-dwim-outline-style-default 'flat + "Default style in which to fold in outline-minor-mode: 'nested or + 'flat." + :type '(choice (const :tag "Flat (show all headings)" flat) + (const :tag "Nested (nest headings hierarchically)" nested)) + :group 'fold-dwim) + +(defvar fold-dwim-toggle-selective-display 'nil + "Set this non-nil to make fold-dwim functions use selective + display (folding of all lines indented as much or more than the + current line). Probably only useful for minor modes like + makefile-mode that don't provide a more intelligent way of + folding.") + +(make-variable-buffer-local + 'fold-dwim-toggle-selective-display) + +(defun fold-dwim-maybe-recenter () + "It's annoyingly frequent that hiding a fold will leave you +with point on the top or bottom line of the screen, looking at +nothing but an ellipsis. TODO: only recenter if we end up near +the top or bottom of the screen" + (recenter)) + +(defun fold-dwim-toggle-selective-display () + "Set selective display to indentation of current line" + (interactive) + (if (numberp selective-display) + (set-selective-display nil) + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (let ((col (current-column))) + (if (zerop col) + (set-selective-display nil) + (set-selective-display col)))))) + +(defun fold-dwim-hide-all () + "Hide all folds of various kinds in the buffer or region" + (interactive) + (save-excursion + (save-restriction + (when (and transient-mark-mode mark-active) + (narrow-to-region (region-beginning) (region-end))) + (when (and (boundp 'TeX-fold-mode) TeX-fold-mode) + (TeX-fold-buffer)) + (when hs-minor-mode + (hs-hide-all)) + (when (or outline-minor-mode (eq major-mode 'outline-mode)) + (if (fold-dwim-outline-nested-p) + (hide-sublevels 1) + (hide-body))) + ;; (when (derived-mode-p 'nxml-mode) + ;; (nxml-hide-all-text-content)) + (when (and (boundp 'folding-mode) folding-mode) + (folding-whole-buffer)))) + (fold-dwim-maybe-recenter)) + +(defun fold-dwim-show-all () + "Show all folds of various kinds in the buffer or region" + (interactive) + (save-excursion + (save-restriction + (when (and transient-mark-mode mark-active) + (narrow-to-region (region-beginning) (region-end))) + (when (and (boundp 'TeX-fold-mode) TeX-fold-mode) + (TeX-fold-clearout-buffer)) + (when hs-minor-mode + (hs-show-all)) + ;; (when (derived-mode-p 'nxml-mode) + ;; (nxml-show-all)) + (when (or outline-minor-mode (eq major-mode 'outline-mode)) + (show-all)) + (when (and (boundp 'folding-mode) folding-mode) + (folding-open-buffer)) + (when fold-dwim-toggle-selective-display + (set-selective-display 'nil))))) + +(defun fold-dwim-hide () + "Hide one item" + (or (and (boundp 'TeX-fold-mode) + TeX-fold-mode + (let ((type (fold-dwim-auctex-env-or-macro))) + (when type + (TeX-fold-item type)))) + ;; Look for html headers. + (when (and (derived-mode-p 'nxml-mode 'html-mode) + outline-minor-mode) + (when (save-excursion + (save-match-data + (looking-back (rx "<" (optional "/") + "h" (any "1-6") + (0+ (not (any "<"))))))) + (hide-entry) + t)) + (and hs-minor-mode + (when (save-excursion + (or (hs-find-block-beginning) (hs-inside-comment-p))) + (hs-hide-block) + (hs-already-hidden-p))) + ;; (and (derived-mode-p 'nxml-mode) + ;; (condition-case nil + ;; (save-excursion + ;; (nxml-back-to-section-start)) + ;; (error nil)) + ;; (nxml-hide-text-content)) + (and (boundp 'folding-mode) + folding-mode + (condition-case nil + (save-excursion + (folding-hide-current-entry) + t) + (error nil))) + (when (or outline-minor-mode (eq major-mode 'outline-mode)) + (if (fold-dwim-outline-nested-p) + (hide-subtree) + (hide-entry)))) + (fold-dwim-maybe-recenter)) + + +(defun fold-dwim-show () + "If point is in a closed or temporarily open fold, + open it. Returns nil if nothing was done" + (save-excursion + (let ((stop)) + (when (and (or outline-minor-mode (eq major-mode 'outline-mode)) + (or (fold-dwim-outline-invisible-p (line-end-position)) + (and (bolp) + (not (bobp)) + (fold-dwim-outline-invisible-p (1- (point)))))) + (if (not (fold-dwim-outline-nested-p)) + (show-entry) + (show-children) + (show-entry)) + (setq stop "outline-minor-mode")) + (when (and (not stop) + hs-minor-mode + (hs-already-hidden-p)) + (hs-show-block) + (setq stop "hs-minor-mode")) + (when (and (not stop) + (boundp 'TeX-fold-mode) + TeX-fold-mode) + (let ((overlays (overlays-at (point)))) + (while overlays + (when (eq (overlay-get (car overlays) 'category) 'TeX-fold) + (delete-overlay (car overlays)) + (setq stop "Tex-fold-mode")) + (setq overlays (cdr overlays))))) + ;; (when (and (not stop) + ;; (derived-mode-p 'nxml-mode)) + ;; (let ((overlays (overlays-at (point)))) + ;; (while (and overlays (not stop)) + ;; (when (overlay-get (car overlays) 'nxml-outline-display) + ;; (setq stop "nxml folding")) + ;; (setq overlays (cdr overlays)))) + ;; (when stop + ;; (nxml-show))) + (when (and (not stop) + (boundp 'folding-mode) + folding-mode + (save-excursion + (beginning-of-line) + (let ((current-line-mark (folding-mark-look-at))) + (when (and (numberp current-line-mark) + (= current-line-mark 0)) + (folding-show-current-entry) + (setq stop "folding-mode")))))) + stop))) + +;;;###autoload +(defun fold-dwim-toggle () + "Toggle visibility or some other visual things. +Try toggling different visual things in this order: + +- Images shown at point with `inlimg-mode' +- Text at point prettified by `html-write-mode'. + +For the rest it unhides if possible, otherwise hides in this +order: + +- `org-mode' header or something else using that outlines. +- Maybe `fold-dwim-toggle-selective-display'. +- `Tex-fold-mode' things. +- In html if `outline-minor-mode' and after heading hide content. +- `hs-minor-mode' things. +- `outline-minor-mode' things. (Turns maybe on this.) + +It uses `fold-dwim-show' to show any hidden text at point; if no +hidden fold is found, try `fold-dwim-hide' to hide the +construction at the cursor. + +Note: Also first turn on `fold-dwim-mode' to get the keybinding +for this function from it." + (interactive) + (fold-dwim-mode 1) + (cond + ((get-char-property (point) 'html-write) + (html-write-toggle-current-tag)) + ((get-char-property (point) 'inlimg-img) + (inlimg-toggle-display (point))) + ((eq major-mode 'org-mode) + (org-cycle)) + ((and (fboundp 'outline-cycle) + outline-minor-mode) + (outline-cycle)) + (t + (unless (or outline-minor-mode hs-minor-mode) + (outline-minor-mode 1)) + (if fold-dwim-toggle-selective-display + (fold-dwim-toggle-selective-display) + (let ((unfolded (fold-dwim-show))) + (if unfolded + (message "Fold DWIM showed: %s" unfolded) + (fold-dwim-hide))))))) + +;;;###autoload +(define-minor-mode fold-dwim-mode + "Key binding for `fold-dwim-toggle'." + :global t + :group 'nxhtml + :group 'foldit + nil) + +;; Fix-me: Maybe move to fold-dwim and rethink? +(defvar fold-dwim-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c) ?+] 'fold-dwim-toggle) + map)) + +;;;###autoload +(defun fold-dwim-unhide-hs-and-outline () + "Unhide everything hidden by Hide/Show and Outline. +Ie everything hidden by `hs-minor-mode' and +`outline-minor-mode'." + (interactive) + (hs-show-all) + (show-all)) + +;;;###autoload +(defun fold-dwim-turn-on-hs-and-hide () + "Turn on minor mode `hs-minor-mode' and hide. +If major mode is derived from `nxml-mode' call `hs-hide-block' +else call `hs-hide-all'." + (interactive) + (hs-minor-mode 1) + (foldit-mode 1) + (if (derived-mode-p 'nxml-mode) + (hs-hide-block) + (hs-hide-all))) + +;;;###autoload +(defun fold-dwim-turn-on-outline-and-hide-all () + "Turn on `outline-minor-mode' and call `hide-body'." + (interactive) + (outline-minor-mode 1) + (foldit-mode 1) + (hide-body)) + +(defun fold-dwim-auctex-env-or-macro () + (let ((type (cond + ;; Fold macro before env, unless it's begin or end + ((save-excursion + (let ((macro-start (TeX-find-macro-start))) + (and macro-start + (not (= macro-start (point))) + (goto-char macro-start) + (not (looking-at + (concat (regexp-quote TeX-esc) + "\\(begin\\|end\\)[ \t]*{")))))) + 'macro) + ((and (eq major-mode 'context-mode) + (save-excursion + (ConTeXt-find-matching-start) (point))) + 'env) + ((and (eq major-mode 'texinfo-mode) + (save-excursion + (Texinfo-find-env-start) (point))) + 'env) + ((and (eq major-mode 'latex-mode) + (condition-case nil + (save-excursion + (LaTeX-find-matching-begin) (point) + (not (looking-at "\\\\begin[ \t]*{document}"))) + (error nil))) + 'env) + (t + nil)))) + type)) + +(defun fold-dwim-outline-invisible-p (pos) + "The version of this function in outline.el doesn't work so + well for our purposes, because it doesn't distinguish between + invisibility caused by outline, and that of other modes." + (save-excursion + (goto-char pos) + (let ((overlays (overlays-at (point))) + (found-one)) + (while overlays + (when (eq (overlay-get (car overlays) 'invisible) 'outline) + (setq found-one t)) + (setq overlays (cdr overlays))) + found-one))) + +(defun fold-dwim-outline-nested-p () + "Are we using the flat or nested style for outline-minor-mode?" + (let ((style (get major-mode 'fold-dwim-outline-style))) + (if style + (eq style 'nested) + (eq fold-dwim-outline-style-default 'nested)))) + +(provide 'fold-dwim) diff --git a/emacs.d/nxhtml/util/foldit.el b/emacs.d/nxhtml/util/foldit.el new file mode 100644 index 0000000..0ffacc3 --- /dev/null +++ b/emacs.d/nxhtml/util/foldit.el @@ -0,0 +1,357 @@ +;;; foldit.el --- Helpers for folding +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-08-10 Mon +;; Version: +;; Last-Updated: +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Defines `foldit-mode' which puts visual clues on hidden regions. +;; Does not do any folding itself but works with `outline-minor-mode' +;; and `hs-minor-mode'. +;; +;; Fix-me: reveal-mode does not work with this and I have no idea why +;; ... +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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 3, 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: + +;; Fix-me: start-tag-beg/start-tag-end are workarounds for smaller +;; bugs in hs-minor-mode and outline-minor-mode. Maybe try to fix +;; them... - but there are a whole bunch of other invisibilty related +;; bugs that ought to be fixed first since otherwise it is impossible +;; to know where point goes after hiding/unhiding. + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'hideshow)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'outline)) + +(defsubst foldit-overlay-priority () + (1+ (or (and (boundp 'mlinks-link-overlay-priority) + mlinks-link-overlay-priority) + 100))) + +;;;###autoload +(defgroup foldit nil + "Customization group for foldit folding helpers." + :group 'nxhtml) + +(defvar foldit-temp-at-point-ovl nil) +(make-variable-buffer-local 'foldit-temp-at-point-ovl) + +;;;###autoload +(define-minor-mode foldit-mode + "Minor mode providing visual aids for folding. +Shows some hints about what you have hidden and how to reveal it. + +Supports `hs-minor-mode', `outline-minor-mode' and major modes +derived from `outline-mode'." + :lighter nil + (if foldit-mode + (progn + ;; Outline + (add-hook 'outline-view-change-hook 'foldit-outline-change nil t) + ;; Add our overlays + (when (or (and (boundp 'outline-minor-mode) outline-minor-mode) + ;; Fix-me: mumamo + (derived-mode-p 'outline-mode)) (foldit-outline-change)) + ;; hs + (unless (local-variable-p 'hs-set-up-overlay) + (set (make-local-variable 'hs-set-up-overlay) 'foldit-hs-set-up-overlay)) + ;; Add our overlays + (when (or (and (boundp 'hs-minor-mode) hs-minor-mode)) + (save-restriction + (widen) + (let (ovl) + (dolist (ovl (overlays-in (point-min) (point-max))) + (when (eq (overlay-get ovl 'invisible) 'hs) + (funcall hs-set-up-overlay ovl))))))) + ;; Outline + (remove-hook 'outline-view-change-hook 'foldit-outline-change t) + ;; hs + (when (and (local-variable-p 'hs-set-up-overlay) + (eq hs-set-up-overlay 'foldit-hs-set-up-overlay)) + (kill-local-variable 'hs-set-up-overlay)) + ;; Remove our overlays + (save-restriction + (widen) + (let (ovl prop) + (dolist (ovl (overlays-in (point-min) (point-max))) + (when (setq prop (overlay-get ovl 'foldit)) + (case prop + ;;('display (overlay-put ovl 'display nil)) + ('foldit (delete-overlay ovl)) + (t (delete-overlay ovl)) + ))))))) + +(defcustom foldit-avoid '(org-mode) + "List of major modes to avoid." + :group 'foldit) + +;;;###autoload +(define-globalized-minor-mode foldit-global-mode foldit-mode + (lambda () (foldit-mode 1)) + :group 'foldit) + +(defun foldit-hidden-line-str (hidden-lines type) + "String to display for hidden lines. +HIDDEN-LINES are the number of lines and TYPE is a string +indicating how they were hidden." + (propertize (format " ...(%d %slines)" hidden-lines type) + 'face 'shadow)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Outline + +(defvar foldit-outline-keymap + (let ((map (make-sparse-keymap))) + (define-key map "\r" 'foldit-outline-show-entry) + (define-key map [down-mouse-1] 'foldit-outline-show-entry) + (define-key map [S-tab] 'mlinks-backward-link) + (define-key map [tab] 'mlinks-forward-link) + (define-key map "\t" 'mlinks-forward-link) + map)) + +(defun foldit-outline-change () + "Check outline overlays. +Run this in `outline-view-change-hook'." + ;; We get the variables FROM and TO here from `outline-flag-region' + ;; so let us use them. But O is hidden... + (let* (from + to + num-lines + ovl + (tag "")) + (cond + ((and (boundp 'start) + start + (boundp 'end) + end) + (setq from start) + (setq to end)) + (t + (setq from (point-min)) + (setq to (point-max)))) + (dolist (ovl (overlays-in from to)) + (when (eq (overlay-get ovl 'invisible) 'outline) + (setq num-lines (count-lines (overlay-start ovl) (overlay-end ovl))) + (overlay-put ovl 'display (concat + (propertize "+" 'face 'mode-line) + "" + tag (foldit-hidden-line-str num-lines ""))) + (overlay-put ovl 'foldit 'display) ;; Should be a list... + (overlay-put ovl 'keymap foldit-outline-keymap) + (overlay-put ovl 'face 'lazy-highlight) + (overlay-put ovl 'mouse-face 'highlight) + (overlay-put ovl 'help-echo "Press RET to show hidden part") + (overlay-put ovl 'mlinks-link t) + (overlay-put ovl 'priority (foldit-overlay-priority)) + (mumamo-with-buffer-prepared-for-jit-lock + (let* ((start-tag-beg (overlay-start ovl)) + (start-tag-end start-tag-beg)) + (put-text-property start-tag-beg (+ start-tag-beg 1) + 'foldit-tag-end (copy-marker start-tag-end)))) + )))) + +(defvar foldit-outline-hide-again-keymap + (let ((map (make-sparse-keymap))) + (define-key map "\r" 'foldit-outline-hide-again) + (define-key map [down-mouse-1] 'foldit-outline-hide-again) + (define-key map [S-tab] 'mlinks-backward-link) + (define-key map [tab] 'mlinks-forward-link) + (define-key map "\t" 'mlinks-forward-link) + map)) + +(defun foldit-outline-show-entry () + "Show hidden entry." + (interactive) + (let ((tag-end (get-text-property (point) 'foldit-tag-end))) + (show-entry) + (mumamo-with-buffer-prepared-for-jit-lock + (set-text-properties (point) (+ (point) 2) 'foldit-tag-end)) + (when tag-end (goto-char tag-end)) + (foldit-add-temp-at-point-overlay "-" + foldit-outline-hide-again-keymap + "Press RET to hide again"))) + +(defun foldit-outline-hide-again () + "Hide entry again." + (interactive) + (when (overlayp foldit-temp-at-point-ovl) + (delete-overlay foldit-temp-at-point-ovl)) + (hide-entry)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Hide/Show + +(defvar foldit-hs-start-tag-end-func 'foldit-hs-default-start-tag-end) +(make-variable-buffer-local 'foldit-hs-start-tag-end-func) +(put 'foldit-hs-start-tag-end-func 'permanent-local t) + +(defun foldit-hs-default-start-tag-end (beg) + "Find end of hide/show tag beginning at BEG." + (min (+ beg 65) + (save-excursion + (goto-char beg) + (line-end-position)))) + +(defvar foldit-hs-keymap + (let ((map (make-sparse-keymap))) + (define-key map "\r" 'foldit-hs-show-block) + (define-key map [down-mouse-1] 'foldit-hs-show-block) + (define-key map [S-tab] 'mlinks-backward-link) + (define-key map [tab] 'mlinks-forward-link) + (define-key map "\t" 'mlinks-forward-link) + map)) + +(defvar foldit-hs-hide-again-keymap + (let ((map (make-sparse-keymap))) + (define-key map "\r" 'foldit-hs-hide-again) + (define-key map [down-mouse-1] 'foldit-hs-hide-again) + (define-key map [S-tab] 'mlinks-backward-link) + (define-key map [tab] 'mlinks-forward-link) + (define-key map "\t" 'mlinks-forward-link) + map)) + +(defun foldit-hs-set-up-overlay (ovl) + "Set up overlay OVL for hide/show." + (let* ((num-lines (count-lines (overlay-start ovl) (overlay-end ovl))) + (here (point)) + (start-tag-beg (overlay-start ovl)) + (start-tag-end (funcall foldit-hs-start-tag-end-func start-tag-beg)) + (tag (buffer-substring start-tag-beg start-tag-end))) + (goto-char here) + ;;(overlay-put ovl 'isearch-open-invisible t) + (overlay-put ovl 'display (concat + (propertize "+" 'face 'mode-line) + " " + tag (foldit-hidden-line-str num-lines "h"))) + (overlay-put ovl 'foldit 'display) + (overlay-put ovl 'keymap foldit-hs-keymap) + (overlay-put ovl 'face 'next-error) + (overlay-put ovl 'face 'lazy-highlight) + (overlay-put ovl 'mouse-face 'highlight) + (overlay-put ovl 'help-echo "Press RET to show hidden part") + (overlay-put ovl 'mlinks-link t) + (overlay-put ovl 'priority (foldit-overlay-priority)) + (mumamo-with-buffer-prepared-for-jit-lock + (put-text-property start-tag-beg (+ start-tag-beg 1) + 'foldit-tag-end (copy-marker start-tag-end))))) + +(defun foldit-hs-show-block () + "Show hidden block." + (interactive) + (let ((tag-end (get-text-property (point) 'foldit-tag-end))) + (hs-show-block) + (mumamo-with-buffer-prepared-for-jit-lock + (set-text-properties (point) (+ (point) 2) 'foldit-tag-end)) + (when tag-end (goto-char tag-end)) + (foldit-add-temp-at-point-overlay "-" + foldit-hs-hide-again-keymap + "Press RET to hide again"))) + +(defun foldit-hs-hide-again () + "Hide hide/show block again." + (interactive) + (when (overlayp foldit-temp-at-point-ovl) + (delete-overlay foldit-temp-at-point-ovl)) + (hs-hide-block)) + + +;;; Fix-me: break out this +;; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +(defun foldit-add-temp-at-point-overlay (marker keymap msg) + "Add a temporary overlay with a marker MARKER and a keymap KEYMAP. +The overlay is also given the help echo MSG. + +This overlay is removed as soon as point moves from current point." + (let ((ovl (make-overlay (point) (1+ (point)))) + (real (buffer-substring (point) (1+ (point))))) + (overlay-put ovl 'isearch-open-invisible t) + (overlay-put ovl 'display (concat + (propertize marker 'face 'mode-line) + " " + msg + real)) + (overlay-put ovl 'foldit 'foldit) + (overlay-put ovl 'keymap keymap) + (overlay-put ovl 'face 'lazy-highlight) + (overlay-put ovl 'mouse-face 'highlight) + (overlay-put ovl 'help-echo msg) + (overlay-put ovl 'mlinks-link t) + (overlay-put ovl 'priority (foldit-overlay-priority)) + (setq foldit-temp-at-point-ovl ovl) + (add-hook 'post-command-hook + 'foldit-remove-temp-at-point-overlay + nil t))) + +(defun foldit-remove-temp-at-point-overlay () + "Remove overlay made by `foldit-add-temp-at-point-overlay'." + (condition-case err + (unless (and foldit-temp-at-point-ovl + (overlay-buffer foldit-temp-at-point-ovl) + (= (overlay-start foldit-temp-at-point-ovl) + (point))) + (delete-overlay foldit-temp-at-point-ovl) + (setq foldit-temp-at-point-ovl nil) + (remove-hook 'post-command-hook 'foldit-remove-temp-at-point-overlay t) + ) + (error (message "foldit-remove-temp-at-point-overlay: %s" + (propertize (error-message-string err)))))) +;; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + +;; (defun put-before-on-invis () +;; (let* (o +;; (io (catch 'io +;; (dolist (o (overlays-at (1+ (point)))) +;; (when (overlay-get o 'invisible) +;; (throw 'io o))))) +;; (str (propertize "IOSTRING" +;; 'face 'secondary-selection +;; ))) +;; (overlay-put io 'before-string str) +;; ;;(overlay-put io 'display "display") +;; (overlay-put io 'display nil) +;; ;;(overlay-put io 'after-string "AFTER") +;; )) + +(provide 'foldit) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; foldit.el ends here diff --git a/emacs.d/nxhtml/util/fupd.el b/emacs.d/nxhtml/util/fupd.el new file mode 100644 index 0000000..bb8b3af --- /dev/null +++ b/emacs.d/nxhtml/util/fupd.el @@ -0,0 +1,127 @@ +;;; fupd.el --- Helper functions for updating files +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Tue Feb 28 17:21:20 2006 +;; Version: 0.1 +;; Last-Updated: Tue Feb 20 21:09:20 2007 (3600 +0100) +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Helper functions for updating files. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(defun fupd-has-contents (file content) + "Check if file FILE contains CONTENT. +Return a vector with these elements: +- elt 0: t if file contains CONTENT and buffer is not modified. +- elt 1: t if file contains CONTENT. +- elt 2: file buffer if file exists. +- elt 3: nil unless file already was in a buffer." + (let (ok same buffer old-buffer) + (when (file-exists-p file) + (setq buffer (get-file-buffer file)) + (setq old-buffer (when buffer t)) + (unless buffer + (setq buffer (find-file-noselect file))) + (with-current-buffer buffer + (setq same (string= + content + (buffer-substring-no-properties + (point-min) (point-max))))) + (setq ok (and same + (not (buffer-modified-p buffer))))) + (vector ok same buffer old-buffer))) + +(defun fupd-ok (ret-val) + "Return t if RET-VAL indicate file is uptodate. +RET-VAL should be the return value from `fupd-has-contents'." + (elt ret-val 0)) + +(defun fupd-kill-new-buffer (ret-val) + "Kill new buffer indicated by RET-VAL. +RET-VAL should be the return value from `fupd-has-contents'." + (unless (elt ret-val 3) + (let ((buffer (elt ret-val 2))) + (when (bufferp buffer) + ;;(message "fupd-kill-new-buffer: %s" (buffer-file-name buffer))(sit-for 4) + (kill-buffer buffer))))) + +;;(fupd-has-contents buffer-file-name (buffer-string)) +;;(fupd-update-file buffer-file-name (buffer-string)) +(defun fupd-update-file (file content) + "Update file FILE with content CONTENT. +Do nothing if the file already has that content. If the file was +not in a buffer before kill the file's buffer afterwards. + +Return t if the file was updated, otherwise nil." + (let* ((osbo (fupd-has-contents file content)) + (ok (elt osbo 0)) + (same (elt osbo 1)) + (buff (elt osbo 2)) + (oldb (elt osbo 3)) + wrote + ) + (unless ok + (if buff + (with-current-buffer buff + (unless same + (erase-buffer) + (insert content)) + (save-buffer) + (setq wrote t) + (unless oldb + (kill-buffer (current-buffer)))) + (with-temp-buffer + (insert content) + (write-file file)))) + wrote)) + +;; (defun fupd-copy-file (from-file to-file) +;; (let ( +;; (from-buff (find-buffer-visiting from-file)) +;; (to-buff (find-buffer-visiting to-file)) +;; (from-attr (file-attributes from-file)) +;; (to-attr (file-attributes to-file)) +;; (from-size (nth 7 from-attr)) +;; (to-size (nth 7 to-attr)) +;; (from-mod (nth 5 from-attr)) +;; (to-mode (nth 5 to-attr)) +;; ) +;; )) + +(provide 'fupd) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; fupd.el ends here diff --git a/emacs.d/nxhtml/util/gimpedit.el b/emacs.d/nxhtml/util/gimpedit.el new file mode 100644 index 0000000..e624e9f --- /dev/null +++ b/emacs.d/nxhtml/util/gimpedit.el @@ -0,0 +1,172 @@ +;;; gimpedit.el --- Edit files with GIMP +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Wed May 23 14:59:50 2007 +(defconst gimpedit:version "0.31") ;;Version: +;; Last-Updated: 2009-11-03 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `setup-helper', `w32-reg-iface', `w32-regdat'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Simple interface to start editing with GIMP. +;; +;; If you want to edit files from within Emacs see the doc string of +;; `gimpedit-edit-buffer'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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-and-compile (require 'w32-regdat nil t)) + +;; (message "%S" (gimpedit-get-remote-command)) +(defun gimpedit-get-remote-command () + (if (featurep 'w32-regdat) + (save-match-data + (let ((cmd (w32-regdat-gimp-win-remote-cmd)) + cmd-list) + (while (< 0 (length cmd)) + (cond + ((or (string-match (rx string-start + ?\" + (submatch + (0+ (not (any ?\")))) + ?\" + (0+ space)) + cmd) + (string-match (rx string-start + (submatch + (0+ (not (any space)))) + (0+ space)) + cmd)) + (setq cmd-list (cons (match-string-no-properties 1 cmd) cmd-list)) + (setq cmd (substring cmd (match-end 0)))))) + (cadr cmd-list))) + (if (memq system-type '(windows-nt)) + (let (prog) + (catch 'found-prog + (dolist (num '(2 3 4 5 6 7 8 9)) + (setq prog (concat (getenv "ProgramFiles") + "\\GIMP-2.0\\bin\\gimp-2." + (number-to-string num) + ".exe")) + (when (file-exists-p prog) + (throw 'found-prog prog))))) + "gimp"))) + +;;;###autoload +(defgroup gimpedit nil + "Customization group for GIMP." + :group 'external + :group 'nxhtml) + +(defcustom gimpedit-remote-command (gimpedit-get-remote-command) + "Program name to use when calling GIMP remotely. +This could be be the full path to the program used when opening +files with GIMP or a just the program file name if it is in the +executables path. + +Example: + + The value is fetched from the registry on MS Windows if + possible or is else given the default value: + + \"C:\\Program Files\\GIMP-2.0\\bin\\gimp-2.6.exe\" + + On other system it has the default value + + \"gimp\"." + :type '(choice (file :tag "Full file name" :must-match t) + (string :tag "File name (must be in path)")) + :group 'gimpedit) + +;;;###autoload +(defun gimpedit-edit-file (image-file &optional extra-args) + "Edit IMAGE-FILE with GIMP. +See also `gimpedit-edit-file'." + (interactive (list (or (get-char-property (point) 'image-file) + (read-file-name "Image to edit in GIMP: ")))) + (setq image-file (expand-file-name image-file)) + (apply 'call-process gimpedit-remote-command + nil + 0 + nil + (reverse (cons image-file (reverse extra-args)))) + (let ((msg " Asked GIMP to open %s - you may have to switch to GIMP")) + (put-text-property 0 (length msg) 'face 'highlight msg) + (message msg (file-name-nondirectory image-file)))) + +;;;###autoload +(defun gimpedit-edit-buffer () + "Edit image file in current buffer with GIMP. +See also `gimpedit-edit-file'. + +You may also be interested in gimpedit-mode with which you can edit +gimp files from within Emacs using GIMP's scripting +possibilities. See + + URL `http://www.emacswiki.org/emacs/GimpMode'" + (interactive) + (unless (buffer-file-name) + (error + "Can't edit in GIMP because this buffer does not have a file name.")) + (gimpedit-edit-file (buffer-file-name))) + +;;;###autoload +(defun gimpedit-can-edit (file-name) + (and file-name + (member (downcase (file-name-extension file-name)) + '("png" "gif" "jpg" "jpeg")))) + +;; (defcustom gimpedit-point-key-bindings '(([(control ?c) ?&] gimpedit-edit-file)) +;; "Key bindings suggested for image links etc." +;; :type '(repeat (list key-sequence function)) +;; :group 'gimpedit) + +;; (defun gimpedit-add-point-bindings (map) +;; "Add `gimpedit-point-key-bindings' to point keymap MAP. +;; Set it up like this: + +;; (eval-after-load 'gimpedit +;; '(gimpedit-add-point-bindings MY-MAP)) + +;; There must also be a character property `image-file' at point for this +;; to work." +;; (dolist (binding gimpedit-point-key-bindings) +;; (let ((key (nth 0 binding)) +;; (fun (nth 1 binding))) +;; (define-key map key fun)))) + +(provide 'gimpedit) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; gimpedit.el ends here diff --git a/emacs.d/nxhtml/util/gpl.el b/emacs.d/nxhtml/util/gpl.el new file mode 100644 index 0000000..a109555 --- /dev/null +++ b/emacs.d/nxhtml/util/gpl.el @@ -0,0 +1,213 @@ +;;; gpl.el --- Highlight and edit gpl color palettes + +(defconst gpl:version "0.01") +;; Copyright (C) 2008 Niels Giesen + +;; Author: Niels Giesen +;; Keywords: extensions, tools + +;; 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 3 of the License, 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. If not, see . + +;;; Commentary: + +;; GPL provides font-locking and has functions to edit the values +;; of colors (hue, saturation value, red, green and blue vals) +;; in-place in a simple, intuitive, and lightweight fashion. See the +;; documentation of `gpl-mode'. + +;; The methods and keybindings used are roughly the same as in the new +;; css-color mode. I should maybe have abstracted both color notation +;; models better, but did not feel like it. With under 200 lines of +;; code, it did not seem worth the effort. + +;; The css-color.el used is the one by Niels Giesen, at +;; `http://niels.kicks-ass.org/public/elisp/css-color.el'. + +;; Installation: + +;; Put this file in your load-path. Put a declaration such as + +;; (autoload 'gpl-mode "gpl") +;; (add-to-list 'auto-mode-alist +;; '("\\.gpl\\'" . gpl-mode)) + +;; In your initialization file (e.g. ~/.emacs) to make sure `gpl-mode' +;; is started anytime you open a *.gpl file, and gpl-mode is only +;; loaded when needed. + +;;; Code: +(require 'css-color) + +(defvar gpl-keywords + '(("^[[:space:]]*\\([a-fA-F[:digit:]]\\{1,3\\}\\)[[:space:]]+\\([a-fA-F[:digit:]]\\{1,3\\}\\)[[:space:]]+\\([a-fA-F[:digit:]]\\{1,3\\}\\)" + (0 + (let ((color (concat "#" (apply 'css-color-rgb-to-hex + (mapcar 'string-to-number + (list + (match-string-no-properties 1) + (match-string-no-properties 2) + (match-string-no-properties 3))))))) + + (put-text-property (match-beginning 0) + (match-end 0) + 'keymap gpl-map) + (put-text-property (match-beginning 0) + (match-end 0) + 'face (list :background + color + :foreground + (css-color-foreground-color + color)))))))) + +;;;###autoload +(define-derived-mode gpl-mode fundamental-mode "GPL" + "Mode for font-locking and editing color palettes of the GPL format. + +Such palettes are used and produced by free software applications +such as the GIMP, Inkscape, Scribus, Agave and on-line tools such +as http://colourlovers.com. + +You can also use +URL `http://niels.kicks-ass.org/public/elisp/css-palette.el' to import +such palette into a css-file as hexadecimal color palette." + (setq font-lock-defaults + '((gpl-keywords) + t))) + +(defvar gpl-map + (let ((m (make-sparse-keymap))) + (define-key m "=" 'gpl-up) + (define-key m "-" 'gpl-down) + (define-key m "h" 'gpl-hue-up) + (define-key m "H" 'gpl-hue-down) + (define-key m "v" 'gpl-value-up) + (define-key m "V" 'gpl-value-down) + (define-key m "s" 'gpl-saturation-up) + (define-key m "S" 'gpl-saturation-down) + m) + "Mode map for `gpl-mode'") + +(defun gpl-get-color-at-point () + (or (get-text-property (point) 'color) + (apply 'css-color-rgb-to-hsv + (gpl-get-rgb-list-at-point)))) + +(defun gpl-get-rgb-list-at-point () + (mapcar 'string-to-number + (split-string + (buffer-substring-no-properties + (point-at-bol) + (+ 11 (point-at-bol))) "[[:space:]]+" t))) + +(defun gpl-replcolor-at-p (fun increment) + (let ((pos (point))) + (beginning-of-line) + (insert + (funcall fun + (gpl-get-color-at-point) + increment)) + (delete-region (point) (+ (point) 11)) + (goto-char pos))) + +(defun gpl-hsv-to-gimp-color (h s v) + (propertize + (apply 'format "%3d %3d %3d" + (css-color-hsv-to-rgb h s v)) + 'keymap gpl-map + 'color (list h s v))) + +(defun gpl-what-channel () + (/ (- (point) (point-at-bol)) 4)) + +(defun gpl-adjust-channel-at-p (incr) + (interactive "p") + (let ((pos (point)) + (channel (gpl-what-channel))) + (beginning-of-line) + (let ((rgb + (gpl-get-rgb-list-at-point))) + (setf (nth channel rgb) + (css-color-within-bounds + (+ incr (nth channel rgb)) + 0 255)) + (delete-region (point) (+ 11 (point))) + (insert + (propertize + (apply 'format "%3d %3d %3d" rgb) + 'keymap gpl-map + 'color nil))) + (goto-char pos))) + +(defun gpl-inchue (color incr) + (destructuring-bind (h s v) color + (gpl-hsv-to-gimp-color + (+ incr h) s v))) + +(defun gpl-incsat (color incr) + (destructuring-bind (h s v) color + (gpl-hsv-to-gimp-color + h (css-color-within-bounds (+ incr s) 0 100) v))) + +(defun gpl-incval (color incr) + (destructuring-bind (h s v) color + (gpl-hsv-to-gimp-color + h s (css-color-within-bounds (+ incr v) 0 100)))) + +(defun gpl-adj-hue-at-p (increment) + (interactive "p") + (gpl-replcolor-at-p 'gpl-inchue increment)) + +(defun gpl-adj-saturation-at-p (increment) + (interactive "p") + (gpl-replcolor-at-p 'gpl-incsat increment)) + +(defun gpl-adj-value-at-p (increment) + (interactive "p") + (gpl-replcolor-at-p 'gpl-incval increment)) + +;; channels (r, g, b) +(defun gpl-up (val) + (interactive "p") + (gpl-adjust-channel-at-p val)) + +(defun gpl-down (val) + (interactive "p") + (gpl-adjust-channel-at-p (- val))) +;; hue +(defun gpl-hue-up (val) + (interactive "p") + (gpl-adj-hue-at-p val)) + +(defun gpl-hue-down (val) + (interactive "p") + (gpl-adj-hue-at-p (- val))) +;; saturation +(defun gpl-saturation-up (val) + (interactive "p") + (gpl-adj-saturation-at-p val)) + +(defun gpl-saturation-down (val) + (interactive "p") + (gpl-adj-saturation-at-p (- val))) +;; value +(defun gpl-value-up (val) + (interactive "p") + (gpl-adj-value-at-p val)) + +(defun gpl-value-down (val) + (interactive "p") + (gpl-adj-value-at-p (- val))) + +(provide 'gpl) +;;; gpl.el ends here diff --git a/emacs.d/nxhtml/util/hfyview.el b/emacs.d/nxhtml/util/hfyview.el new file mode 100644 index 0000000..0e0450d --- /dev/null +++ b/emacs.d/nxhtml/util/hfyview.el @@ -0,0 +1,651 @@ +;;; hfyview.el --- View current buffer as html in web browser + +;; Copyright (C) 2005, 2006, 2007 by Lennart Borgman + +;; Author: Lennart Borgman +;; Created: Fri Oct 21 2005 +(defconst hfyview:version "0.63") ;; Version: +;; Last-Updated: 2010-04-16 Fri +;; Keywords: printing +;; URL: http://OurComments.org/Emacs/DL/elisp/hfyview.el +;; Compatibility: +;; +;; +;; Features that might be required by this library: +;; + ;; `easymenu'. +;; +;; +;; htmlfontify.el is part of Emacs. +;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This file shows the current buffer in your web browser with all +;; the colors it has. The purpose is mainly to make it possible to +;; easily print what you see in Emacs in colors on different +;; platforms. +;; +;; Put this file in your load-path and in your .emacs this: +;; +;; (require 'hfyview) +;; +;; This defines the commands `hfyview-buffer', `hfyview-region' and +;; `hfyview-window' which will show the whole or a part of the buffer +;; in your web browser. +;; +;; You can add those commands to the menus by customizing +;; `hfyview-quick-print-in-files-menu' to t. This will add an entry +;; "Quick Print (Using Web Browser)" to the files menu. +;; +;; +;; There is also a command `hfyview-frame' to take a "screen shot" of +;; your current frame and produce an html look-alike page. If you +;; turn on `hfyview-frame-mode' you get this function on the +;; key in most situations. +;; +;; +;; You can see an example of the output here: +;; +;; http://ourcomments.org/Emacs/nXhtml/doc/htmlfontify-example.html +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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. +;; +;; To find out more about the GNU General Public License you can visit +;; Free Software Foundation's website http://www.fsf.org/. Or, write +;; to the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'htmlfontify)) +(require 'easymenu) + +(defvar hfyview-selected-window) + +(defvar hfyview-frame-mode-emulation-map + (let ((m (make-sparse-keymap))) + ;;(define-key m [apps] 'hfyview-frame) + m)) + +(defvar hfyview-frame-mode-emulation-maps + (list (cons 'hfyview-frame-mode hfyview-frame-mode-emulation-map))) + +;; Fix-me: which are needed? Probably only viper, but have to test. +(defconst hfyview-frame-mode-other-maps + '( + hfyview-frame-mode-emulation-map + minibuffer-local-completion-map + minibuffer-local-filename-completion-map + minibuffer-local-isearch-map + minibuffer-local-map + ;; minibuffer-local-must-match-filename-map + minibuffer-local-must-match-map + minibuffer-local-ns-map + viper-minibuffer-map + isearch-mode-map)) + +(define-minor-mode hfyview-frame-mode + "Define some useful things for `hfyview-frame'. +The key is bound to `hfyview-frame' in this mode. When +this mode is on you can push to get all of what you see on +the screen. Without it the minibuffer/echo area will not be +shown." + :global t + :group 'htmlfontify + (if hfyview-frame-mode + (progn + (add-hook 'pre-command-hook 'hfy-grab-minibuffer-content) + (add-hook 'post-command-hook 'hfy-grab-echo-content) + (add-to-list 'emulation-mode-map-alists 'hfyview-frame-mode-emulation-maps) + (dolist (map hfyview-frame-mode-other-maps) + (define-key (symbol-value map) [(apps)] 'hfyview-frame) + ) + ) + (remove-hook 'pre-command-hook 'hfy-grab-minibuffer-content) + (remove-hook 'post-command-hook 'hfy-grab-echo-content) + (setq emulation-mode-map-alists (delq 'hfyview-frame-mode-emulation-maps emulation-mode-map-alists)) + (dolist (map hfyview-frame-mode-other-maps) + (define-key (symbol-value map) [(apps)] nil)))) + +(defun hfyview-fontify-region (start end) + "Fontify region between START and END the htmlfontify way." + ;; If the last command in mumamo resulted in a change of major-mode + ;; the big bug watcher in mumamo will get us if we do not tell that + ;; we know what we are doing: + (let ((mumamo-just-changed-major nil)) + (if start + (save-restriction + (widen) + (narrow-to-region start end) + (assert (= end (point-max))) + (assert (= start (point-min))) + (htmlfontify-buffer)) + (htmlfontify-buffer)))) + +(defun hfyview-buffer-1(start end show-source) + "Convert current buffer between START and END to html. +If SHOW-SOURCE is non-nil then also show produced html in other +window." + (let ((hbuf (hfyview-fontify-region start end))) + (with-current-buffer hbuf + (setq buffer-file-name nil) + (browse-url-of-buffer)) + (when show-source (switch-to-buffer-other-window hbuf)) + hbuf)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;; Menus + +(defvar hfyview-print-menu (make-sparse-keymap "QP")) +(defvar hfyview-print-region-menu (make-sparse-keymap "QPR")) +(defvar hfyview-print-window-menu (make-sparse-keymap "QPW")) +(defun hfyview-add-to-files-menu () + "Add \"Quick Print\" entry to file menu." + ;; Why did I redo this??? + (setq hfyview-print-menu (make-sparse-keymap "QP")) + (setq hfyview-print-region-menu (make-sparse-keymap "QPR")) + (setq hfyview-print-window-menu (make-sparse-keymap "QPW")) + ;; Main + (define-key-after menu-bar-file-menu [hfyview-print] + (list 'menu-item + "Quick Print (Using Web Browser)" + hfyview-print-menu + :visible 'hfyview-print-visible) + 'separator-print) + ;; Main submenu + (define-key hfyview-print-menu [hfyview-browser-frame-pre] + '(menu-item "Print Preview Frame" hfyview-frame + :help "Print preview frame with web browser")) + (define-key hfyview-print-menu [hfyview-browser-window-pre] + '(menu-item "Print Preview Window" hfyview-window + :help "Print preview window with web browser")) + (define-key hfyview-print-menu [hfyview-browser-region-pre] + (list 'menu-item "Print Preview Region" 'hfyview-region + :help "Print preview region with web browser" + :enable 'mark-active)) + (define-key hfyview-print-menu [hfyview-separator-pre] + '(menu-item "--")) + (define-key hfyview-print-menu [hfyview-browser-pre] + '(menu-item "Print Preview Buffer" hfyview-buffer + :help "Print preview buffer with web browser" + :visible t)) + ) + +;;;###autoload +(defcustom hfyview-quick-print-in-files-menu nil + "Add Quick print entries to File menu if non-nil. +If you set this to nil you have to restart Emacs to get rid of +the Quick Print entry." + :type 'boolean + :set (lambda (sym val) + (set-default sym val) + (if val + (hfyview-add-to-files-menu))) + :group 'hfy-view) + +(defvar hfyview-print-visible t + "Non-nil means show Quick Print entry on the file menu.") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;; Interactive commands + +;;;###autoload +(defun hfyview-buffer (arg) + "Convert buffer to html preserving faces and show in web browser. +With command prefix ARG also show html source in other window." + (interactive "P") + (hfyview-buffer-1 nil nil arg)) + +;;;###autoload +(defun hfyview-region (arg) + "Convert region to html preserving faces and show in web browser. +With command prefix ARG also show html source in other window." + (interactive "P") + (hfyview-buffer-1 (region-beginning) (region-end) arg)) + +;;;###autoload +(defun hfyview-window (arg) + "Convert window to html preserving faces and show in web browser. +With command prefix ARG also show html source in other window." + (interactive "P") + (hfyview-buffer-1 (window-start) (window-end) arg)) + +;;;###autoload +(defun hfyview-frame (whole-buffers) + "Convert frame to html preserving faces and show in web browser. +Make an XHTML view of the current Emacs frame. Put it in a buffer +named *hfyview-frame* and show that buffer in a web browser. + +If WHOLE-BUFFERS is non-nil then the whole content of the buffers +is shown in the XHTML page, otherwise just the part that is +visible currently on the frame. + +If you turn on the minor mode `hfyview-frame-mode' you can also +get the minibuffer/echo area in the output. See this mode for +details. + +With command prefix also show html source in other window." + (interactive (list (y-or-n-p "Enter y for whole buffers, n for only visible part? "))) + (let ((title "Emacs - Frame Dump") + buf) + (setq title (frame-parameter (selected-frame) 'name)) + (setq buf (hfyview-frame-1 whole-buffers title)) + (when current-prefix-arg + (switch-to-buffer-other-window buf)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;; Internal commands + +(defconst hfyview-modline-format + ;; There seems to be a bug in Firefox that prevents this from + ;; displaying correctly. Anyway this is just a quick and reasonable + ;; approximation. + (concat "
" + ;; Using
 gives empty line above and below
+          ;;"
"
+          "-- (Unix)%s   %s    (%s%s) "
+          (make-string 6 ?-)
+          "%s" ;; Viper
+          (make-string 200 ?-)
+          ;;"
" + "
")) + +(defun hfyview-get-minors () + "Return string with active minor mode highlighters." + (let ((minors "")) + (dolist (mr minor-mode-alist) + (let ((mm (car mr)) + (ml (cadr mr))) + (when (symbol-value mm) + (when (stringp ml) + (setq minors (concat minors ml)))))) + minors)) + +;; (hfyview-dekludge-string " ") +(defun hfyview-dekludge-string (str) + "Return html quoted string STR." + (mapconcat (lambda (c) + (hfy-html-quote + (char-to-string c))) + (append str) + "")) + +(defvar viper-mode-string) ;; Silence compiler + +(defun hfyview-fontify-win-to (win tag whole-buffer) + "Return html code for window WIN. +Sorround the code with the html tag . +WHOLE-BUFFER corresponds to the similar argument for +`hfyview-frame-1'." + (let* ((bstart (unless whole-buffer (window-start win))) + (bend (unless whole-buffer (window-end win))) + (hbuf (hfyview-fontify-region bstart bend)) + (edges (window-edges win)) + (width (- (nth 2 edges) (nth 0 edges))) + (height (- (nth 3 edges) (nth 1 edges))) + (border-color (or (hfy-triplet "SystemActiveBorder") + "gray")) + start + end + css-start + css-end + mod-fgcolor + mod-bgcolor + mod-width + mod + bu-name + ma-name + minors + (window-start-line (point-min)) + (window-end-line (point-max)) + (is-selected-window (eq win hfyview-selected-window)) + (mark-viper "") + ) + ;; Fix-me: fetch style too + (with-current-buffer (window-buffer win) + (unless whole-buffer + (save-restriction + (widen) + (setq window-start-line (line-number-at-pos bstart)) + (setq window-end-line (line-number-at-pos bend)) + (unless (or (< (line-number-at-pos (point-min)) window-start-line) + (> (line-number-at-pos (point-max)) window-end-line)) + (setq whole-buffer t)) + ) + ) + (setq mod-fgcolor (face-attribute (if is-selected-window 'mode-line 'mode-line-inactive) :foreground)) + (setq mod-bgcolor (face-attribute (if is-selected-window 'mode-line 'mode-line-inactive) :background)) + (setq mod-fgcolor (hfy-triplet mod-fgcolor)) + (setq mod-bgcolor (hfy-triplet mod-bgcolor)) + (setq mod (if (buffer-modified-p) "**" "--")) + (when buffer-read-only + (setq mod "%%")) + (setq bu-name (buffer-name)) + (setq ma-name mode-name) + (setq minors (hfyview-get-minors)) + (when (and (local-variable-p 'viper-mode-string) viper-mode-string) + (setq mark-viper viper-mode-string)) + ) + ;; Compensate for scroll-bars + (setq mod-width (+ width 1)) + (with-current-buffer hbuf + (setq width (- width 2.5)) + (setq width (* 0.57 width)) + (setq height (+ height 2)) ;; For pre + ;;(setq height (+ height 1.2)) ;; For horisontal scrollbar + (setq height (* 1.16 height)) + (goto-char (point-min)) + (re-search-forward "") + (setq start (point)) + (insert + (format "<%s style=\"width:%sem; height:%sem; border: 1px solid %s; overflow:%s; padding:4px;\">\n" + tag width height border-color + (if whole-buffer "auto" "hidden") ;; overflow + )) + (goto-char (point-max)) + (setq end (search-backward "")) + (unless whole-buffer + (insert + (format "\n
Truncated to line %s - %s!
\n" + window-start-line window-end-line))) + (insert "\n") + ;;(lwarn t :warning "%s" mark-viper) + (insert (format hfyview-modline-format + width + mod-fgcolor mod-bgcolor mod + (hfyview-dekludge-string bu-name) + (hfyview-dekludge-string ma-name) + (hfyview-dekludge-string minors) + (hfyview-dekludge-string mark-viper))) + (setq end (point)) + (goto-char (point-min)) + (search-forward "") + (setq css-end (point)) + (set-buffer-modified-p nil) + (setq buffer-file-name nil)) + (list hbuf start end css-start css-end))) + +;; (defun hfyview-window-framed () +;; "Just a test" +;; (interactive) +;; (let* ((res (hfyview-fontify-win-to (selected-window) "div" nil)) +;; (hbuf (nth 0 res))) +;; (with-current-buffer hbuf +;; (browse-url-of-buffer)))) + +(defun hfyview-fontify-tree-win (win whole-buffer) + "Return html code for window WIN. +WHOLE-BUFFER corresponds to the similar argument for +`hfyview-frame-1'." + (with-selected-window win + (let* ((start (window-start)) + (end (window-end)) + (res (hfyview-fontify-win-to win "div" whole-buffer)) + (hbuf (nth 0 res))) + (with-current-buffer hbuf + (rename-buffer (generate-new-buffer-name (format "%s %s-%s" win start end)))) + ;;(lwarn t :warning "win=%s, hbuf=%s" win hbuf) + res))) + +(defun hfyview-fontify-tree (wt whole-buffers) + "Return list of html code for all windows in tree WT. +WT should be the result of function `window-tree' or a subtree of +this. For WHOLE-BUFFERS see `hfyview-frame-1'." + (if (not (listp wt)) + (hfyview-fontify-tree-win wt whole-buffers) + (let ((ret)) + (dolist (w (cddr wt)) + (setq ret (cons (hfyview-fontify-tree w whole-buffers) ret))) + (list (car wt) ret)))) + +(defun hfyview-frame-to-html (res) + "Return list with css and html code for frame. +RES is the collected result from `hfyview-fontify-tree'." + (let ((html "") + (css "") + (first (car res)) + (td "") + h) + (cond + ((memq first '(nil t)) + (dolist (sub (reverse (cadr res))) + (let* ((fres (hfyview-frame-to-html sub)) + (h (nth 0 fres)) + (c (nth 1 fres))) + (when first (setq h (concat "\n" h "\n"))) + (setq html (concat html h)) + (setq css (concat css c)))) + (unless first + (setq html (concat "" html "\n"))) + (setq html (concat "\n" html "
\n")) + (setq html (concat td html "\n")) + ) + ((bufferp first) + ;; (buf start end) + (let* ((buf (nth 0 res)) + (sta (nth 1 res)) + (end (nth 2 res)) + (cst (nth 3 res)) + (cnd (nth 4 res)) + (h + ;;(concat "" "temp" "\n") + (with-current-buffer buf (buffer-substring-no-properties sta end))) + (c + ;;(concat "" "temp" "\n") + (with-current-buffer buf (buffer-substring-no-properties cst cnd)))) + (setq h (concat td h + "\n")) + (setq html (concat html h)) + (setq css c) + (kill-buffer buf))) + (t + (error "Uh?"))) + (list html css))) + +(defconst hfyview-xhtml-header + " + + + + %s + +%s + + \n") + +(defvar hfyview-xhtml-footer "\n\n") + +(defun hfyview-wm-border-color () + "Return CSS code for color to use in window borders." + (or (hfy-triplet "SystemActiveTitle") + (hfy-triplet "blue"))) + +(defvar hfy-grabbed-echo-content nil) +(defvar hfy-grabbed-minibuffer-content nil) +(defvar hfyview-prompt-face nil) + +(defun hfyview-frame-minibuff (use-grabbed) + "Return html code for minibuffer. +If USE-GRABBED is non-nil use what has been grabbed by +`hfy-grab-echo-content' or `hfy-grab-minibuffer-content'. +Otherwise make a default content for the minibuffer." + (if (and use-grabbed + (or hfy-grabbed-echo-content + hfy-grabbed-minibuffer-content)) + (let* ((str (if hfy-grabbed-echo-content + hfy-grabbed-echo-content + hfy-grabbed-minibuffer-content)) + (tmpbuf (get-buffer-create "*hfy-minibuff-temp*")) + (hbuf (with-current-buffer tmpbuf + (let ((inhibit-read-only t)) + (erase-buffer) + ;; Fix-me: move the propertize to a new + ;; copy-buffer in hfy-fontify-buffer. Explained + ;; in mail to Vivek. + (insert (propertize str + 'read-only nil + 'intangible nil + 'field nil + 'modification-hooks nil + 'insert-in-front-hooks nil + 'insert-behind-hooks nil + 'point-entered nil + 'point-left nil + 'font-sticky nil + 'rear-nonsticky nil + )) + (htmlfontify-buffer)))) + bdy-start + bdy-end + bdy-txt + css-start + css-end + css-txt) + (with-current-buffer hbuf + (goto-char (point-min)) + (search-forward "") + (setq css-end (point)) + (goto-char (point-min)) + (search-forward "
")
+          (setq bdy-start (point))
+          (goto-char (point-max))
+          (search-backward "
") + (setq bdy-end (point)) + (list (buffer-substring css-start css-end) + (buffer-substring bdy-start bdy-end)))) + (let ((mini-bg (face-attribute hfyview-prompt-face :background)) + (mini-fg (face-attribute hfyview-prompt-face :foreground))) + (if (eq mini-fg 'unspecified) + (setq mini-fg "") + (setq mini-fg (concat "color:" (hfy-triplet mini-fg) "; "))) + (if (eq mini-bg 'unspecified) + (setq mini-bg "") + (setq mini-bg (concat "background:" (hfy-triplet mini-bg) "; "))) + (list nil + (concat + "" + " M-x " + "" + " " + "hfyview-frame" + ))))) + +(defun hfyview-frame-1(whole-buffers frame-title) + "Return buffer with html code for current frame. +If WHOLE-BUFFERS is non-nil then make scrollable buffers in the +html output. Otherwise just make html code for the currently +visible part of the buffers. + +FRAME-TITLE is the title to show on the resulting html page." + (let* ((wt (window-tree)) + (hfyview-selected-window (selected-window)) + (res (hfyview-fontify-tree (car wt) whole-buffers)) + (title-bg-color (hfyview-wm-border-color)) + (title-color (or (hfy-triplet "SystemHilightText") + "white")) + (title-style (concat (format "background-color:%s; color:%s;" title-bg-color title-color) + "border: none; padding:4px; vertical-align: middle;")) + (outbuf (get-buffer-create "frame")) + html + css + ;; (face-attribute 'minibuffer-prompt :foreground) + (hfyview-prompt-face (plist-get minibuffer-prompt-properties 'face)) + minibuf + (frame-width (* 0.56 (frame-width))) + table-style + (icon-file (expand-file-name "../etc/images/icons/emacs_16.png" exec-directory)) + (img-tag (if (file-exists-p icon-file) + (concat ""))) + mini-css + mini-html + ) + (setq table-style + (format "border: solid %s; width:%sem;" + (hfyview-wm-border-color) + frame-width + )) + (setq minibuf (hfyview-frame-minibuff hfyview-frame-mode)) + (setq mini-css (nth 0 minibuf)) + (setq mini-html (nth 1 minibuf)) + (when (string= mini-html "") (setq mini-html " ")) + (setq res (hfyview-frame-to-html res)) + (setq html (nth 0 res)) + (setq css (nth 1 res)) + (with-current-buffer outbuf + ;;(lwarn t :warning "outbuf=%s" outbuf) + (erase-buffer) + (insert (format hfyview-xhtml-header + (concat "Emacs frame dump - " frame-title) + css) + (if mini-css mini-css "") + (format "\n" table-style) + "\n" + (format "\n" title-style img-tag + (hfyview-dekludge-string frame-title)) + "\n" + "\n" + html + "\n" + "\n" + "\n" + "\n" + "
%s  %s
\n" + mini-html + "
\n" + hfyview-xhtml-footer) + (browse-url-of-buffer) + outbuf))) + +(defun hfy-grab-echo-content () + "Return echo area content." + (setq hfy-grabbed-echo-content (current-message))) + +(defun hfy-grab-minibuffer-content () + "Return minibuffer content." + ;;(interactive) + (let* ((mw (minibuffer-window)) + (mb (window-buffer mw))) + (setq hfy-grabbed-minibuffer-content + (with-current-buffer mb + (buffer-substring + (point-min) (point-max))) + ))) + +;;(add-hook 'pre-command-hook 'grab-minibuffer-content nil t) +;;(remove-hook 'pre-command-hook 'grab-minibuffer-content) t) + +(provide 'hfyview) +;;; hfyview.el ends here diff --git a/emacs.d/nxhtml/util/hl-needed.el b/emacs.d/nxhtml/util/hl-needed.el new file mode 100644 index 0000000..7a160b6 --- /dev/null +++ b/emacs.d/nxhtml/util/hl-needed.el @@ -0,0 +1,402 @@ +;;; hl-needed.el --- Turn on highlighting of line and column when needed +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Fri Nov 30 21:19:18 2007 +;; Version: 0.60 +;; Last-Updated: 2010-03-19 Fri +;; URL: http://www.emacswiki.org/cgi-bin/wiki/hl-needed.el +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `hl-line', `vline'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This is yet another highlight line and/or column idea. The idea is +;; to try to show line and column only when it is probably most +;; needed. See `hl-needed-mode' for more info. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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: + +(require 'hl-line) +(require 'vline nil t) + +;;;###autoload +(defgroup hl-needed nil + "Customization group for `hl-needed-mode'." + :group 'convenience) + +(defcustom hl-needed-always nil + "Highlight always. +This is similar to turning on `vline-mode' and `hl-line-mode'" + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-mark-line t + "Highlight line." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-mark-column t + "Highlight column." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-in-readonly-buffers nil + "Do not highlight in read-only buffers unless non-nil." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-not-in-modes + '(wab-compilation-mode + custom-mode) + "List of modes where highlighting should not be done." + :type '(repeat function) + :group 'hl-needed) + +;;(setq hl-needed-idle-time 5) +(defcustom hl-needed-idle-time 20 + "Highligh current line and/or column if Emacs is idle for more seconds. +If nil do not turn on `hl-line-mode' when Emacs is idle." + :type '(choice (const :tag "Don't turn on when Emacs is idle" nil) + (integer :tag "Turn on after (seconds)")) + :group 'hl-needed) + +(defcustom hl-needed-on-mouse t + "Highlight current line and/or column on clicks." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-on-new-window t + "Highlight current line and/or column on new window selection." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-on-new-buffer t + "Highlight current line and/or column on new buffer selection." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-on-config-change t + "Highlight current line and/or column on window conf change." + :type 'boolean + :group 'hl-needed) + +(defcustom hl-needed-on-scrolling t + "Highlight current line and/or column after scrolling." + :type 'boolean + :group 'hl-needed) + +(defvar hl-needed-face 'hl-needed-face) +(defface hl-needed-face + '((t (:inherit highlight))) + "Face for flashing." + :group 'hl-needed) + +(defcustom hl-needed-flash-delay 0.0 + "Time to wait before turning on flash highlighting. +If a key is pressed before this flash highlighting is not done." + :type 'float + :group 'hl-needed) + +(defcustom hl-needed-flash-duration 1.0 + "Turn off flash highlighting after this number of second. +Highlighting is turned off only if it was turned on because of +some change. It will not be turned off if it was turned on +because Emacs was idle for more than `hl-needed-idle-time'. + +The default time is choosen to not disturb too much. I believe +human short attention may often be of this time. \(Compare eye +contact time.)" + :type 'float + :group 'hl-needed) + +(defcustom hl-needed-currently-fun 'hl-needed-currently + "Function that checks if highlighting should be done. +The function should return nil if not needed and non-nil +otherwise." + :type 'function + :group 'hl-needed) + +(defvar hl-needed-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c) ?? ??] 'hl-needed-show) + map)) + +;;;###autoload +(define-minor-mode hl-needed-mode + "Try to highlight current line and column when needed. +This is a global minor mode. It can operate in some different +ways: + +- Highlighting can be on always, see `hl-needed-always'. + +Or, it can be turned on depending on some conditions. In this +case highlighting is turned off after each command and turned on +again in the current window when either: + +- A new window was selected, see `hl-needed-on-new-window'. +- A new buffer was selected, see `hl-needed-on-new-buffer'. +- Window configuration was changed, see `hl-needed-on-config-change'. +- Buffer was scrolled see `hl-needed-on-scrolling'. +- A window was clicked with the mouse, see `hl-needed-on-mouse'. + +After this highlighting may be turned off again, normally after a +short delay, see `hl-needed-flash'. + +If either highlighting was not turned on or was turned off again +it will be turned on when + +- Emacs has been idle for `hl-needed-idle-time' seconds. + +See also `hl-needed-not-in-modes' and `hl-needed-currently-fun'. + +Note 1: For columns to be highlighted vline.el must be available. + +Note 2: This mode depends on `hl-line-mode' and `vline-mode' and +tries to cooperate with them. If you turn on either of these that +overrides the variables for turning on the respective +highlighting here." + :global t + :group 'hl-needed + ;;:keymap hl-needed-mode-map + (if hl-needed-mode + (progn + ;;(unless (memq major-mode hl-needed-not-in-modes) (setq hl-needed-window t)) + (when (featurep 'hl-needed) (hl-needed-show)) + (add-hook 'post-command-hook 'hl-needed-post-command) + (add-hook 'pre-command-hook 'hl-needed-pre-command) + (add-hook 'window-configuration-change-hook 'hl-needed-config-change) + ) + (remove-hook 'post-command-hook 'hl-needed-post-command) + (remove-hook 'pre-command-hook 'hl-needed-pre-command) + (remove-hook 'window-configuration-change-hook 'hl-needed-config-change) + (hl-needed-cancel-timer) + (hl-needed-cancel-flash-timer) + (hl-needed-hide))) + +(defvar hl-needed-timer nil) +(defvar hl-needed-flash-timer nil) +(defvar hl-needed-window nil) +(defvar hl-needed-buffer nil) +(defvar hl-needed-window-start nil) +(defvar hl-needed-flash-this nil) +(defvar hl-needed-config-change nil) + +(defvar hl-needed-old-blink nil) +(defun hl-needed-show () + "Highlight current line and/or column now." + (interactive) + (when (with-no-warnings (called-interactively-p)) + (setq hl-needed-flash-this nil) + (unless hl-needed-mode + (message "Use hl-needed-hide to remove highlighting"))) + (setq hl-needed-old-blink nil) ;; So blink is not turned on by hl-needed-hide + (hl-needed-hide) + (unless (active-minibuffer-window) + (setq hl-needed-old-blink blink-cursor-mode) + (when blink-cursor-mode + (blink-cursor-mode -1) + ;;(when (timerp blink-cursor-timer) (cancel-timer blink-cursor-timer)) + (blink-cursor-end) + ) + (unless hl-line-mode + (when hl-needed-mark-line + (let ((hl-line-mode t) + (hl-line-sticky-flag nil) + (hl-line-face hl-needed-face)) + (hl-line-highlight)))) + (unless vline-mode + (when hl-needed-mark-column + (when (featurep 'vline) + (let ((vline-style 'face) + (vline-face hl-line-face) + (vline-current-window-only t)) + (vline-show))))))) + +(defun hl-needed-hide () + (interactive) + (when (and hl-needed-old-blink + (not blink-cursor-mode)) + (blink-cursor-mode 1)) + (setq hl-needed-old-blink nil) + (unless hl-line-mode + (hl-line-unhighlight)) + (when (featurep 'vline) + (unless vline-mode + (vline-clear)))) + +(defun hl-needed-cancel-timer () + (when (timerp hl-needed-timer) (cancel-timer hl-needed-timer)) + (setq hl-needed-timer nil)) + +(defun hl-needed-start-timer (wait) + (hl-needed-cancel-timer) + (setq hl-needed-timer + (run-with-idle-timer wait + nil 'hl-needed-show-in-timer))) + +(defun hl-needed-show-in-timer () + "Turn on with special error handling. +Erros may go unnoticed in timers. This should prevent it." + (condition-case err + (save-match-data ;; runs in timer + (hl-needed-show)) + (error + (lwarn 'hl-needed-show + :error "%s" (error-message-string err))))) + +(defun hl-needed-hide-in-timer () + "Turn off with special error handling. +Erros may go unnoticed in timers. This should prevent it." + (condition-case err + (unless hl-needed-always + (hl-needed-hide)) + (error + (lwarn 'hl-needed-hide + :error "%s" (error-message-string err))))) + +(defun hl-needed-hide-flash-in-timer () + "Turn off with special error handling. +Erros may go unnoticed in timers. This should prevent it." + (condition-case err + (unless hl-needed-always + (hl-needed-hide) + (hl-needed-start-timer hl-needed-idle-time)) + (error + (lwarn 'hl-needed-hide + :error "%s" (error-message-string err))))) + +(defun hl-needed-currently () + "Check if `hl-line-mode' is needed in buffer." + ;; Check for change of buffer and window + (if hl-needed-always + t + (unless (or (memq major-mode hl-needed-not-in-modes) + isearch-mode + (and buffer-read-only + (not hl-needed-in-readonly-buffers))) + (or (and hl-needed-on-new-window + (not (eq hl-needed-window (selected-window)))) + ;;(progn (message "here1") nil) + (and hl-needed-on-new-buffer + (not (eq hl-needed-buffer (current-buffer)))) + ;;(progn (message "here2") nil) + (and hl-needed-on-config-change + hl-needed-config-change) + ;;(progn (message "here3") nil) + (and hl-needed-on-mouse + (listp last-input-event) + (memq (car last-input-event) '(mouse-1 mouse-2 mouse-3))) + ;;(progn (message "here4") nil) + (and hl-needed-on-scrolling + (and (not (eq hl-needed-window-start (window-start))) + (< 1 + (abs + (- (line-number-at-pos hl-needed-window-start) + (line-number-at-pos (window-start))))))))))) + +(defun hl-needed-cancel-flash-timer () + (when (timerp hl-needed-flash-timer) (cancel-timer hl-needed-flash-timer)) + (setq hl-needed-flash-timer nil)) + +(defun hl-needed-start-maybe-flash-timer () + (when (and hl-needed-flash-this + (not hl-needed-always)) + (hl-needed-cancel-flash-timer) + (setq hl-needed-flash-timer + (run-with-timer (+ hl-needed-flash-delay hl-needed-flash-duration) + nil 'hl-needed-hide-flash-in-timer)))) + +(defvar hl-needed-pre-command-time (current-time)) + +(defun hl-needed-check () + ;; Cancel `hl-line-mode' and timer + (unless (active-minibuffer-window) + (if (funcall hl-needed-currently-fun) + (progn + ;; Some time calc for things that pause to show us where we are: + (let* ((time-pre hl-needed-pre-command-time) + (time-now (current-time)) + (pre (+ (nth 1 time-pre) (* 0.0000001 (nth 2 time-pre)))) + (now (+ (nth 1 time-now) (* 0.0000001 (nth 2 time-now))))) + (if (< 1 (- now pre)) ;; Fix-me: option? + nil ;; Don't show anything here, it just disturbs + ;;(hl-needed-show) + (hl-needed-start-timer hl-needed-flash-delay) + (hl-needed-start-maybe-flash-timer)))) + ;; Submit an idle timer that can turn highlighting on. + (hl-needed-start-timer hl-needed-idle-time))) + (setq hl-needed-config-change nil) + (unless (active-minibuffer-window) + (setq hl-needed-window (selected-window)) + (setq hl-needed-buffer (current-buffer)) + (setq hl-needed-window-start (window-start)))) + +(defvar hl-needed-after-active-minibuffer nil) + +(defun hl-needed-pre-command () + ;;(message "active-minibuffer-window=%s" (active-minibuffer-window)) + (setq hl-needed-after-active-minibuffer (active-minibuffer-window)) + (condition-case err + (progn + (hl-needed-cancel-timer) + (hl-needed-cancel-flash-timer) + (hl-needed-hide) + (setq hl-needed-flash-this hl-needed-flash-duration) + (setq hl-needed-pre-command-time (current-time))) + (error + (message "hl-needed-pre-command error: %s" err)))) + +(defun hl-needed-post-command () + (condition-case err + (if (eq last-command 'keyboard-quit) + (hl-needed-hide) + (hl-needed-check)) + (error + (message "hl-needed-post-command error: %s" err)))) + +(defvar hl-needed-minibuffer-active nil) + +(defun hl-needed-config-change () + (condition-case err + (if (active-minibuffer-window) + (setq hl-needed-minibuffer-active t) + ;; Changing buffer in the echo area is a config change. Catch this: + (setq hl-needed-config-change (not hl-needed-after-active-minibuffer)) + (setq hl-needed-after-active-minibuffer nil) + (setq hl-needed-minibuffer-active nil)) + (error + (message "hl-needed-config-change error: %s" err)))) + +(provide 'hl-needed) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; hl-needed.el ends here diff --git a/emacs.d/nxhtml/util/html-write.el b/emacs.d/nxhtml/util/html-write.el new file mode 100644 index 0000000..c7a7c76 --- /dev/null +++ b/emacs.d/nxhtml/util/html-write.el @@ -0,0 +1,455 @@ +;;; html-write.el --- Hide some tags for writing text in XHTML +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-10-03T01:29:44+0200 Thu +(defconst html-write:version "0.6") ;; Version: +;; Last-Updated: 2009-08-11 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; The minor mode `html-write-mode' displays simple tags like , +;; , , or with appropriate faces (for example bold +;; and italic) instead of displaying the tags. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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: + +;; Silence byte compiler +(defvar jit-lock-start) +(defvar jit-lock-end) + +(eval-when-compile (require 'mumamo)) ;; Just for the defmacro ... +(eval-when-compile (require 'mlinks nil t)) + +;;;###autoload +(defgroup html-write nil + "Customization group for html-write." + :group 'nxhtml + :group 'convenience) + +(defface html-write-base + '((t (:inherit font-lock-type-face))) + "Face from which other faces inherits." + :group 'html-write) + +(defface html-write-em + '((t (:inherit html-write-base :slant italic))) + "Face used for tags." + :group 'html-write) + +(defface html-write-strong + '((t (:inherit html-write-base :weight bold))) + "Face used for tags." + :group 'html-write) + +(defface html-write-link + '((t (:inherit html-write-base :underline t))) + "Face used for tags." + :group 'html-write) + +(defconst html-write-tag-list + '(("i" html-write-em-tag-actions) + ("b" html-write-strong-tag-actions) + ("em" html-write-em-tag-actions) + ("strong" html-write-strong-tag-actions) + ("a" html-write-a-tag-actions) + ;;("img" html-write-img-tag-actions t) + ) + "List of tags that should be hidden. +A record in the list has the format + + \(TAG HANDLE [SINGLE]) + +where +- TAG is the tag name string. + +- HANDLE is a function to call when hiding the tag. It takes + three parameters, TAG-BEGIN, TAG-END and OVERLAY. TAG-BEGIN + and TAG-END are start and end of the start tag. OVERLAY is an + overlay used for faces, keymaps etc that covers the whole tag." + ) + +(defun html-write-em-tag-actions (tag-begin tag-end overlay) + "Do actions for tags for tag between TAG-BEGIN and TAG-END. +OVERLAY is the overlay added by `html-write-mode' for this tag." + (overlay-put overlay 'face 'html-write-em)) + +(defun html-write-strong-tag-actions (tag-begin tag-end overlay) + "Do actions for tags for tag between TAG-BEGIN and TAG-END. +OVERLAY is the overlay added by `html-write-mode' for this tag." + (overlay-put overlay 'face 'html-write-strong)) + +;; Fix-me +(defun html-write-img-tag-actions (tag-begin tag-end overlay) + "Do actions for tags for tag between TAG-BEGIN and TAG-END. +OVERLAY is the overlay added by `html-write-mode' for this tag." + (save-match-data + (let ((here (point-marker)) + href) + (save-restriction + (narrow-to-region tag-begin tag-end) + (goto-char tag-begin) + (when (looking-at (rx (*? anything) + (1+ space) + "src=\"" + (submatch + (+ (not (any "\"\n")))) + "\"")) + (setq href (match-string-no-properties 1)))) + (when href + (overlay-put overlay 'display (concat "image " href)) + (overlay-put overlay 'html-write-url href)) + (goto-char (point))))) + +(defun html-write-point-entered-echo (left entered) + (let ((msg (get-char-property entered 'help-echo))) + (when msg (message "%s" msg)))) + +(defun html-write-a-tag-actions (tag-begin tag-end overlay) + "Do actions for tags for tag between TAG-BEGIN and TAG-END. +OVERLAY is the overlay added by `html-write-mode' for this tag." + (save-match-data + (let ((here (point-marker)) + href) + (save-restriction + (narrow-to-region tag-begin tag-end) + (goto-char tag-begin) + (when (looking-at (rx (*? anything) + (1+ space) + "href=\"" + (submatch + (+ (not (any "\"\n")))) + "\"")) + (setq href (match-string-no-properties 1)))) + (when href + (overlay-put overlay 'face 'html-write-link) + (overlay-put overlay 'help-echo href) + ;; Fix-me: Seems like point-entered must be a text prop + (overlay-put overlay 'point-entered 'html-write-point-entered-echo) + (overlay-put overlay 'mouse-face 'highlight) + (if (eq ?# (string-to-char href)) + (setq href (concat "file:///" buffer-file-name href)) + (when (file-exists-p href) + (setq href (expand-file-name href)))) + (overlay-put overlay 'html-write-url href)) + (goto-char (point))))) + +(defun html-write-get-tag-ovl () + "Get tag overlay at current point." + (catch 'ranges + (dolist (ovl (overlays-at (point))) + (let ((ranges (overlay-get ovl 'html-write))) + (when ranges + (throw 'ranges ovl)))))) + +(defun html-write-toggle-current-tag () + "Toggle display of tag at current point." + (interactive) + (let* ((ovl (html-write-get-tag-ovl)) + (hiding-ranges (overlay-get ovl 'html-write)) + (invis (get-text-property (caar hiding-ranges) 'invisible)) + (ovl-start (overlay-start ovl)) + (ovl-end (overlay-end ovl))) + (if invis + (progn + (overlay-put ovl 'html-face (overlay-get ovl 'face)) + (overlay-put ovl 'face 'highlight) + (dolist (range hiding-ranges) + (let ((start (car range)) + (end (cdr range))) + (mumamo-with-buffer-prepared-for-jit-lock + (put-text-property start end 'invisible nil))))) + (delete-overlay ovl) + (html-write-hide-tags ovl-start ovl-end)))) + +(defun html-write-browse-link () + "Browse link in current tag." + (interactive) + (let* ((ovl (html-write-get-tag-ovl)) + (url (overlay-get ovl 'html-write-url))) + (unless url + (error "No link in this tag")) + (browse-url url) + )) + +(defvar html-write-keymap + (let ((map (make-sparse-keymap)) + keys) + (define-key map [(control ?c) ?+] 'html-write-toggle-current-tag) + (define-key map [(control ?c) ?!] 'html-write-browse-link) + (define-key map [mouse-1] 'html-write-browse-link) + (when (featurep 'mlinks) + (setq keys (where-is-internal 'mlinks-goto mlinks-mode-map)) + (dolist (key keys) + (define-key map key 'html-write-mlinks-goto)) + (setq keys (where-is-internal 'mlinks-goto-other-window mlinks-mode-map)) + (dolist (key keys) + (define-key map key 'html-write-mlinks-goto-other-window)) + (setq keys (where-is-internal 'mlinks-goto-other-frame mlinks-mode-map)) + (dolist (key keys) + (define-key map key 'html-write-mlinks-goto-other-frame)) + ) + map)) + +(defun html-write-mlinks-goto () + "Goto link." + (interactive) + (html-write-mlinks-goto-1 'mlinks-goto)) + +(defun html-write-mlinks-goto-other-window () + "Goto link in other window." + (interactive) + (html-write-mlinks-goto-1 'mlinks-goto-other-window)) + +(defun html-write-mlinks-goto-other-frame () + "Goto link in other frame." + (interactive) + (html-write-mlinks-goto-1 'mlinks-goto-other-frame)) + +(defun html-write-mlinks-goto-1 (goto-fun) + (let* ((ovl (html-write-get-tag-ovl)) + (ovl-start (overlay-start ovl)) + (ovl-end (overlay-end ovl)) + (here (point-marker))) + (goto-char ovl-start) + (skip-chars-forward "^\"" ovl-end) + (forward-char) + (unless (funcall goto-fun) (goto-char here)) + )) + +;;(html-write-make-hide-tags-regexp) +(defun html-write-make-hide-tags-regexp () + "Make regexp used for finding tags to hide." + ;; fix-me: single tags. Fix-me: what did I mean??? Maybe < etc... + (let ((tags-re + (mapconcat 'identity + (mapcar (lambda (elt) + (if (stringp elt) + elt + (car elt))) + html-write-tag-list) + "\\|"))) + (concat + "<\\(?1:" + "\\(?:" tags-re "\\)" + "\\)[^>]*>\\(?3:[^<]*\\)\\(?2:\\)" + ))) + +(defvar html-write-pending-changes nil) +(make-variable-buffer-local 'html-write-pending-changes) +(put 'html-write-pending-changes 'permanent-local t) + + +(defun html-write-hide-tags (start end) + "Hide tags matching `html-write-tag-list' between START and END." + ;;(message "html-write-hide-tags %s %s" start end) + (let ((here (point-marker)) + (buffer-name (buffer-file-name)) + (dbg nil)) + (save-restriction + (widen) + (goto-char start) + (save-match-data + (let ((hide-tags-regexp (html-write-make-hide-tags-regexp))) + (when dbg (message "before search start=%s end=%s, point=%s" start end (point))) + (while (re-search-forward hide-tags-regexp end t) + (let* ((ovl (make-overlay (match-beginning 0) (match-end 0) + nil t nil)) + (tag-fun (cadr (assoc (match-string-no-properties 1) + html-write-tag-list))) + hiding-ranges) + ;;(overlay-put ovl 'face 'font-lock-variable-name-face) + (overlay-put ovl 'keymap html-write-keymap) + (setq hiding-ranges + (list (cons (1- (match-beginning 1)) (match-beginning 3)) + (cons (match-beginning 2) (match-end 2)))) + (overlay-put ovl 'html-write hiding-ranges) + (mumamo-with-buffer-prepared-for-jit-lock + (dolist (range hiding-ranges) + (let ((start (car range)) + (end (cdr range))) + (put-text-property start end 'invisible 'html-write) + ;; Fix-me: more careful rear-nonsticky? + (put-text-property (1- end) end + 'rear-nonsticky '(invisible))))) + ;; Let tag-fun override + (when tag-fun + (funcall tag-fun (match-end 1) (match-beginning 3) ovl)) + ))))) + (goto-char here))) + +(defun html-write-reveal-tags (start end) + "Reveal tags between START and END." + (let ((here (point-marker))) + (save-restriction + (widen) + (goto-char (point-min)) + (save-match-data + (mumamo-with-buffer-prepared-for-jit-lock + (remove-text-properties start + end + '(invisible html-write)) + (dolist (ovl (overlays-in start end)) + (when (overlay-get ovl 'html-write) + (let ((end (overlay-end ovl))) + (remove-list-of-text-properties (1- end) end '(rear-nonsticky)) + (delete-overlay ovl))))))) + (goto-char here))) + +;;;###autoload +(define-minor-mode html-write-mode + "Minor mode for convenient display of some HTML tags. +When this mode is on a tag in `html-write-tag-list' is displayed as +the inner text of the tag with a face corresponding to the tag. +By default for example ... is displayed as italic and +... is displayed as an underlined clickable link. + +Only non-nested tags are hidden. The idea is just that it should +be easier to read and write, not that it should look as html +rendered text. + +See the customization group `html-write' for more information about +faces. + +The following keys are defined when you are on a tag handled by +this minor mode: + +\\{html-write-keymap} + +IMPORTANT: Most commands you use works also on the text that is +hidden. The movement commands is an exception, but as soon as +you edit the buffer you may also change the hidden parts. + +Hint: Together with `wrap-to-fill-column-mode' this can make it +easier to see what text you are actually writing in html parts of +a web file." + :group 'html-write + (if t + (if html-write-mode + (html-write-font-lock t) + (html-write-font-lock nil) + (save-restriction + (widen) + (html-write-reveal-tags (point-min) (point-max)))))) +(put html-write-mode 'permanent-local t) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Font lock + +(defun html-write-jit-extend-after-change (start end old-len) + "For JIT lock extending. +Should be on `jit-lock-after-change-extend-region-functions'. + +START, END and OLD-LEN are the parameters from after change." + (let ((our-ovls nil)) + (dolist (ovl (append (overlays-in start end) + (overlays-at start) + nil)) + ;; Leave the overlays until re-fontification time, but note their extent. + (when (overlay-get ovl 'html-write) + (setq jit-lock-start (min jit-lock-start (overlay-start ovl))) + (setq jit-lock-end (max jit-lock-end (overlay-end ovl))))))) + + +(defun html-write-fontify (bound) + ;;(message "html-write-fontify %s" bound) + (let (tag-ovl) + ;;(save-match-data + (let* ((hide-tags-regexp (html-write-make-hide-tags-regexp)) + (next-tag (re-search-forward hide-tags-regexp bound t)) + (tag-beg (when next-tag (match-beginning 0))) + (tag-end (when next-tag (match-end 0))) + (tag-nam (when next-tag (match-string-no-properties 1))) + (tag-fun (when next-tag (cadr (assoc tag-nam html-write-tag-list)))) + tag-hid + (old-start (next-single-char-property-change (max (point-min) (1- (point))) 'html-write nil bound))) + ;;(message "here a old-start=%s, tag-beg/end=%s/%s" old-start tag-beg tag-end) + (setq tag-ovl (when next-tag (make-overlay tag-beg tag-end))) + (when old-start + ;; Fix-me: maybe valid, perhaps better keep it then? + (let ((ovl (catch 'ovl + (dolist (o (append (overlays-at old-start) + (overlays-in old-start (1+ old-start)) + nil)) + (when (overlay-get o 'html-write) + (throw 'ovl o)))))) + (when ovl ;; fix-me: there should be one... + ;;(message "here b") + (mumamo-with-buffer-prepared-for-jit-lock + (remove-list-of-text-properties (overlay-start ovl) (overlay-end ovl) '(invisible html-write))) + (delete-overlay ovl)))) + ;;(html-write-hide-tags start end) + ;;(message "here d, tag-ovl=%s" tag-ovl) + (when tag-ovl + (overlay-put tag-ovl 'face 'font-lock-variable-name-face) + (overlay-put tag-ovl 'keymap html-write-keymap) + (setq tag-hid + (list (cons (1- (match-beginning 1)) (match-beginning 3)) + (cons (match-beginning 2) (match-end 2)))) + (overlay-put tag-ovl 'html-write tag-hid) + (when tag-fun + (funcall tag-fun (match-end 1) (match-beginning 3) tag-ovl)) + (mumamo-with-buffer-prepared-for-jit-lock + (dolist (range tag-hid) + (let ((start (car range)) + (end (cdr range))) + (put-text-property start end 'invisible 'html-write) + ;;(put-text-property start end 'html-write t) + ;; Fix-me: more careful rear-nonsticky? + (put-text-property (1- end) end + 'rear-nonsticky '(invisible))))))) + ;;) + (when tag-ovl + (set-match-data (list (copy-marker (overlay-start tag-ovl)) + (copy-marker (overlay-end tag-ovl)))) + (goto-char (1+ (overlay-end tag-ovl))) + t))) + +(defun html-write-font-lock (on) + ;; See mlinks.el + (let* ((add-or-remove (if on 'font-lock-add-keywords 'font-lock-remove-keywords)) + (fontify-fun 'html-write-fontify) + (args (list nil `(( ,fontify-fun ( 0 'html-write-base t )))))) + (when fontify-fun + (when on (setq args (append args (list t)))) + (apply add-or-remove args) + (font-lock-mode -1) + (font-lock-mode 1) + ))) + +(provide 'html-write) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; html-write.el ends here diff --git a/emacs.d/nxhtml/util/idn.el b/emacs.d/nxhtml/util/idn.el new file mode 100644 index 0000000..21f7a4c --- /dev/null +++ b/emacs.d/nxhtml/util/idn.el @@ -0,0 +1,151 @@ +;;; idn.el --- Recommended Identifier Profiles for IDN +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2010-03-24 Wed +;; Version: 0.1 +;; Last-Updated: 2010-03-26 Fri +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; + ;; `nxhtml-base'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Functions for handling IDN chars defined by +;; `http://www.unicode.org/reports/tr39/'. +;; +;; See `idn-is-recommended'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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 3, 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: + +;; Fix-me: You have to change this if you are not using nXhtml: +(require 'nxhtml-base) +(defvar uts39-datadir (expand-file-name "etc/uts39/" nxhtml-install-dir)) + +(defun idn-init (bv) + (save-match-data + (let* ((idnchars-file (expand-file-name "idnchars.txt" uts39-datadir)) + (idnchars-old (find-buffer-visiting idnchars-file)) + (idnchars-buf (or idnchars-old + (if (not (file-exists-p idnchars-file)) + (message "Can't find file %S" idnchars-file) + (find-file-noselect idnchars-file)))) + here + (range-patt (rx bol + (group (repeat 4 (any xdigit))) + (optional ".." + (group (repeat 4 (any xdigit)))))) + (num-idn 0)) + (when idnchars-buf + (with-current-buffer idnchars-buf + (setq here (point)) + (save-restriction + (widen) + (goto-char (point-min)) + (while (re-search-forward range-patt nil t) + (let* ((str-beg (match-string 0)) + (str-end (match-string 2)) + (beg (string-to-number str-beg 16)) + (end (or (when str-end (string-to-number str-end 16)) + beg))) + ;;(message "str-beg=%S str-end=%S" str-beg str-end) + (dotimes (ii (1+ (- end beg))) + (let ((num (+ ii beg))) + ;;(message "setting idn-char %s #%4x" num num) + (setq num-idn (1+ num-idn)) + (aset bv num t)))))) + (goto-char here)) + (unless idnchars-old (kill-buffer idnchars-buf)) + (message "Found %d IDN chars" num-idn) + t)))) + +(defconst idn-char-vector + (let ((bv (make-bool-vector (* 256 256) nil))) + (when (idn-init bv) + ;; (string-to-number "002D" 16) + ;; Make a quick sanity check: + (unless (and (not (aref bv 44)) + (aref bv 45)) + (message "idn-char-vector: Bad idn data in file idnchars.txt")) + bv)) + "Boolean vector with recommended IDN chars.") + + +;;(idn-is-recommended 0) +;;(idn-is-recommended 65535) +(defsubst idn-is-recommended (char) + "Return t if character CHAR is a recommended IDN char. +See URL `http://www.unicode.org/reports/tr39/'. + +Data is initialized from the file idnchars.txt in the directory +`uts39-datadir'. This file is fetched from the above URL." + (aref idn-char-vector char)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Below are some help functions that can be commented out. + +;;(global-set-key [f9] 'idn-char-at-point) +(defun idn-char-at-point (pos) + "Tell if char at POS is an recommended IDN char. +Default POS is current point." + (interactive "d") + (let* ((this-char (char-after pos)) + (recommended (idn-is-recommended this-char))) + (message "IDN char at point: %s (#%000x)" recommended this-char))) + +(defun idn-list-chars () + "Show all IDN chars. +For more info see `idn-is-recommended'. + +Note: This may crash Emacs currently, at least on w32." + (interactive) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'idn-list-chars) (interactive-p)) + (with-current-buffer (help-buffer) + (insert + "Recommended Identifier Characters for IDN:\n\n") + (let ((col 0) + (cnt 0)) + (dotimes (nn (length idn-char-vector)) + (when (aref idn-char-vector nn) + (setq cnt (1+ cnt)) + (setq col (mod (1+ col) 20)) + (when (= col 0) (insert "\n ")) + (insert " " (char-to-string nn)))) + (insert "\n\n" + (format "There were %d IDN chars defined in `idn-char-vector'." cnt)) + )))) + +(provide 'idn) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; idn.el ends here diff --git a/emacs.d/nxhtml/util/inlimg.el b/emacs.d/nxhtml/util/inlimg.el new file mode 100644 index 0000000..9b07fb3 --- /dev/null +++ b/emacs.d/nxhtml/util/inlimg.el @@ -0,0 +1,429 @@ +;;; inlimg.el --- Display images inline +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-09-27 +(defconst inlimg:version "0.7") ;; Version: +;; Last-Updated: 2009-07-14 Tue +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Display images inline. See `inlimg-mode' for more information. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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 'cl)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'ourcomments-util nil t)) + +(defvar inlimg-assoc-ext + '((png (".png")) + (gif (".gif")) + (tiff (".tiff")) + (jpeg (".jpg" ".jpeg")) + (xpm (".xpm")) + (xbm (".xbm")) + (pbm (".pbm")))) + +(defvar inlimg-img-regexp nil) +(make-variable-buffer-local 'inlimg-img-regexp) +(put 'inlimg-img-regexp 'permanent-local t) + +(defvar inlimg-img-regexp-html + (rx (or (and ""))) + (1+ space)) + "src=\"" + (group (1+ (not (any "\"")))) + "\"" + (*? anything) + "/>") + (and "url(" + ?\" + (group (1+ (not (any "\)")))) + ?\" + ")" + ) + (and "url(" + (group (+? (not (any ")")))) + ")" + ) + ))) + +(defvar inlimg-img-regexp-org + (rx-to-string + `(and "[[file:" + (group (+? (not (any "\]"))) + ,(let ((types nil)) + (dolist (typ image-types) + (when (image-type-available-p typ) + (dolist (ext (cadr (assoc typ inlimg-assoc-ext))) + (setq types (cons ext types))))) + (cons 'or types))) + "]" + (optional "[" + (+? (not (any "\]"))) + "]") + "]" + ))) + +(defconst inlimg-modes-img-values + '( + (html-mode inlimg-img-regexp-html) + (org-mode inlimg-img-regexp-org) + )) + +(defun inlimg-img-spec-p (spec) + (assoc spec inlimg-modes-img-values)) + +;;;###autoload +(defgroup inlimg nil + "Customization group for inlimg." + :group 'nxhtml) + +(defcustom inlimg-margins '(50 . 5) + "Margins when displaying image." + :type '(cons (integer :tag "Left margin") + (integer :tag "Top margin")) + :set (lambda (sym val) + (set-default sym val) + (when (fboundp 'inlimg-update-all-buffers) + (inlimg-update-all-buffers))) + :group 'inlimg) + +(defcustom inlimg-slice '(0 0 400 100) + "How to slice images." + :type '(choice (const :tag "Show whole images" nil) + (list :tag "Show slice of image" + (integer :tag "Top") + (integer :tag "Left") + (integer :tag "Width") + (integer :tag "Height"))) + :set (lambda (sym val) + (set-default sym val) + (when (fboundp 'inlimg-update-all-buffers) + (inlimg-update-all-buffers))) + :group 'inlimg) + +(define-widget 'inlimg-spec-widget 'symbol + "An inline image specification." + :complete-function (lambda () + (interactive) + (lisp-complete-symbol 'inlimg-img-spec-p)) + :prompt-match 'inlimg-img-spec-p + :prompt-history 'widget-function-prompt-value-history + :match-alternatives '(inlimg-img-spec-p) + :validate (lambda (widget) + (unless (inlimg-img-spec-p (widget-value widget)) + (widget-put widget :error (format "Invalid function: %S" + (widget-value widget))) + widget)) + :value 'org-mode + :tag "Inlimg image values spec name") + +;; (customize-option 'inlimg-mode-specs) +(defcustom inlimg-mode-specs + '( + (xml-mode html-mode) + (sgml-mode html-mode) + (nxml-mode html-mode) + (php-mode html-mode) + (css-mode html-mode) + ) + "Equivalent mode for image tag search. +Note that derived modes \(see info) are recognized by default. + +To add new image tag patterns modify `inlimg-modes-img-values'." + :type '(repeat + (list (major-mode-function :tag "Major mode") + (inlimg-spec-widget :tag "Use tags as specified in"))) + :group 'inlimg) + +(defface inlimg-img-tag '((t :inherit 'lazy-highlight)) + "Face added to img tag when displaying image." + :group 'inlimg) + +(defface inlimg-img-remote '((t :inherit 'isearch-fail)) + "Face used for notes telling image is remote." + :group 'inlimg) + +(defface inlimg-img-missing '((t :inherit 'trailing-whitespace)) + "Face used for notes telling image is missing." + :group 'inlimg) + +(defvar inlimg-img-keymap + (let ((map (make-sparse-keymap))) + (define-key map [(control ?c) ?+] 'inlimg-toggle-display) + (define-key map [(control ?c) ?%] 'inlimg-toggle-slicing) + map) + "Keymap on image overlay.") + +(eval-after-load 'gimp + '(gimp-add-point-bindings inlimg-img-keymap)) + +(defsubst inlimg-ovl-p (ovl) + "Return non-nil if OVL is an inlimg image overlay." + (overlay-get ovl 'inlimg-img)) + +(defun inlimg-ovl-valid-p (ovl) + (and (overlay-get ovl 'inlimg-img) + inlimg-img-regexp + (save-match-data + (let ((here (point))) + (goto-char (overlay-start ovl)) + (prog1 + (looking-at (symbol-value inlimg-img-regexp)) + (goto-char here)))))) + +(defun inlimg-next (pt display-image) + "Display or hide next image after point PT. +If DISPLAY-IMAGE is non-nil then display image, otherwise hide it. + +Return non-nil if an img tag was found." + (when inlimg-img-regexp + (let (src dir beg end img ovl remote beg-face) + (goto-char pt) + (save-match-data + (when (re-search-forward (symbol-value inlimg-img-regexp) nil t) + (setq src (or (match-string-no-properties 1) + (match-string-no-properties 2) + (match-string-no-properties 3))) + (setq beg (match-beginning 0)) + (setq beg-face (get-text-property beg 'face)) + (setq remote (string-match "^https?://" src)) + (setq end (- (line-end-position) 0)) + (setq ovl (catch 'old-ovl + (dolist (ovl (overlays-at beg)) + (when (inlimg-ovl-p ovl) + (throw 'old-ovl ovl))) + nil)) + (unless ovl + (setq ovl (make-overlay beg end)) + (overlay-put ovl 'inlimg-img t) + (overlay-put ovl 'priority 100) + (overlay-put ovl 'face 'inlimg-img-tag) + (overlay-put ovl 'keymap inlimg-img-keymap)) + (overlay-put ovl 'image-file src) + (overlay-put ovl 'inlimg-slice inlimg-slice) + (if display-image + (unless (memq beg-face '(font-lock-comment-face font-lock-string-face)) + (unless remote + (setq dir (if (buffer-file-name) + (file-name-directory (buffer-file-name)) + default-directory)) + (setq src (expand-file-name src dir))) + (if (or remote (not (file-exists-p src))) + (setq img (propertize + (if remote " Image is on the web " " Image not found ") + 'face (if remote 'inlimg-img-remote 'inlimg-img-missing))) + (setq img (create-image src nil nil + :relief 5 + :margin inlimg-margins)) + (setq img (inlimg-slice-img img inlimg-slice))) + (let ((str (copy-sequence "\nX"))) + (setq str (propertize str 'face 'inlimg-img-tag)) + (put-text-property 1 2 'display img str) + (overlay-put ovl 'after-string str))) + (overlay-put ovl 'after-string nil)))) + ovl))) + +(defun inlimg-slice-img (img slice) + (if (not slice) + img + (let* ((sizes (image-size img t)) + (width (car sizes)) + (height (cdr sizes)) + (sl-left (nth 0 slice)) + (sl-top (nth 1 slice)) + (sl-width (nth 2 slice)) + (sl-height (nth 3 slice))) + (when (> sl-left width) (setq sl-left 0)) + (when (> (+ sl-left sl-width) width) (setq sl-width (- width sl-left))) + (when (> sl-top height) (setq sl-top 0)) + (when (> (+ sl-top sl-height) height) (setq sl-height (- height sl-top))) + (setq img (list img)) + (setq img (cons (append '(slice) + slice + (list sl-top sl-left sl-width sl-height) + nil) + img))))) + +;;;###autoload +(define-minor-mode inlimg-mode + "Display images inline. +Search buffer for image tags. Display found images. + +Image tags are setup per major mode in `inlimg-mode-specs'. + +Images are displayed on a line below the tag referencing them. +The whole image or a slice of it may be displayed, see +`inlimg-slice'. Margins relative text are specified in +`inlimg-margins'. + +See also the commands `inlimg-toggle-display' and +`inlimg-toggle-slicing'. + +Note: This minor mode uses `font-lock-mode'." + :keymap nil + :group 'inlimg + (if inlimg-mode + (progn + (let ((major-mode (or (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode + (fboundp 'mumamo-main-major-mode) + (mumamo-main-major-mode)) + major-mode))) + (inlimg-get-buffer-img-values) + (unless inlimg-img-regexp + (message "inlim-mode: No image spec, can't do anything")) + (add-hook 'font-lock-mode-hook 'inlimg-on-font-lock-off)) + (inlimg-font-lock t)) + (inlimg-font-lock nil) + (inlimg-delete-overlays))) +(put 'inlimg-mode 'permanent-local t) + +(defun inlimg-delete-overlays () + (save-restriction + (widen) + (let (ovl) + (dolist (ovl (overlays-in (point-min) (point-max))) + (when (inlimg-ovl-p ovl) + (delete-overlay ovl)))))) + +(defun inlimg-get-buffer-img-values () + (let* (rec + (spec (or (catch 'spec + (dolist (rec inlimg-mode-specs) + (when (derived-mode-p (car rec)) + (throw 'spec (nth 1 rec))))) + major-mode)) + (values (when spec (nth 1 (assoc spec inlimg-modes-img-values)))) + ) + (setq inlimg-img-regexp values) + )) + +(defun inlimg--global-turn-on () + (inlimg-get-buffer-img-values) + (when inlimg-img-regexp + (inlimg-mode 1))) + +;;;###autoload +(define-globalized-minor-mode inlimg-global-mode inlimg-mode inlimg--global-turn-on) + +;;;###autoload +(defun inlimg-toggle-display (point) + "Toggle display of image at point POINT. +See also the command `inlimg-mode'." + (interactive (list (point))) + (let ((here (point)) + (ovl + (catch 'ovl + (dolist (ovl (overlays-at (point))) + (when (inlimg-ovl-p ovl) + (throw 'ovl ovl))))) + is-displayed) + (if (not ovl) + (message "No image at point %s" here) + (setq is-displayed (overlay-get ovl 'after-string)) + (inlimg-next (overlay-start ovl) (not is-displayed)) + (goto-char here)))) + +;;;###autoload +(defun inlimg-toggle-slicing (point) + "Toggle slicing of image at point POINT. +See also the command `inlimg-mode'." + (interactive (list (point))) + (let* ((here (point)) + (ovl + (catch 'ovl + (dolist (ovl (overlays-at (point))) + (when (inlimg-ovl-p ovl) + (throw 'ovl ovl))))) + (inlimg-slice inlimg-slice) + is-displayed) + (if (not ovl) + (message "No image at point %s" here) + (setq is-displayed (overlay-get ovl 'after-string)) + (when (overlay-get ovl 'inlimg-slice) + (setq inlimg-slice nil)) + (inlimg-next (overlay-start ovl) is-displayed) + (goto-char here)))) + + +(defun inlimg-font-lock-fun (bound) + (let ((here (point)) + old-ovls new-ovls ovl) + (goto-char (line-beginning-position)) + (dolist (ovl (overlays-in (point) bound)) + (when (inlimg-ovl-p ovl) + (setq old-ovls (cons ovl old-ovls)))) + (while (and (< (point) bound) + (setq ovl (inlimg-next (point) t))) + (setq new-ovls (cons ovl new-ovls))) + (dolist (ovl old-ovls) + (unless (inlimg-ovl-valid-p ovl) + (delete-overlay ovl) + )))) + +;; Fix-me: This stops working for changes with nxhtml-mumamo-mode, but +;; works for nxhtml-mode and html-mumamo-mode... +(defvar inlimg-this-is-not-font-lock-off nil) +(defun inlimg-font-lock (on) + (let ((add-or-remove (if on 'font-lock-add-keywords 'font-lock-remove-keywords)) + (link-fun)) + (funcall add-or-remove nil + `((inlimg-font-lock-fun + 1 + mlinks-link + prepend))) + (let ((inlimg-this-is-not-font-lock-off t) + (mumamo-multi-major-mode nil)) + (font-lock-mode -1) + (font-lock-mode 1)))) + +(defun inlimg-on-font-lock-off () + (unless (or inlimg-this-is-not-font-lock-off + (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode)) + (when inlimg-mode + (inlimg-mode -1) + ))) +(put 'inlimg-on-font-lock-off 'permanent-local-hook t) + + +(provide 'inlimg) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; inlimg.el ends here diff --git a/emacs.d/nxhtml/util/key-cat.el b/emacs.d/nxhtml/util/key-cat.el new file mode 100644 index 0000000..ac4938c --- /dev/null +++ b/emacs.d/nxhtml/util/key-cat.el @@ -0,0 +1,329 @@ +;;; key-cat.el --- List key bindings by category +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: Sat Jan 28 2006 +;; Version: 0.25 +;; Last-Updated: 2009-05-09 Sat +;; Keywords: +;; Compatibility: +;; +;; Requires Emacs 22. +;; +;; Features that might be required by this library: +;; + ;; `cl'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Display help that looks like a reference sheet for common +;; commands. +;; +;; To use this in your .emacs put +;; +;; (require 'key-cat) +;; +;; Then use the command +;; +;; M-x key-cat-help +;; +;; For more information see that command. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) + +(defconst key-cat-cmd-list + '( + (error-testing + (commands + :visible nil + hallo + key-cat-help + key-cat-where-is + )) + ("Help" + (commands + help-for-help + info-emacs-manual + info + )) + ("Special Functions and Keys" + ;; For similar functions that are most often bound to a specific key + (commands + key-cat-tab + key-cat-complete + ) + ) + ("Files, Buffers and Windows" + (commands + find-file + save-buffer + write-file + split-window-vertically + split-window-horizontally + delete-other-windows + other-window + buffer-menu + )) + ("Search and replace" + (commands + isearch-forward + isearch-backward + query-replace + isearch-forward-regexp + isearch-backward-regexp + query-replace-regexp + occur + lgrep + rgrep + )) + ("Lines" + (commands + move-beginning-of-line + move-end-of-line + kill-line + )) + ("Words" + (commands + forward-word + backward-word + kill-word + )) + ("Region" + (commands + set-mark-command + ;;cua-set-mark + kill-region + copy-region-as-kill + yank + yank-pop + )) + ("Undo" + (commands + undo + )) + ("Viper" + (commands + :visible (lambda() + (and (featurep 'viper) + viper-mode)) + viper-next-line + viper-previous-line + viper-forward-word + viper-backward-word + viper-forward-Word + viper-backward-Word + viper-repeat + viper-forward-char + viper-backward-char + viper-next-line-at-bol + viper-previous-line-at-bol + viper-command-argument + viper-digit-argument + )) + ) + "List with common commands to display by `key-cat-help'. +The elements of this list corresponds to sections to show in the +help. Each element consists of sublists beginning with the +keyword 'commands. The sublists may after 'command contain the +keyword :visible which takes a variable or function as argument. +If the argument evaluates to non-nil the list is shown." + ) + + +(defvar key-cat-cmd-list-1 nil) + +(defun key-cat-help() + "Display reference sheet style help for common commands. +See also `key-cat-cmd-list'." + (interactive) + (if (> 22 emacs-major-version) + (message "Sorry, this requires Emacs 22 or later") + ;; Delay to get correct bindings when running through M-x + (setq key-cat-cmd-list-1 key-cat-cmd-list) + (run-with-timer 0.1 nil 'key-cat-help-internal))) + +(defun key-cat-help-internal() ;(category) + (message "Please wait ...") + (condition-case err + (save-match-data ;; runs in timer + (let ((result)) + (help-setup-xref (list #'key-cat-help) + (interactive-p)) + ;; (push (list "Changing commands" + ;; (list + ;; 'command + ;; indent-line-function + ;; )) + ;; key-cat-cmd-list-1) + (dolist (catentry key-cat-cmd-list-1) + (let ((category (car catentry)) + (commands (cdr catentry)) + (cmds) + (keyw) + (visible) + (visible-fun) + (cmdstr) + (doc)) + (dolist (cmdlist commands) + (setq cmdlist (cdr cmdlist)) + (setq visible t) + (while (keywordp (setq keyw (car cmdlist))) + (setq cmdlist (cdr cmdlist)) + (case keyw + (:visible (setq visible-fun (pop cmdlist)) + (setq visible (if (symbolp visible-fun) + (progn + (symbol-value visible-fun)) + (funcall visible-fun))) + ) + )) + (when visible + (dolist (cmd cmdlist) + (setq cmds (cons cmd cmds))))) + (when cmds + (push (format "\n%s:\n" + (let ((s (format "%s" category))) + (put-text-property 0 (length s) + 'face (list + 'bold + ) + s) + s)) + result)) + (setq cmds (reverse cmds)) + (dolist (cmd cmds) + (setq cmdstr + (let ((s "Where to find it:" )) + (put-text-property 0 (length s) + 'face '(:slant italic + :background "RGB:dd/dd/ff" + ) s) s)) + (if (not (functionp cmd)) + (cond + ((eq 'key-cat-tab cmd) + (let ((s "Indent line")) + (put-text-property 0 (length s) 'face '(:foreground "blue") s) + (push s result)) + (push ":\n" result) + (push (concat + " " + "Indent current line (done by specific major mode function).\n") + result) + (push (format " %17s %s\n" cmdstr (key-description [tab])) result) + ) + ((eq 'key-cat-complete cmd) + (let ((s "Completion")) + (put-text-property 0 (length s) 'face '(:foreground "blue") s) + (push s result)) + (push ":\n" result) + (push (concat + " " + "Performe completion at point (done by specific major mode function).\n") + result) + (push (format " %17s %s\n" cmdstr (key-description [meta tab])) result) + ) + (t + (let ((s (format "`%s': (not a function)\n" cmd))) + (put-text-property 0 (length s) 'face '(:foreground "red") s) + (push s result)))) + (let ((keys (key-cat-where-is cmd))) + (push (format "`%s':\n" cmd) result) + (setq doc (documentation cmd t)) + (push + (concat + " " + (if doc + (substring doc 0 (string-match "\n" doc)) + "(not documented)") + "\n") + result) + (if (not keys) + (if (interactive-form cmd) + (push (format " %17s M-x %s\n" cmdstr cmd) result) + (let ((s "(not an interactive command)")) + (put-text-property 0 (length s) 'face '(:foreground "red") s) + (push (format " %17s %s\n" cmdstr s) result))) + (dolist (key keys) + (push (format " %17s " cmdstr) result) + (push (format "%s\n" + (if (eq (elt key 0) 'xmenu-bar) + "Menus" + (key-description key))) + result) + (setq cmdstr "")))))))) + (save-excursion + (with-current-buffer (help-buffer) + (with-output-to-temp-buffer (help-buffer) + (insert + (let ((s "Some important commands\n")) + (put-text-property 0 (length s) + 'face '(:weight bold + :height 1.5 + :foreground "RGB:00/00/66") s) + s)) + (setq result (reverse result)) + (dolist (r result) + (insert r)) + ))) + (message ""))) + (error (message "%s" (error-message-string err))))) + +;; Mostly copied from `where-is': +(defun key-cat-where-is (definition) + "Return key sequences that invoke the command DEFINITION. +Argument is a command definition, usually a symbol with a function definition." + (let ((func (indirect-function definition)) + (defs nil) + (all-keys)) + ;; In DEFS, find all symbols that are aliases for DEFINITION. + (mapatoms (lambda (symbol) + (and (fboundp symbol) + (not (eq symbol definition)) + (eq func (condition-case () + (indirect-function symbol) + (error symbol))) + (push symbol defs)))) + ;; Look at all the symbols--first DEFINITION, + ;; then its aliases. + (dolist (symbol (cons definition defs)) + (let* ((remapped (command-remapping symbol)) + (keys (where-is-internal + ;;symbol overriding-local-map nil nil remapped))) + symbol nil nil nil remapped))) + (when keys + (dolist (key keys) + (setq all-keys (cons key all-keys)))))) + all-keys)) + + + +(provide 'key-cat) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; key-cat.el ends here diff --git a/emacs.d/nxhtml/util/majmodpri.el b/emacs.d/nxhtml/util/majmodpri.el new file mode 100644 index 0000000..7bdbea6 --- /dev/null +++ b/emacs.d/nxhtml/util/majmodpri.el @@ -0,0 +1,448 @@ +;;; 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 diff --git a/emacs.d/nxhtml/util/markchars.el b/emacs.d/nxhtml/util/markchars.el new file mode 100644 index 0000000..e1179b7 --- /dev/null +++ b/emacs.d/nxhtml/util/markchars.el @@ -0,0 +1,151 @@ +;;; markchars.el --- Mark chars fitting certain characteristics +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2010-03-22 Mon +;; Version: +;; Last-Updated: 2010-03-25 Thu +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; Required feature `markchars' was not provided. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Mark special chars, by default non-ascii, non-IDN chars. See +;; `markchars-mode'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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 3, 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: + +(require 'idn) + +;;;###autoload +(defgroup markchars nil + "Customization group for `markchars-mode'." + :group 'convenience) + +(defface markchars-light + '((t (:underline "light blue"))) + "Light face for `markchars-mode' char marking." + :group 'markchars) + +(defface markchars-heavy + '((t (:underline "magenta"))) + "Heavy face for `markchars-mode' char marking." + :group 'markchars) + +(defcustom markchars-face 'markchars-heavy + "Pointer to face used for marking chars." + :type 'face + :group 'markchars) + +;; (markchars-nonidn-fun (point-max)) +;; åäö +;; character: å (229, #o345, #xe5) +;; (idn-is-recommended 229) => t +;; 152F ; 00B7 0034 ; SL # ( ᔯ → ·4 ) CANADIAN SYLLABICS YWE → MIDDLE DOT, DIGIT FOUR # {source:835} ᐧ4 {[source:696]} + +(defun markchars-nonidn-fun (bound) + "Font lock matcher for non-IDN, non-ascii chars." + (let* ((beg (catch 'beg + (while (< (point) bound) + (let ((char (char-after))) + (unless (or (< char 256) + (idn-is-recommended char)) + (throw 'beg (point))) + (forward-char))))) + (end (when beg + (catch 'end + (while (< (point) bound) + (let ((char (char-after (point)))) + (when (or (< char 256) + (idn-is-recommended char)) + (throw 'end (point))) + (forward-char))))))) + (when beg + (setq end (or end bound)) + (set-match-data (list (copy-marker beg) (copy-marker end))) + t))) + +(defcustom markchars-keywords (or (when (fboundp 'idn-is-recommended) 'markchars-nonidn-fun) + "[[:nonascii:]]+") + "Regexp or function for font lock to use for characters to mark. +By default it matches non-IDN, non-ascii chars." + :type '(choice (const :tag "Non-ascii chars" "[[:nonascii:]]+") + (const :tag "Non IDN chars (Unicode.org tr39 suggestions)" markchars-nonidn-fun)) + :group 'markchars) + +(defvar markchars-used-keywords nil + "Keywords currently used for font lock.") +(put 'markchars-used-keywords 'permanent-local t) + +(defun markchars-set-keywords () + "Set `markchars-used-keywords' from options." + (set (make-local-variable 'markchars-used-keywords) + (list + (list markchars-keywords + (list 0 '(put-text-property (match-beginning 0) (match-end 0) + 'face markchars-face)))))) + +;;;###autoload +(define-minor-mode markchars-mode + "Mark special characters. +Which characters to mark are defined by `markchars-keywords'. + +The default is to mark non-IDN, non-ascii chars with a magenta +underline. + +For information about IDN chars see `idn-is-recommended'. + +If you change anything in the customization group `markchars' you +must restart this minor mode for the changes to take effect." + :group 'markchars + :lighter " ø" + (if markchars-mode + (progn + (markchars-set-keywords) + (font-lock-add-keywords nil markchars-used-keywords)) + (font-lock-remove-keywords nil markchars-used-keywords)) + ;; Fix-me: Something like mumamo-mark-for-refontification should be in Emacs. + (if (fboundp 'mumamo-mark-for-refontification) + (save-restriction + (widen) + (mumamo-mark-for-refontification (point-min) (point-max))) + (font-lock-fontify-buffer))) + +;;;###autoload +(define-globalized-minor-mode markchars-global-mode markchars-mode + (lambda () (markchars-mode 1)) + :group 'markchars) + +(provide 'markchars) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; markchars.el ends here diff --git a/emacs.d/nxhtml/util/mlinks.el b/emacs.d/nxhtml/util/mlinks.el new file mode 100644 index 0000000..0f81654 --- /dev/null +++ b/emacs.d/nxhtml/util/mlinks.el @@ -0,0 +1,1367 @@ +;;; mlinks.el --- Minor mode making major mode dependent links +;; +;; Author: Lennar Borgman +;; Created: Tue Jan 16 2007 +(defconst mlinks:version "0.28") ;;Version: +;; Last-Updated: 2010-01-05 Tue +;; Keywords: +;; Compatibility: +;; +;; Fxeatures that might be required by this library: +;; +;; `appmenu', `cl', `mail-prsvr', `mm-util', `ourcomments-util', +;; `url-expand', `url-methods', `url-parse', `url-util', +;; `url-vars'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; This file implements the minor mode `mlinks-mode' that create +;; hyperlinks for different major modes. Such links can be visible or +;; invisible. The meanings of the links are defined per mode. +;; +;; Examples: +;; +;; - In in html style modes the links are visible they can mean either +;; open a file for editing, go to an achnor or view the link in a +;; web browser etc. +;; +;; - In emacs lisp mode the links are invisible, but maybe highlighed +;; when point or mouse is on them. (Having them highlighted when +;; point is on them can be a quick way to check that you have +;; spelled a symbol correct.) The meanings of the links in emacs +;; lisp mode are go to definition. +;; +;; Common to links that open a buffer in Emacs is that you can the +;; buffer opened in the same window, the other window or in a new +;; frame. The same key binding is used in all major modes for this. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; FIX-ME: url-hexify-string etc +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'appmenu nil t)) +(eval-when-compile (require 'mumamo nil t)) +(eval-when-compile (require 'ourcomments-util nil t)) + +(require 'rx) +(require 'url-parse) +(require 'url-expand) + +(defvar mlinks-point-hilighter-overlay nil) +(make-variable-buffer-local 'mlinks-point-hilighter-overlay) +(put 'mlinks-point-hilighter-overlay 'permanent-local t) + +;;;###autoload +(defgroup mlinks nil + "Customization group for `mlinks-mode'." + :group 'nxhtml + :group 'hypermedia) + +(defvar mlinks-link-face 'mlinks-link-face) +(defface mlinks-link-face + '((t (:inherit highlight))) + "Face normally active links have on them." + :group 'mlinks) + +(defvar mlinks-hyperactive-link-face 'mlinks-hyperactive-link-face) +(defface mlinks-hyperactive-link-face + '((t (:inherit isearch))) + "Face hyper active links have on them." + :group 'mlinks) + +(defvar mlinks-font-lock-face 'mlinks-font-lock-face) +(defface mlinks-font-lock-face + '((t :inherit link)) + "Default face for MLinks' links." + :group 'mlinks) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Mode function bindings + +;;(customize-option mlinks-mode-functions) +(defcustom mlinks-mode-functions + '( + ;; For message buffer etc. + (fundamental-mode + ((goto mlinks-elisp-goto) + (hili mlinks-elisp-hili) + (hion t) + ) + ) + (emacs-lisp-mode + ((goto mlinks-elisp-goto) + (hili mlinks-elisp-hili) + (hion t) + ) + ) + ;; *scractch* + (lisp-interaction-mode + ((goto mlinks-elisp-goto) + (hili mlinks-elisp-hili) + (hion t) + ) + ) + (help-mode + ((goto mlinks-elisp-goto) + (hili mlinks-elisp-hili) + (hion t) + ) + ) + (Info-mode + ((goto mlinks-elisp-goto) + (hili mlinks-elisp-hili) + (hion t) + ) + ) + (Custom-mode + ((goto mlinks-elisp-custom-goto) + (hili mlinks-elisp-hili) + (hion t) + (fontify mlinks-custom-fontify) + ) + ) + (text-mode + ((goto mlinks-goto-plain-url) + (hion t) + (fontify mlinks-plain-urls-fontify) + ) + ) + (nxhtml-mode + ((hion t) + (fontify mlinks-html-fontify) + (goto mlinks-html-style-goto) + ) + ) + (nxml-mode + ((hion t) + (fontify mlinks-html-fontify) + (goto mlinks-html-style-goto) + ) + ) + (sgml-mode + ((hion t) + (fontify mlinks-html-fontify) + (goto mlinks-html-style-goto) + ) + ) + (html-mode + ((hion t) + (fontify mlinks-html-fontify) + (goto mlinks-html-style-goto) + ) + ) + ) + "Defines MLinks hyperlinks for major modes. +" + ;; Each element in the list is a list with two elements + + ;; \(MAJOR-MODE SETTINGS) + + ;; where MAJOR-MODE is the major mode for which the settings SETTINGS should be used. + ;; SETTINGS is an association list which can have the following element types + + ;; \(hili HILIGHT-FUN) ;; Mandatory + ;; \(goto GOTO-FUN) ;; Mandatory + ;; \(hion HION-BOOL) ;; Optional + ;; \(next NEXT-FUN) ;; Optional + ;; \(prev PREV-FUN) ;; Optional + + ;; Where + ;; - HILIGHT-FUN is the function to hilight a link when point is + ;; inside the link. This is done when Emacs is idle. + ;; - GOTO-FUN is the function to follow the link at point. + ;; - HION-BOOL is t or nil depending on if hilighting should be on + ;; by default. + ;; - NEXT-FUN is the function to go to the next link. + ;; - PREV-FUN is the function to go to the previous link." + ;; ;;:type '(repeat (alist :key-type symbol :value-type (alist :key-type symbol :value symbol))) + :type '(alist :key-type major-mode-function + :value-type (list + (set + (const :tag "Enable MLinks in this major mode" hion) + (const :tag "Mark All Links" mark) + (list :tag "Enable" (const :tag "Hilighting" hili) function) + (list :tag "Enable" (const :tag "Follow Link" goto) function) + (list :tag "Enable" (const :tag "Goto Next Link" next) function) + (list :tag "Enable" (const :tag "Goto Previous Link" prev) function) + ))) + :group 'mlinks) + + +(defun mlinks-get-mode-value (which) + (let* ((major major-mode) + (mode-rec (assoc major mlinks-mode-functions))) + (catch 'mode-rec + (while (and major + (not mode-rec)) + (setq major (get major 'derived-mode-parent)) + (setq mode-rec (assoc major mlinks-mode-functions)) + (when mode-rec (throw 'mode-rec nil)))) + (when mode-rec + (let* ((mode (car mode-rec)) + (funs-alist (cadr mode-rec)) + (funs (assoc which funs-alist))) + (cdr funs))))) + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Minor modes + +;; (appmenu-dump-keymap mlinks-mode-map) +(defvar mlinks-mode-map + (let ((m (make-sparse-keymap "mlinks"))) + (define-key m [(control ?c) ?\r ?\r] 'mlinks-goto) + (define-key m [(control ?c) ?\r ?w] 'mlinks-goto-other-window) + (define-key m [(control ?c) ?\r ?f] 'mlinks-goto-other-frame) + (define-key m [(control ?c) ?\r ?n] 'mlinks-next-saved-position) + (define-key m [(control ?c) ?\r ?p] 'mlinks-prev-saved-position) + (define-key m [(control ?c) ?\r S-tab] 'mlinks-backward-link) + (define-key m [(control ?c) ?\r tab] 'mlinks-forward-link) + (define-key m [(control ?c) ?\r ?h] 'mlinks-toggle-hilight) + (define-key m [(control ?c) ?\r ?c] 'mlinks-copy-link-text) + m)) + +;;;###autoload +(define-minor-mode mlinks-mode + "Recognizes certain parts of a buffer as hyperlinks. +The hyperlinks are created in different ways for different major +modes with the help of the functions in the list +`mlinks-mode-functions'. + +The hyperlinks can be hilighted when point is over them. Use +`mlinks-toggle-hilight' to toggle this feature for the current +buffer. + +All keybindings in this mode are by default done under the prefi§x +key + + C-c RET + +which is supposed to be a kind of mnemonic for link (alluding to +the RET key commonly used in web browser to follow a link). +\(Unfortunately this breaks the rules in info node `Key Binding +Conventions'.) Below are the key bindings defined by this mode: + +\\{mlinks-mode-map} + +For some major modes `mlinks-backward-link' and +`mlinks-forward-link' will take you to the previous/next link. +By default the link moved to will be active, see +`mlinks-active-links'. + +" + nil + " L" + nil + :keymap mlinks-mode-map + :group 'mlinks + (if mlinks-mode + (progn + (mlinks-add-appmenu) + (mlinks-start-point-hilighter) + (mlinks-add-font-lock)) + (mlinks-stop-point-hilighter) + (when mlinks-point-hilighter-overlay + (when (overlayp mlinks-point-hilighter-overlay) + (delete-overlay mlinks-point-hilighter-overlay)) + (setq mlinks-point-hilighter-overlay nil)) + (mlinks-remove-font-lock))) +(put 'mlinks-mode 'permanent-local t) + +(defun mlinks-turn-on-in-buffer () + (let ((hion (unless (and (boundp 'mumamo-set-major-running) + mumamo-set-major-running) + (mlinks-get-mode-value 'hion)))) + (when hion (mlinks-mode 1)))) + +;;;###autoload +(define-globalized-minor-mode mlinks-global-mode mlinks-mode + mlinks-turn-on-in-buffer + "Turn on `mlink-mode' in all buffer where it is specified. +This is specified in `mlinks-mode-functions'." + :group 'mlinks) + +;; The problem with global minor modes: +(when (and mlinks-global-mode + (not (boundp 'define-global-minor-mode-bug))) + (mlinks-global-mode 1)) + +;;(define-toggle mlinks-active-links t +(define-minor-mode mlinks-active-links + "Use quick movement keys on active links if non-nil. +When moving to an mlink with `mlinks-forward-link' or +`mlinks-backward-link' the link moved to will be in an active +state. This is marked with a new color \(the face `isearch'). +When the new color is shown the following keys are active + +\\{mlinks-hyperactive-point-hilighter-keymap} +Any command cancels this state." + :global t + :init-value t + :group 'mlinks) + + + +(defun mlinks-link-text-prop-range (pos) + (let* ((link-here (get-text-property pos 'mlinks-link)) + (beg (when link-here (previous-single-char-property-change (+ pos 1) 'mlinks-link))) + (end (when link-here (next-single-char-property-change (- pos 0) 'mlinks-link)))) + (when (and beg end) + (cons beg end)))) + +(defun mlinks-link-range (pos) + (or (mlinks-link-text-prop-range pos) + (let ((funs-- (mlinks-get-mode-value 'hili))) + (when funs-- + (save-match-data + (run-hook-with-args-until-success 'funs--)))))) + +(defun mlinks-link-at-point () + "Get link at point." + (mlinks-point-hilighter-1) + (when (and mlinks-point-hilighter-overlay + (overlay-buffer mlinks-point-hilighter-overlay)) + (let* ((ovl mlinks-point-hilighter-overlay) + (beg (overlay-start ovl)) + (end (overlay-end ovl))) + (buffer-substring-no-properties beg end)))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; At point highligher + +(defvar mlinks-point-hilighter-timer nil) + +(defun mlinks-stop-point-hilighter () + (when (timerp mlinks-point-hilighter-timer) + (cancel-timer mlinks-point-hilighter-timer) + (setq mlinks-point-hilighter-timer nil))) + +(defun mlinks-start-point-hilighter () + (mlinks-stop-point-hilighter) + (setq mlinks-point-hilighter-timer + (run-with-idle-timer 0.1 t 'mlinks-point-hilighter))) + +(defvar mlinks-link-overlay-priority 100) + +(defun mlinks-make-point-hilighter-overlay (bounds) + (unless mlinks-point-hilighter-overlay + (setq mlinks-point-hilighter-overlay + (make-overlay (car bounds) (cdr bounds))) + (overlay-put mlinks-point-hilighter-overlay 'priority mlinks-link-overlay-priority) + (overlay-put mlinks-point-hilighter-overlay 'mouse-face 'highlight) + (mlinks-set-normal-point-hilight) + )) + +(defun mlinks-point-hilighter () + "Mark link at point if any. +This moves the hilight point overlay to point or deletes it." + ;; This runs in a timer, protect it. + (condition-case err + (let ((inhibit-point-motion-hooks t)) + (mlinks-point-hilighter-1)) + (error "mlinks-point-hilighter error: %s" (error-message-string err)))) + +(defun mlinks-point-hilighter-1 () + (when mlinks-mode + (let ((bounds-- (mlinks-link-range (point)))) + (if bounds-- + (if mlinks-point-hilighter-overlay + (move-overlay mlinks-point-hilighter-overlay (car bounds--) (cdr bounds--)) + (mlinks-make-point-hilighter-overlay bounds--)) + (when mlinks-point-hilighter-overlay + (delete-overlay mlinks-point-hilighter-overlay)))))) + +(defvar mlinks-hyperactive-point-hilighter-keymap + (let ((m (make-sparse-keymap "mlinks"))) + (define-key m [S-tab] 'mlinks-backward-link) + (define-key m [tab] 'mlinks-forward-link) + (define-key m "\t" 'mlinks-forward-link) + (define-key m [?\r] 'mlinks-goto) + (define-key m [?w] 'mlinks-goto-other-window) + (define-key m [?f] 'mlinks-goto-other-frame) + (define-key m [mouse-1] 'mlinks-goto) + (set-keymap-parent m mlinks-mode-map) + m)) + +(defvar mlinks-point-hilighter-keymap + (let ((m (make-sparse-keymap "mlinks"))) + (define-key m [mouse-1] 'mlinks-goto) + (set-keymap-parent m mlinks-mode-map) + m)) + +(defun mlinks-point-hilighter-pre-command () + (condition-case err + (unless (let ((map (overlay-get mlinks-point-hilighter-overlay 'keymap))) + (where-is-internal this-command + (list + map))) + (mlinks-set-normal-point-hilight) + (unless mlinks-point-hilighter-timer + (delete-overlay mlinks-point-hilighter-overlay))) + (error (message "mlinks-point-hilighter-pre-command: %s" err)))) +(put 'mlinks-point-hilighter-pre-command 'permanent-local t) + +(defun mlinks-set-hyperactive-point-hilight () + "Make link hyper active, ie add some special key binding. +Used after jumping specifically to a link. The idea is that the +user may want to easily jump between links in this state." + (add-hook 'pre-command-hook 'mlinks-point-hilighter-pre-command nil t) + (mlinks-point-hilighter) + (overlay-put mlinks-point-hilighter-overlay 'face mlinks-hyperactive-link-face) + (overlay-put mlinks-point-hilighter-overlay 'keymap mlinks-hyperactive-point-hilighter-keymap)) + +(defun mlinks-set-normal-point-hilight () + "Make link normally active as if you happened to be on it." + (remove-hook 'pre-command-hook 'mlinks-point-hilighter-pre-command t) + (mlinks-point-hilighter) + (overlay-put mlinks-point-hilighter-overlay 'face mlinks-link-face) + (overlay-put mlinks-point-hilighter-overlay 'keymap mlinks-point-hilighter-keymap)) + +(defun mlinks-set-point-hilight-after-jump-to () + "Set hilight style after jump to link." + (if mlinks-active-links + (mlinks-set-hyperactive-point-hilight) + (mlinks-set-normal-point-hilight))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Jumping around + +(defvar mlinks-places nil) +(make-variable-buffer-local 'mlinks-placesn) +(put 'mlinks-places 'permanent-local t) + +(defvar mlinks-places-n 0) +(make-variable-buffer-local 'mlinks-places-n) +(put 'mlinks-places-n 'permanent-local t) + +(defun mlinks-has-links () + (or (mlinks-get-mode-value 'fontify) + (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + ;; Fix-me: just assume multi major has it... Need a list of + ;; major modes. There is no way to get such a list for the + ;; multi major mode (since you can't know what the chunk + ;; functions will return. However you can get a list of + ;; current chunks major mode. + t + ))) + +(defun mlinks-backward-link () + "Go to previous `mlinks-mode' link in buffer." + (interactive) + (if (not (mlinks-has-links)) + (message "There is no way to go to previous link for this major mode") + (let ((res (mlinks-prev-link))) + (if res + (progn + (goto-char res) + (mlinks-set-point-hilight-after-jump-to)) + (message "No previous link found"))))) + +(defun mlinks-forward-link () + "Go to next `mlinks-mode' link in buffer." + (interactive) + (if (not (mlinks-has-links)) + (message "There is no way to go to next link for this major mode") + (let ((res (mlinks-next-link))) + (if res + (progn + (goto-char res) + (mlinks-set-point-hilight-after-jump-to)) + (message "No next link found"))))) + + +(defun mlinks-goto () + "Follow `mlinks-mode' link at current point. +Save the current position so that they can be move to again by +`mlinks-prev-saved-position' and `mlinks-next-saved-position'. + +Return non-nil if link was followed, otherewise nil." + (interactive) + (mlinks-goto-1 nil)) + +(defun mlinks-goto-other-window () + "Like `mlinks-goto' but opens in other window. +Uses `switch-to-buffer-other-window'." + (interactive) + (mlinks-goto-1 'other-window)) + +(defun mlinks-goto-other-frame () + "Like `mlinks-goto' but opens in other frame. +Uses `switch-to-buffer-other-frame'." + (interactive) + (mlinks-goto-1 'other-frame)) + +(defun mlinks-goto-1(where) + (push-mark) + (let* ((funs (mlinks-get-mode-value 'goto)) + (old (point-marker)) + (mlinks-temp-buffer-where where) + (res (run-hook-with-args-until-success 'funs))) + (if (not res) + (progn + (message "Don't know how to follow this MLink link") + nil) + (unless (= old (point-marker)) + (let* ((prev (car mlinks-places))) + (when (or (not prev) + ;;(not (markerp prev)) + (not (marker-buffer prev)) + (/= old prev)) + (setq mlinks-places (cons old mlinks-places)) + (setq mlinks-places-n (length mlinks-places)))))))) + + +(defun mlinks-prev-saved-position () + "Go to previous position saved by `mlinks-goto'." + (interactive) + (unless (mlinks-goto-n (1- mlinks-places-n)) + (message "No previous MLink position"))) + +(defun mlinks-next-saved-position () + "Go to next position saved by `mlinks-goto'." + (interactive) + (unless (mlinks-goto-n (1+ mlinks-places-n)) + (message "No next MLink position"))) + +(defun mlinks-goto-n (to) + (if (not mlinks-places) + (message "No saved MLinks positions") + (let ((minp 1) + (maxp (length mlinks-places))) + (if (<= to minp) + (progn + (setq to minp) + (message "Going to first MLinks position")) + (if (>= to maxp) + (progn + (setq to maxp) + (message "Going to last MLinks position")))) + (setq mlinks-places-n to) + (let ((n (- maxp to)) + (places mlinks-places) + place + buffer + point) + (while (> n 0) + (setq places (cdr places)) + (setq n (1- n))) + (setq place (car places)) + (mlinks-switch-to-buffer (marker-buffer place)) + (goto-char place))))) + +(defvar mlinks-temp-buffer-where nil) +(defun mlinks-switch-to-buffer (buffer) + (mlinks-switch-to-buffer-1 buffer mlinks-temp-buffer-where)) + +(defun mlinks-switch-to-buffer-1(buffer where) + (cond + ((null where) + (switch-to-buffer buffer)) + ((eq where 'other-window) + (switch-to-buffer-other-window buffer)) + ((eq where 'other-frame) + (switch-to-buffer-other-frame buffer)) + (t + (error "Invalid argument, where=%s" where)))) + +;; FIXME: face, var +(defun mlinks-custom (var) + (customize-option var) + ) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; AppMenu support + +(defun mlinks-appmenu () + (when mlinks-mode + ;; Fix-me: reverse the list + (let ((link-val (mlinks-link-at-point)) + (map (make-sparse-keymap "mlinks")) + (num 2)) + (when (mlinks-get-mode-value 'prev) + (define-key map [mlinks-next-link] + (list 'menu-item "Next Link" 'mlinks-forward-link))) + (when (mlinks-get-mode-value 'next) + (define-key map [mlinks-prev-link] + (list 'menu-item "Previous Link" 'mlinks-backward-link))) + (when link-val + (let* ((possible (when (member major-mode '(html-mode nxhtml-mode nxml-mode sqml-mode text-mode)) + (mlinks-html-possible-href-actions link-val))) + (mailto (assoc 'mailto possible)) + (view-web (assoc 'view-web possible)) + (view-web-base (assoc 'view-web-base possible)) + (edit (assoc 'edit possible)) + (file (nth 1 edit)) + (anchor (nth 2 edit)) + (choices) + (answer) + ) + (when (> (length map) num) + (define-key map [mlinks-href-sep] (list 'menu-item "--"))) + (setq num (length map)) + (when view-web + (define-key map [mlinks-href-view-web] + (list 'menu-item "Browse Link Web Url" + `(lambda () (interactive) + (browse-url ,link-val))))) + (when view-web-base + (define-key map [mlinks-href-view-web-based] + (list 'menu-item "Browse Link Web Url (base URL found)" + `(lambda () (interactive) + (browse-url (cdr ,view-web-base)))))) + (when mailto + (define-key map [mlinks-href-mail] + (list 'menu-item (concat "&Mail to " (substring link-val 7)) + `(lambda () (interactive) + (mlinks-html-mail-to ,link-val))))) + (when edit + (when (and (file-exists-p file) + (not anchor) + (assoc 'upload possible)) + (let ((abs-file (expand-file-name file))) + (define-key map [mlinks-href-upload] + (list 'menu-item "Upload Linked File" + `(lambda () (interactive) + (html-upl-upload-file ,abs-file)))))) + (when (and (file-exists-p file) + (not anchor) + (assoc 'edit-gimp possible)) + (let ((abs-file (expand-file-name file))) + (define-key map [mlinks-href-edit-gimp] + (list 'menu-item "Edit Linked File with GIMP" + `(lambda () (interactive) + (gimpedit-edit-file ,abs-file)))))) + (when (and (file-exists-p file) + (assoc 'view-local possible)) + (let ((url (concat "file:///" (expand-file-name file)))) + (when anchor + (let ((url-anchor (concat url "#" anchor))) + (define-key map [mlinks-href-view-file-at] + (list 'menu-item (concat "Browse Linked File URL at #" anchor) + `(lambda () (interactive) + (browse-url ,url-anchor)))))) + (define-key map [mlinks-href-view-file] + (list 'menu-item "&Browse Linked File URL" + `(lambda () (interactive) + (browse-url ,url)))))) + (when (> (length map) num) + (define-key map [mlinks-href-sep-2] (list 'menu-item "--"))) + (setq num (length map)) + (unless (equal file (buffer-file-name)) + (define-key map [mlinks-href-edit] + (list 'menu-item "&Open Linked File" + `(lambda () (interactive) (mlinks-goto)))) + (define-key map [mlinks-href-edit-window] + (list 'menu-item "&Open Linked File in Other Window" + `(lambda () (interactive) (mlinks-goto-other-window)))) + (define-key map [mlinks-href-edit-frame] + (list 'menu-item "&Open Linked File in New Frame" + `(lambda () (interactive) (mlinks-goto-other-frame)))) + ) + (when (and (file-exists-p file) anchor) + (define-key map [mlinks-href-edit-at] + (list 'menu-item (concat "Open Linked File &at #" anchor) + `(lambda () (interactive) + (mlinks-goto))))) + ) + (when (> (length map) num) + (define-key map [mlinks-href-sep-1] (list 'menu-item "--"))) + (setq num (length map)) + (when link-val + (define-key map [mlinks-href-copy-link] + (list 'menu-item "&Copy Link Text" + 'mlinks-copy-link-text))))) + (when (> (length map) 2) + map)))) + +(defun mlinks-add-appmenu () + "Add entries for MLinks to AppMenu." + (when (featurep 'appmenu) + (appmenu-add 'mlinks 100 'mlinks-mode "Current MLink" 'mlinks-appmenu))) + +(defun mlinks-copy-link-text () + "Copy text of `mlinks-mode' link at point to clipboard." + (interactive) + (mlinks-point-hilighter) + (let ((ovl mlinks-point-hilighter-overlay)) + (if (and ovl + (overlayp ovl) + (overlay-buffer ovl) + (eq (current-buffer) + (overlay-buffer ovl)) + (<= (overlay-start ovl) + (point)) + (>= (overlay-end ovl) + (point))) + (let* ((beg (overlay-start ovl)) + (end (overlay-end ovl)) + (str (buffer-substring beg end))) + (copy-region-as-kill beg end) + (message "Copied %d chars to clipboard" (length str))) + (message "No link here to copy")))) + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;; text-mode etc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defvar mlinks-plain-urls-regexp + (rx-to-string `(or (submatch (optional "mailto:") + (regexp ,(concat + ;;"[a-z0-9$%(*-=?[_][^<>\")!;:,{}]*" + "[a-z0-9$%(*=?[_-][^<>\")!;:,{}]*" + "\@" + "\\(?:[a-z0-9\-]+\.\\)+[a-z0-9]\\{2,4\\}"))) + (submatch (or (regexp "https?://") + "www.") + (1+ (any ,url-get-url-filename-chars)) + ) + ))) + +(defun mlinks-plain-urls-fontify (bound) + (mlinks-fontify bound mlinks-plain-urls-regexp 0)) + +(defun mlinks-goto-plain-url () + (let* ((range (mlinks-link-range (point))) + (link (when range (buffer-substring-no-properties (car range) (cdr range))))) + ;;(mlinks-html-href-act-on link) + (when (= 0 (string-match mlinks-plain-urls-regexp link)) + (let ((which (if (match-end 1) 1 2))) + (cond + ((= 1 which) + (mlinks-html-mail-to link) + t) + ((= 2 which) + (browse-url link) + t) + (t nil)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;; nxhtml-mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun mlinks-html-style-goto () + (mlinks-html-style-mode-fun t)) + +(defvar mlinks-html-link-regexp + ;; This value takes care of nxhtml-strval-mode (and is therefore a little bit incorrect ...) + ;;"\\(?:^\\|[[:space:]]\\)\\(?:href\\|src\\)[[:space:]]*=[[:space:]]*\"\\([^<«\"]*\\)\"" + (rx (or "^" space) + (or "href" "src") + (0+ space) + "=" + (0+ space) + (submatch + (or + (seq "\"" + (and + (0+ (not (any "\"")))) + "\"") + (seq "'" + (and + (0+ (not (any "\'")))) + "'"))))) + +(defun mlinks-html-style-mode-fun (goto) + (let (start + end + bounds) + (save-excursion + (forward-char) + (when (< 0 (skip-chars-forward "^\"'" (line-end-position))) + (forward-char) + (save-match-data + (when (looking-back + mlinks-html-link-regexp + (line-beginning-position -1)) + (let ((which (if (match-beginning 1) 1 2))) + (setq start (1+ (match-beginning which))) + (setq end (1- (match-end which)))) + (setq bounds (cons start end)))))) + (when start + (if (not goto) + bounds + (let ((href-val (buffer-substring-no-properties start end))) + (mlinks-html-href-act-on href-val)) + t)))) + +(defun mlink-check-file-to-edit (file) + (assert (file-name-absolute-p file)) + (let ((file-dir (file-name-directory file))) + (unless (file-directory-p file-dir) + (if (file-directory-p (file-name-directory file)) + (if (yes-or-no-p (format "Directory %s does not exist. Create it? " file-dir)) + (make-directory file-dir) + (setq file nil)) + (if (yes-or-no-p (format "Directory %s and its parent does not exist. Create them? " file-dir)) + (make-directory file-dir t) + (setq file nil)))) + file)) + +(defun mlinks-html-edit-at (file &optional anchor) + (let ((abs-file (if (file-name-absolute-p file) + file + (expand-file-name file)))) + (if (or (file-directory-p abs-file) + (string= abs-file + (file-name-as-directory abs-file))) + (if (file-directory-p abs-file) + (when (y-or-n-p (format "Do you want to edit the directory %s? : " abs-file)) + (dired abs-file)) + (message "Can't find directory %s" abs-file)) + (when (mlink-check-file-to-edit abs-file) + (let ((b (find-file-noselect abs-file))) + (mlinks-switch-to-buffer b)) + (when anchor + (let ((here (point)) + (anchor-regexp (concat "\\(?:id\\|name\\)[[:space:]]*=[[:space:]]*\"" anchor "\""))) + (goto-char (point-min)) + (if (search-forward-regexp anchor-regexp nil t) + (backward-char 2) + (message "Anchor \"%s\" not found" anchor) + (goto-char here)))))))) + +(defun mlinks-html-mail-to (addr) + (browse-url addr)) + +(defun mlinks-html-href-act-on (href-val) + (if href-val + (let* ((possible (mlinks-html-possible-href-actions href-val)) + (edit (assoc 'edit possible)) + (file (nth 1 edit)) + (anchor (nth 2 edit)) + ) + (cond (edit + (mlinks-html-edit-at file anchor) + t) + ((assoc 'mailto possible) + (when (y-or-n-p "This is a mail address. Do you want to send a message to this mail address? ") + (mlinks-html-mail-to href-val))) + ((assoc 'view-web possible) + (when (y-or-n-p "Can't edit this URL, it is on the web. View the URL in your web browser? ") + (browse-url href-val))) + ((assoc 'view-web-base possible) + (when (y-or-n-p "Can't edit, based URL is to the web. View resulting URL in your web browser? ") + (browse-url (cdr (assoc 'view-web-base possible))))) + (t + (message "Do not know how to handle this URL")) + )) + (message "No value for href attribute"))) + +(defun mlinks-html-possible-href-actions (link) + (let ((urlobj (url-generic-parse-url link)) + (edit nil) + (possible nil)) + (cond ((member (url-type urlobj) '("http" "https")) + (add-to-list 'possible (cons 'view-web link))) + ((member (url-type urlobj) '("mailto")) + (add-to-list 'possible (cons 'mailto link))) + ((url-host urlobj) + (message "Do not know how to handle this URL")) + (t (setq edit t))) + (when edit + (let ((base-href (mlinks-html-find-base-href))) + (when base-href + (let ((baseobj (url-generic-parse-url base-href))) + (setq edit nil) + (cond ((member (url-type baseobj) '("http" "https")) + (add-to-list 'possible (cons 'view-web-base (url-expand-file-name link base-href)))) + ((url-host urlobj) + (message "Do not know how to handle this URL")) + (t (setq edit t))))) + (when edit + (let* ((full (split-string (url-filename urlobj) "#")) + (file (nth 0 full)) + (anchor (nth 1 full)) + ) + (when (equal file "") + (setq file (buffer-file-name))) + (when base-href + ;; We know at this point it is not a http url + (setq file (expand-file-name file base-href))) + (let ((ext (downcase (file-name-extension file)))) + (when (member ext '("htm" "html")) + (add-to-list 'possible (cons 'view-local (list file anchor)))) + (when (and (featurep 'gimpedit) + (member ext '("gif" "png" "jpg" "jpeg"))) + (add-to-list 'possible (cons 'edit-gimp (list file anchor))))) + (when (featurep 'html-upl) + (add-to-list 'possible (cons 'upload (list file anchor)))) + (add-to-list 'possible (cons 'edit (list file anchor))))))) + possible)) + +(defun mlinks-html-find-base-href () + "Return base href found in the current file." + (let ((base-href)) + (save-excursion + (goto-char (point-min)) + (while (and (not base-href) + (search-forward-regexp "\\|]*href *= *\"\\(.*?\\)\"") + (setq base-href (match-string-no-properties 1)))))) + base-href)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;; Custom-mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun mlinks-elisp-custom-goto () + (mlinks-elisp-mode-fun 'custom)) + +(defvar mlinks-custom-link-regexp + (rx "`" + (group + (1+ (not (any "'")))) + "'")) + +(defun mlinks-custom-fontify (bound) + (mlinks-fontify bound mlinks-custom-link-regexp 0)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;; emacs-lisp-mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defun mlinks-elisp-goto () + (mlinks-elisp-mode-fun 'source)) + +(defun mlinks-elisp-hili () + (mlinks-elisp-mode-fun nil)) + +(defun mlinks-elisp-mode-fun (goto) + (let ((symbol-name (thing-at-point 'symbol))) + (when symbol-name + (let ((bounds-- (bounds-of-thing-at-point 'symbol)) + ret--) + (if (save-excursion + (goto-char (cdr bounds--)) + (looking-back (concat "(\\(?:require\\|featurep\\)\s+'" symbol-name) + (line-beginning-position))) + (progn + (setq ret-- bounds--) + (when goto + (mlinks-elisp-mode-require symbol-name))) + (when (mlinks-elisp-mode-symbol symbol-name goto) + (setq ret-- bounds--))) + ret--)))) + +(defun mlinks-elisp-function (symbol) + "Go to an elisp function." + (interactive "aElisp function: ") + (mlinks-elisp-mode-symbol (symbol-name symbol) 'source)) + +(defun mlinks-elisp-mode-symbol (symbol-name-- goto--) + ;; Fix-me: use uninterned variables (see mail from Miles) + ;; Make these names a bit strange because they are boundp at the time of checking: + (let ((symbol-- (intern-soft symbol-name--)) + defs--) + (when (and symbol-- (boundp symbol--)) + (add-to-list 'defs-- 'variable)) + (when (fboundp symbol--) + (add-to-list 'defs-- 'function)) + (when (facep symbol--) + (add-to-list 'defs-- 'face)) + ;; Avoid some fails hits + (when (memq symbol-- + '(goto t + bounds-- funs-- ret-- + symbol-- defs-- symbol-name-- goto--)) + (setq defs-- nil)) + (let (defs-places + def) + (if (not goto--) + (progn + defs--) + (if (not defs--) + (progn + (message "Could not find definition of '%s" symbol-name--) + nil) + (dolist (type (cond + ((eq goto-- 'source) + '(nil defvar defface)) + ((eq goto-- 'custom) + '(defvar defface)) + (t + (error "Bad goto-- value: %s" goto--)))) + (condition-case err + (add-to-list 'defs-places + (cons + type + (save-excursion + (let* ((bp (find-definition-noselect symbol-- type)) + (b (car bp)) + (p (cdr bp))) + (unless p + (with-current-buffer b + (save-restriction + (widen) + (setq bp (find-definition-noselect symbol-- type))))) + bp)))) + (error + ;;(lwarn '(mlinks) :error "%s" (error-message-string err)) + (when t + (cond + ((eq (car err) 'search-failed)) + ((and (eq (car err) 'error) + (string= (error-message-string err) + (format "Don't know where `%s' is defined" symbol--)))) + (t + (message "%s: %s" (car err) (error-message-string err)))))))) + (if (= 1 (length defs-places)) + (setq def (car defs-places)) + (let ((many nil) + lnk) + (dolist (d defs-places) + (if (not lnk) + (setq lnk (cdr d)) + (unless (equal lnk (cdr d)) + (setq many t)))) + (if (not many) + (setq def (car defs-places)) + (let* ((alts (mapcar (lambda (elt) + (let ((type (car elt)) + str) + (setq str + (cond + ((not type) + "Function") + ((eq type 'defvar) + "Variable") + ((eq type 'defface) + "Face"))) + (cons str elt))) + defs-places)) + (stralts (mapcar (lambda (elt) + (car elt)) + alts)) + (completion-ignore-case t) + (stralt (completing-read "Type: " stralts nil t)) + (alt (assoc stralt alts))) + (setq def (cdr alt)))))) + (when def + (cond + ((eq goto-- 'source) + ;; Be sure to go to the real sources from CVS: + (let* ((buf (car (cdr def))) + ;; Avoid going to source + ;;(file (find-source-lisp-file (with-current-buffer buf buffer-file-name)) ) + (file (with-current-buffer buf buffer-file-name)) + (orig-buf (find-file-noselect file))) + (mlinks-switch-to-buffer orig-buf) + (let ((p (cdr (cdr def)))) + ;; Fix-me: Move this test to a more general place. + (if (or (< p (point-min)) + (> p (point-max))) + ;; Check for cloned indirect buffers. + (progn + (setq orig-buf + (catch 'view-in-buf + (dolist (indirect-buf (buffer-list)) + ;;(message "base-buffer=%s, orig-buf=%s, eq => %s" (buffer-base-buffer indirect-buf) orig-buf (eq (buffer-base-buffer indirect-buf) orig-buf)) + (when (eq (buffer-base-buffer indirect-buf) orig-buf) + (with-current-buffer indirect-buf + ;;(message "indirect-buf=%s" indirect-buf) + (unless (or (< p (point-min)) + (> p (point-max))) + ;;(message "switching") + ;;(mlinks-switch-to-buffer indirect-buf) + (message "mlinks: Switching to indirect buffer because of narrowing") + (throw 'view-in-buf indirect-buf) + )) + )))) + (when orig-buf + (mlinks-switch-to-buffer orig-buf)) + ;;(message "cb=%s" (current-buffer)) + (if (or (< p (point-min)) + (> p (point-max))) + (when (y-or-n-p (format "%s is invisible because of narrowing. Widen? " symbol--)) + (widen) + (goto-char p)) + (goto-char p))) + (goto-char p))))) + ((eq goto-- 'custom) + (mlinks-custom symbol--)) + (t + (error "Back goto-- value again: %s" goto--))))))))) + +(defun mlinks-elisp-mode-require (module) + (let ((where mlinks-temp-buffer-where)) + (cond + ((null where) + (find-library module)) + ((eq where 'other-window) + (other-window 1) + (find-library module)) + ((eq where 'other-frame) + (make-frame-command) + (find-library module)) + (t + (error "Invalid argument, where=%s" where))))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;; Helpers when adopting for modes ;;;;;;;;;;;;;;;;; + +;;; Save this, do not delete this comment: + +;; (defun mlinks-hit-test () +;; "Just a helper function for adding support for new modes." +;; (let* ( +;; (s0 (if (match-string 0) (match-string 0) "")) +;; (s1 (if (match-string 1) (match-string 1) "")) +;; (s2 (if (match-string 2) (match-string 2) "")) +;; (s3 (if (match-string 3) (match-string 3) "")) +;; ) +;; (message "match0=%s, match1=%s, match2=%s, match3=%s" s0 s1 s2 s3))) + +;; (defun mlinks-handle-reg-fun-list (reg-fun-list) +;; "Just a helper function." +;; (let (done +;; regexp +;; hitfun +;; m +;; p +;; b +;; ) +;; (dolist (rh reg-fun-list) +;; (message "rh=%s" rh);(sit-for 2) +;; (unless done +;; (setq regexp (car rh)) +;; (setq hitfun (cadr rh)) +;; (message "regexp=%s, hitfun=%s" regexp hitfun);(sit-for 1) +;; (when (and (save-match-data +;; (setq m (re-search-backward regexp (line-beginning-position) t)) +;; (> p (match-beginning 0)))) +;; (setq done t) +;; (setq b (match-beginning 0)) +;; (setq e (match-end 0)) +;; ) +;; (if (not (and b e +;; (< b p) +;; (< p e))) +;; (message "MLinks Mode did not find any link here") +;; (goto-char b) +;; (if (not (looking-at regexp)) +;; (error "Internal error, regexp %s, no match looking-at" regexp) +;; (let ((last (car mlinks-places)) +;; (m (make-marker))) +;; (set-marker m (line-beginning-position)) +;; (when (or (not last) +;; (/= m last)) +;; (setq mlinks-places (cons m mlinks-places)))) +;; (funcall hitfun)) +;; ))))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Font Lock use + +(defvar mlinks-link-update-pos-max nil) +(make-variable-buffer-local 'mlinks-link-update-pos-max) +(put 'mlinks-link-update-pos-max 'permanent-local t) + +(defun mlinks-remove-font-lock () + "Remove info from font-lock." + (when (mlinks-want-font-locking) + (mlink-font-lock nil))) + +(defun mlinks-add-font-lock () + "Add info to font-lock." + (when (mlinks-want-font-locking) + (mlink-font-lock t))) + +(defun mlinks-want-font-locking () + (or (mlinks-get-mode-value 'fontify) + (mlinks-get-mode-value 'next-mark))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Font Lock integration + +(defun mlink-font-lock (on) + (let* ((add-or-remove (if on 'font-lock-add-keywords 'font-lock-remove-keywords)) + (fontify-fun (car (mlinks-get-mode-value 'fontify))) + (args (list nil `(( ,fontify-fun ( 0 mlinks-font-lock-face t )))))) + (when fontify-fun + ;; Note: Had a lot of trouble with this which I modelled first + ;; after dlink. Using hi-lock as a model made it work with + ;; mumamo too. + ;; + ;; Next arg, HOW, is needed to get it to work with mumamo. This + ;; adds it last, like hi-lock. + (when on (setq args (append args (list t)))) + (apply add-or-remove args) + (font-lock-mode -1) + (font-lock-mode 1)))) + +(defun mlinks-html-fontify (bound) + (mlinks-fontify bound mlinks-html-link-regexp 1)) + +(defun mlinks-fontify (bound regexp border) + (let ((start (point)) + end-start + stop next-stop + (more t) + old-beg old-end + (wn 1) + ret) + ;; Note: we shouldnot use save-match-data here. Instead + ;; set-match-data is called below! + (if (not (re-search-forward regexp bound t)) + (setq end-start bound) + (setq ret t) + (setq end-start (- (point) 2)) + (let* ((which (if (match-beginning 1) 1 2)) + (beg (+ (match-beginning which) border)) + (end (- (match-end which) border))) + (put-text-property beg end 'mlinks-link t) + (set-match-data (list (copy-marker end) (copy-marker beg))))) + (setq stop start) + (setq next-stop -1) + (while (and (> 100 (setq wn (1+ wn))) + (setq next-stop (next-single-char-property-change stop 'mlinks-link nil end-start)) + (/= next-stop stop)) + (setq stop next-stop) + (if (get-text-property stop 'mlinks-link) + (setq old-beg stop) + (when old-beg + (remove-list-of-text-properties old-beg stop '(mlinks-link 'mouse-face))))) + ret)) + +(defun mlinks-next-link () + "Find next link, fontify as necessary." + (let* ((here (point)) + (prev-pos (point)) + (fontified-here (get-text-property (max (point-min) (1- prev-pos)) 'fontified)) + (fontified-to (next-single-char-property-change prev-pos 'fontified)) + (pos (next-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-to (point-max)))) + (fontified-all (and fontified-here (not fontified-to))) + ready + next-fontified-to) + (while (not (or ready + (and fontified-all + (not pos)))) + (if pos + (progn + (unless (get-text-property pos 'mlinks-link) + ;; Get to next link + (setq prev-pos pos) + (setq pos (next-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-to (point-max))))) + (when pos + (setq ready (get-text-property pos 'mlinks-link)) + (setq prev-pos pos) + (unless ready (setq pos nil)))) + (unless (or fontified-all fontified-to) + (if (get-text-property prev-pos 'fontified) + (setq fontified-all + (not (setq fontified-to + (next-single-char-property-change prev-pos 'fontified)))) + (setq fontified-to ( or (previous-single-char-property-change prev-pos 'fontified) + 1)))) + (setq next-fontified-to (min (+ fontified-to 5000) + (point-max))) + (mumamo-with-buffer-prepared-for-jit-lock + (progn + (put-text-property fontified-to next-fontified-to 'fontified t) + (font-lock-fontify-region fontified-to next-fontified-to))) + (setq fontified-to (next-single-char-property-change (1- next-fontified-to) + 'fontified)) + (setq fontified-all (not fontified-to)) + (setq pos (next-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-to (point-max)))))) + (when ready prev-pos))) + +(defun mlinks-prev-link () + "Find previous link, fontify as necessary." + (let* ((prev-pos (point)) + (fontified-from (previous-single-char-property-change prev-pos 'fontified)) + (fontified-here (get-text-property (max (point-min) (1- prev-pos)) 'fontified)) + (fontified-all (and fontified-here (not fontified-from))) + (pos (when fontified-here + (previous-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-from 1)))) + ready + next-fontified-from) + (while (not (or ready + (and fontified-all + (not pos)))) + (assert (numberp prev-pos) t) + (if pos + (progn + (when (and (> (1- pos) (point-min)) + (get-text-property (1- pos) 'mlinks-link)) + ;; Get out of current link + (setq prev-pos pos) + (setq pos (previous-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-from 1)))) + (when pos + (setq prev-pos pos) + (setq ready (and (get-text-property pos 'fontified) + (or (= 1 pos) + (not (get-text-property (1- pos) 'mlinks-link))) + (get-text-property pos 'mlinks-link))) + (unless ready (setq pos nil)))) + (setq next-fontified-from (max (- fontified-from 5000) + (point-min))) + (mumamo-with-buffer-prepared-for-jit-lock + (progn + (put-text-property next-fontified-from fontified-from 'fontified t) + (font-lock-fontify-region next-fontified-from fontified-from))) + (setq fontified-from (previous-single-char-property-change + (1+ next-fontified-from) 'fontified)) + (setq fontified-all (not fontified-from)) + (setq pos (previous-single-char-property-change prev-pos 'mlinks-link nil + (or fontified-from 1))))) + (when ready pos))) + + +;;; This is for the problem reported by some Asian users: +;;; +;;; Lisp error: (invalid-read-syntax "] in a list") +;;; +;; Local Variables: +;; coding: utf-8 +;; End: + +(provide 'mlinks) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; mlinks.el ends here diff --git a/emacs.d/nxhtml/util/mumamo-aspnet.el b/emacs.d/nxhtml/util/mumamo-aspnet.el new file mode 100644 index 0000000..c6bb2c7 --- /dev/null +++ b/emacs.d/nxhtml/util/mumamo-aspnet.el @@ -0,0 +1,227 @@ +;;; mumamo-aspnet.el --- Support for ASP .Net in `mumamo-mode'. +;; +;;;;; John: Please change here to what you want: +;; Author: John J Foerch (jjfoerch A earthlink O net) +;; Maintainer: +;; Created: ?? +;; Version: == +;; Last-Updated: Wed Dec 12 21:55:11 2007 (3600 +0100) +;; URL: http://OurComments.org/Emacs/Emacs.html +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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 GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Support for ASP .Net in `mumamo-mode'. If you want to use VB then +;; you have to get the vb mode that this is written for here: +;; +;; http://www.emacswiki.org/cgi-bin/wiki/VbDotNetMode +;; +;; A C# mode is already included in nXhtml. That is the one that this +;; library has been tested with. +;; +;; +;;; Usage: +;; +;; Put this file in you Emacs `load-path' and add in your .emacs: +;; +;; (eval-after-load 'mumamo +;; (require 'mumamo-aspnet) +;; (mumamo-aspnet-add-me)) +;; +;; A file with the extension .aspx will no be opened with nxhtml-mode +;; as the main major mode and with chunks in csharp-mode etc. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(eval-when-compile (require 'mumamo)) + +;;; + +;; (defun mumamo-aspnet-add-me() +;; "Make mumamo aware of the ASP.Net extension." +;; (add-to-list 'mumamo-chunk-family-list +;; '("ASP.Net nXhtml Family" nxhtml-mode +;; (mumamo-chunk-aspnet +;; mumamo-chunk-aspnet-script +;; mumamo-chunk-inlined-style +;; mumamo-chunk-inlined-script +;; mumamo-chunk-style= +;; mumamo-chunk-onjs= +;; )) +;; t) +;; (add-to-list 'mumamo-chunk-family-list +;; '("ASP.Net XHTML Family" html-mode +;; (mumamo-chunk-aspnet +;; mumamo-chunk-aspnet-script +;; mumamo-chunk-inlined-style +;; mumamo-chunk-inlined-script +;; mumamo-chunk-style= +;; mumamo-chunk-onjs= +;; )) +;; t) + + +;; (add-to-list 'mumamo-filenames-list +;; '("\\.aspx\\'" "ASP.Net nXhtml Family")) +;; ;; Make it SET for current session in Custom. +;; (customize-set-variable 'mumamo-filenames-list mumamo-filenames-list) +;; (customize-set-value 'mumamo-filenames-list mumamo-filenames-list) + +;; ;; this is how to set up mode aliases, should we need them. +;; (add-to-list 'mumamo-major-modes '(csharp-mode csharp-mode)) +;; (add-to-list 'mumamo-major-modes '(vbnet-mode vbnet-mode)) +;; ;; Make it SET for current session in Custom. +;; (customize-set-variable 'mumamo-major-modes mumamo-major-modes) +;; (customize-set-value 'mumamo-major-modes mumamo-major-modes) +;; ) + + +;;; aspnet + +(defvar mumamo-aspnet-page-language-mode-spec nil + "A mumamo mode-spec for the default language of an ASP.Net page. +This is what is set with the directive `@ Page Language' on the +page. + +Internal variable.") +(make-variable-buffer-local 'mumamo-aspnet-page-language-mode-spec) +;;(add-to-list 'mumamo-survive 'mumamo-aspnet-page-language-mode-spec) +(put 'mumamo-aspnet-page-language-mode-spec 'permanent-local t) + +(defconst mumamo-aspnet-language-regex + (rx (0+ (not (any ">"))) + word-start "language" (0+ space) "=" (0+ space) ?\" (submatch (0+ (not (any ?\" ?>)))) ?\" + )) + +(defun mumamo-aspnet-get-page-language-mode-spec () + (or mumamo-aspnet-page-language-mode-spec + (save-excursion + (goto-char (point-min)) + (when (search-forward "<%@ Page") + (let ((case-fold-search t)) + (when (looking-at mumamo-aspnet-language-regex) + (mumamo-aspnet-mode-spec-for-language (match-string 1)))))) + 'fundamental-mode)) + +(defun mumamo-aspnet-get-mode-for-chunk (&optional chunk-type) + (cond ((eq chunk-type 'script) + (mumamo-get-major-mode-substitute + (or (if (looking-at mumamo-aspnet-language-regex) + (mumamo-aspnet-mode-spec-for-language (match-string 1)) + (mumamo-aspnet-get-page-language-mode-spec)) + 'fundamental-mode) + 'fontification)) + ((eq chunk-type 'directive) + 'fundamental-mode) + ;;(t (mumamo-mode-from-modespec + (t (mumamo-get-major-mode-substitute + (mumamo-aspnet-get-page-language-mode-spec) + 'fontification + )))) + + +(defun mumamo-chunk-aspnet(pos min max) + "Find <% ... %>." + (mumamo-find-possible-chunk pos min max + 'mumamo-search-bw-exc-start-aspnet + 'mumamo-search-bw-exc-end-jsp + 'mumamo-search-fw-exc-start-jsp + 'mumamo-search-fw-exc-end-jsp)) + +(defun mumamo-search-bw-exc-start-aspnet(pos min) + ;;(let ((exc-start (mumamo-search-bw-exc-start-str pos min "<%"))) + (let ((exc-start (mumamo-chunk-start-bw-str pos min "<%"))) + (when (and exc-start + (<= exc-start pos)) + (cons exc-start + (mumamo-aspnet-get-mode-for-chunk + (if (eq (char-after exc-start) ?@) + 'directive)))))) + +(defconst mumamo-aspnet-script-tag-start-regex + (rx ""))) + word-start "runat" (0+ space) "=" (0+ space) ?\" "server" ?\" + (0+ (not (any ">"))) + ">" + )) + +(defun mumamo-aspnet-mode-spec-for-language (language) + (let ((language (downcase language))) + (cond ((equal language "c#") 'csharp-mode) + ((equal language "vb") 'vbnet-mode) + (t 'fundamental-mode)))) + +(defun mumamo-search-bw-exc-start-aspnet-script(pos min) + (goto-char (+ pos 7)) + (let ((marker-start (search-backward "...." + (mumamo-find-possible-chunk pos min max + 'mumamo-search-bw-exc-start-aspnet-script + 'mumamo-search-bw-exc-end-inlined-script + 'mumamo-search-fw-exc-start-aspnet-script + 'mumamo-search-fw-exc-end-inlined-script)) + +;; Fix-me: define a multi major mode for asp. Or maybe just drop this +;; file? + +(provide 'mumamo-aspnet) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; mumamo-aspnet.el ends here diff --git a/emacs.d/nxhtml/util/mumamo-fun.el b/emacs.d/nxhtml/util/mumamo-fun.el new file mode 100644 index 0000000..eb3c5c2 --- /dev/null +++ b/emacs.d/nxhtml/util/mumamo-fun.el @@ -0,0 +1,3333 @@ +;;; mumamo-fun.el --- Multi major mode functions +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2008-03-09T01:35:21+0100 Sun +;; Version: 0.51 +;; Last-Updated: 2008-08-04T17:54:29+0200 Mon +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `backquote', `bytecomp', `cl', `flyspell', `ispell', `mumamo', +;; `sgml-mode'. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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 GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Defines some "multi major modes" functions. See mumamo.el for more +;; information. +;; +;;;; Usage: +;; +;; See mumamo.el for how to use the multi major mode functions +;; defined here. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (add-to-list 'load-path default-directory)) +(eval-when-compile (require 'mumamo)) +(eval-when-compile (require 'sgml-mode)) +;;(mumamo-require) + +;;;#autoload +;;(defun mumamo-fun-require ()) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; File wide key bindings + +(defun mumamo-multi-mode-map () + "Return mumamo multi mode keymap." + (symbol-value + (intern-soft (concat (symbol-name mumamo-multi-major-mode) "-map")))) + +;; (defun mumamo-multi-mode-hook-symbol () +;; "Return mumamo multi mode hook symbol." +;; (intern-soft (concat (symbol-name mumamo-multi-major-mode) "-hook"))) + +;;;###autoload +(defun mumamo-define-html-file-wide-keys () + "Define keys in multi major mode keymap for html files." + (let ((map (mumamo-multi-mode-map))) + (define-key map [(control ?c) (control ?h) ?b] 'nxhtml-browse-file) + )) +;; (defun mumamo-add-html-file-wide-keys (hook) +;; (add-hook hook 'mumamo-define-html-file-wide-keys) +;; ) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Chunk search routines for XHTML things + +(defun mumamo-chunk-attr= (pos min max attr= attr=is-regex attr-regex submode) + "This should work similar to `mumamo-find-possible-chunk'. +See `mumamo-chunk-style=' for an example of use. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-chunk-attr=-new pos max attr= attr=is-regex attr-regex submode)) + +(defun mumamo-chunk-attr=-new-fw-exc-fun (pos max) + ;;(msgtrc "(mumamo-chunk-attr=-new-fw-exc-fun %s %s)" pos max) + (save-match-data + (let ((here (point)) + first-dq + next-dq + (this-chunk (mumamo-get-existing-new-chunk-at pos))) + (if this-chunk + (goto-char (overlay-end this-chunk)) + (goto-char (overlay-end mumamo-last-chunk))) + (setq first-dq (search-forward "\"" max t)) + (unless (bobp) + (backward-char) + (condition-case err + (with-syntax-table (standard-syntax-table) + (setq next-dq (scan-sexps (point) 1))) + (error nil))) + (prog1 + next-dq + (goto-char here))))) + +(defun mumamo-chunk-attr=-new-find-borders-fun (start-border end-border dummy) + ;;(setq borders (funcall find-borders-fun start-border end-border exc-mode)) + (save-match-data + (let ((here (point)) + (end2 (when end-border (1- end-border))) + start2) + (goto-char start-border) + (save-match-data + (setq start2 (search-forward "\"" (+ start-border 200) t))) + (goto-char here) + (list start2 end2)))) + +(defun mumamo-chunk-attr=-new (pos + ;;min + max + attr= + attr=is-regex + attr-regex + submode) + ;;(message "\n(mumamo-chunk-attr=-new %s %s %s %s %s %s)" pos max attr= attr=is-regex attr-regex submode) + ;;(mumamo-condition-case err + (condition-case err + (save-match-data + (let ((here (point)) + (next-attr= (progn + ;; fix-me: + (if (not attr=is-regex) + (goto-char (+ pos (length attr=))) + (goto-char pos) + (skip-chars-forward "a-zA-Z=")) + (goto-char pos) + (if attr=is-regex + (re-search-forward attr= max t) + (search-forward attr= max t)))) + next-attr-sure + ;;next-attr= + start start-border + end end-border + exc-mode + borders + exc-start-next + exc-end-next + exc-start-next + exc-end-next + (tries 0) + (min (1- pos)) + look-max + ) + ;; make sure if we have find prev-attr= or not + (unless (eq (char-after) ?\") + (setq next-attr= nil)) + (when next-attr= + (forward-char) + (skip-chars-forward "^\"") + (setq look-max (+ (point) 2))) + (while (and next-attr= + (< min (point)) + (not next-attr-sure) + (< tries 5)) + ;;(msgtrc "attr=-new: min=%s, point=%s" min (point)) + (setq tries (1+ tries)) + ;;(if (not (re-search-backward "<[^?]" (- min 300) t)) + (if (not (re-search-backward "<[^?]\\|\?>" (- min 300) t)) + (setq next-attr= nil) + ;;(if (looking-at attr-regex) + (if (let ((here (point))) + (prog1 + (re-search-forward attr-regex look-max t) + (goto-char here))) + ;;(if (mumamo-end-in-code (point) next-attr= 'php-mode) + (setq next-attr-sure 'found) + (unless (bobp) + (backward-char) + ;;(msgtrc "attr=-new 1: min=%s, point=%s" min (point)) + (setq next-attr= (if attr=is-regex + (re-search-backward attr= (- min 300) t) + (search-backward attr= (- min 300) t))))))) + (unless next-attr-sure (setq next-attr= nil)) + + + ;; find prev change and if inside style= the next change + (when next-attr= + (setq exc-start-next (match-beginning 1)) + (setq exc-end-next (match-end 2)) + (when (>= exc-start-next pos) + (if (> pos exc-end-next) + (progn + (setq start (+ (match-end 2) 1)) + ;;(setq start-border (+ (match-end 2) 2)) + ) + (setq exc-mode submode) + (setq start (match-beginning 1)) + (setq start-border (match-beginning 2)) + (setq end (1+ (match-end 2))) + (setq end-border (1- end))) + )) + ;; find next change + (unless end + (if start + (goto-char start) + (goto-char pos) + (search-backward "<" min t)) + ;;(msgtrc "attr=-new 2: min=%s, point=%s" min (point)) + (setq next-attr= (if attr=is-regex + (re-search-forward attr= max t) + (search-forward attr= max t))) + (when (and next-attr= + (search-backward "<" min t)) + (when (looking-at attr-regex) + (setq end (match-beginning 1))))) + (when start (assert (>= start pos) t)) + (when end (assert (<= pos end) t)) + ;;(message "start-border=%s end-border=%s" start-border end-border) + (when (or start-border end-border) + (setq borders (list start-border end-border nil))) + ;; (message "mumamo-chunk-attr=-new: %s" + ;; (list start + ;; end + ;; exc-mode + ;; borders + ;; nil ;; parseable-by + ;; 'mumamo-chunk-attr=-new-fw-exc-fun ;; fw-exc-fun + ;; 'mumamo-chunk-attr=-new-find-borders-fun ;; find-borders-fun + ;; )) + (goto-char here) + (setq end nil) + (when (or start end) + (list start + end + exc-mode + borders + nil ;; parseable-by + 'mumamo-chunk-attr=-new-fw-exc-fun ;; fw-exc-fun + 'mumamo-chunk-attr=-new-find-borders-fun ;; find-borders-fun + )))) + (error (mumamo-display-error 'mumamo-chunk-attr=-new "%s" (error-message-string err))) + )) + +;;;; xml pi + +(defvar mumamo-xml-pi-mode-alist + '(("php" . php-mode) + ("python" . python-mode)) + "Alist used by `mumamo-chunk-xml-pi' to get exception mode." ) + +;; Fix-me: make it possible to make the borders part of the php chunk +;; so that parsing of them by nxml may be skipped. Or, rather if the +;; borders are not part of the chunk then assume nxml can not parse +;; the chunk and the borders. +;; (defun mumamo-search-bw-exc-start-xml-pi-1 (pos min lt-chars) +;; "Helper for `mumamo-chunk-xml-pi'. +;; POS is where to start search and MIN is where to stop. +;; LT-CHARS is just at pos is end of 1000 pos) +;;; (assert (and (= (char-after pos) ??) +;;; (= (char-after (1+ pos)) ?>))) + (save-excursion + (save-restriction + (widen) + (save-match-data + (when (search-backward "<" (- pos 150) t) + (when (looking-at (rx line-start "<\?xml" (1+ space))) + (mumamo-msgfntfy "mumamo-xml-pi-end-is-xml-end %s => t" pos) + t))))))) + +;; (defun mumamo-search-bw-exc-end-xml-pi (pos min) +;; "Helper for `mumamo-chunk-xml-pi'. +;; POS is where to start search and MIN is where to stop." +;; ;; Fix me: merge xml header +;; (mumamo-msgfntfy "mumamo-search-bw-exc-end-xml-pi %s %s" pos min) +;; ;;(let ((end-pos (mumamo-chunk-end-bw-str pos min "?>"))) +;; (let ((end-pos (mumamo-chunk-end-bw-str-inc pos min "?>"))) +;; (mumamo-msgfntfy " end-pos=%s" end-pos) +;; (when end-pos +;; (unless (or (mumamo-xml-pi-end-is-xml-end end-pos) +;; (= (save-restriction +;; (widen) +;; (char-after (- end-pos 1))) +;; ?<)) +;; (mumamo-msgfntfy " returning end-pos") +;; end-pos)))) + +(defun mumamo-search-fw-exc-end-xml-pi (pos max) + "Helper for `mumamo-chunk-xml-pi'. +POS is where to start search and MAX is where to stop." + ;; Fix me: merge xml header + ;;(let ((end-pos (mumamo-chunk-end-fw-str pos max "?>"))) + (save-match-data + (let ((end-pos (mumamo-chunk-end-fw-str-inc pos max "?>"))) + (when end-pos + (unless (mumamo-xml-pi-end-is-xml-end end-pos) + end-pos))))) + +(defun mumamo-search-fw-exc-start-xml-pi-1 (pos max lt-chars) + "Helper for `mumamo-chunk-xml-pi'. +POS is where to start search and MAX is where to stop. + +Used in `mumamo-search-fw-exc-start-xml-pi'. For an explanation +of LT-CHARS see `mumamo-search-bw-exc-start-xml-pi-1'." + (goto-char pos) + (skip-chars-backward "a-zA-Z") + ;;(let ((end-out (mumamo-chunk-start-fw-str (point) max lt-chars))) + (let ((end-out (mumamo-chunk-start-fw-str-inc (point) max lt-chars)) + spec + exc-mode + hit) + (when (looking-at "xml") + (if t ;(= 1 pos) + (setq end-out (mumamo-chunk-start-fw-str-inc (1+ (point)) max lt-chars)) + (setq end-out nil))) + (when end-out + ;; Get end-out: + (if (looking-at (rx (0+ (any "a-z")))) + (progn + ;;(setq end-out (match-end 0)) + (setq end-out (- (match-beginning 0) 2)) + (setq spec (match-string-no-properties 0)) + (setq exc-mode (assoc spec mumamo-xml-pi-mode-alist)) + (if exc-mode + (setq exc-mode (cdr exc-mode)) + (setq exc-mode 'php-mode)) + (setq end-out (list end-out exc-mode nil)) + ) + (setq end-out nil)) + end-out))) + +(defun mumamo-search-fw-exc-start-xml-pi-old (pos max) + "Helper for `mumamo-chunk-xml-pi'. +POS is where to start search and MAX is where to stop." + (mumamo-search-fw-exc-start-xml-pi-1 pos max "" can be handled. +;; +;; Fix-me: Maybe generalize for other values than ") + (here (point))) + (if (and inc) ;; exc-mode) + (progn + (when start + ;;(setq start-border (+ start (length begin-mark))) + (goto-char (+ start (length begin-mark))) + (skip-chars-forward "=a-zA-Z") + (setq start-border (point)) + ) + (when end + (setq end-border + (- end (length end-mark))))) + (if (and (not inc) (not exc-mode)) + (progn + (when start + (setq start-border + (+ start (length end-mark)))) + (when end + (setq end-border (- end (length begin-mark))) + ;;(goto-char end) + ;;(skip-chars-forward "=a-zA-Z") + ;;(setq end-border (point)) + )))) + (goto-char here) + (when (or start-border end-border) + (list start-border end-border)))) + +(defun mumamo-chunk-xml-pi (pos min max) + "Find process instruction, . Return range and wanted mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-xml-pi + ;; 'mumamo-search-bw-exc-end-xml-pi + ;; 'mumamo-search-fw-exc-start-xml-pi-old + ;; 'mumamo-search-fw-exc-end-xml-pi + ;; 'mumamo-find-borders-xml-pi) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-xml-pi-new + 'mumamo-search-fw-exc-end-xml-pi + 'mumamo-find-borders-xml-pi)) + + +;;;; ")) + +;; (defun mumamo-search-fw-exc-start-inlined-style-old (pos max) +;; "Helper for `mumamo-chunk-inlined-style'. +;; POS is where to start search and MAX is where to stop." +;; (goto-char (1+ pos)) +;; (skip-chars-backward "^<") +;; ;; Handle "))) + +;; (defun mumamo-chunk-inlined-style-old (pos min max) +;; "Find . Return range and 'css-mode. +;; See `mumamo-find-possible-chunk' for POS, MIN and MAX." +;; (mumamo-find-possible-chunk pos min max +;; 'mumamo-search-bw-exc-start-inlined-style +;; 'mumamo-search-bw-exc-end-inlined-style +;; 'mumamo-search-fw-exc-start-inlined-style-old +;; 'mumamo-search-fw-exc-end-inlined-style)) + +(defun mumamo-search-fw-exc-start-inlined-style (pos max) + "Helper for `mumamo-chunk-inlined-style'. +POS is where to start search and MAX is where to stop." + (goto-char (1+ pos)) + (skip-chars-backward "^<") + ;; Handle .... Return range and 'css-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-inlined-style + 'mumamo-search-fw-exc-end-inlined-style)) + +;;;; ")) + +;; (defun mumamo-search-fw-exc-start-inlined-script-old (pos max) +;; "Helper for `mumamo-chunk-inlined-script'. +;; POS is where to start search and MAX is where to stop." +;; (goto-char (1+ pos)) +;; (skip-chars-backward "^<") +;; ;; Handle "))) + +;; (defun mumamo-chunk-inlined-script-old (pos min max) +;; "Find . Return range and 'javascript-mode. +;; See `mumamo-find-possible-chunk' for POS, MIN and MAX." +;; (mumamo-find-possible-chunk pos min max +;; 'mumamo-search-bw-exc-start-inlined-script +;; 'mumamo-search-bw-exc-end-inlined-script +;; 'mumamo-search-fw-exc-start-inlined-script-old +;; 'mumamo-search-fw-exc-end-inlined-script)) + +(defun mumamo-search-fw-exc-start-inlined-script (pos max) + "Helper for `mumamo-chunk-inlined-script'. +POS is where to start search and MAX is where to stop." + (goto-char (1+ pos)) + (skip-chars-backward "^<") + ;; Handle .... Return range and 'javascript-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-inlined-script + 'mumamo-search-fw-exc-end-inlined-script)) + +;;;; on[a-z]+=\"javascript:" + +(defconst mumamo-onjs=-attr= + (rx + ;;"on[a-z]+=" + (or "onclick" "ondblclick" "onmousedown" "onmousemove" "onmouseout" "onmouseover" "onmouseup" "onkeydown" "onkeypress" "onkeyup") + "=")) + +(defconst mumamo-onjs=-attr-regex + (rx point + (or "<" "?>") + (* (not (any ">"))) + space + (submatch + ;;"on" (1+ (any "a-za-z")) + (or "onclick" "ondblclick" "onmousedown" "onmousemove" "onmouseout" "onmouseover" "onmouseup" "onkeydown" "onkeypress" "onkeyup") + "=") + (0+ space) + ?\" + (submatch + (opt "javascript:") + (0+ + (not (any "\"")))) + )) + +(defun mumamo-chunk-onjs=(pos min max) + "Find javascript on...=\"...\". Return range and 'javascript-mode." + (mumamo-chunk-attr= pos min max mumamo-onjs=-attr= t mumamo-onjs=-attr-regex + 'javascript-mode)) + +;;;; py:somthing=\"python\" + +(defconst mumamo-py:=-attr= "py:[a-z]+=") + +(defconst mumamo-py:=-attr-regex + (rx point + (or "<" "?>") + (* (not (any ">"))) + space + (submatch + "py:" (1+ (any "a-za-z")) + "=") + (0+ space) + ?\" + (submatch + (0+ + (not (any "\"")))) + )) + +(defun mumamo-chunk-py:=(pos min max) + "Find python py:...=\"...\". Return range and 'python-mode." + (mumamo-chunk-attr= pos min max mumamo-py:=-attr= t mumamo-py:=-attr-regex + 'python-mode)) + +(defun mumamo-chunk-py:match (pos min max) + (save-match-data + (let ((here (point)) + (py:match (progn + (goto-char pos) + (re-search-forward (rx "py:match" + (1+ space) + (0+ (not (any ">"))) + word-start + (submatch "path=") + (0+ space) + ?\" + (submatch + (0+ + (not (any "\""))))) + max t))) + start end borders + ) + (when py:match + (setq start (match-beginning 1)) + (setq end (match-end 2)) + (setq borders (list (match-end 1) (1- end))) + ) + (goto-char here) + (when start + (list start + end + 'python-mode + borders + nil ;; parseable-by + 'mumamo-chunk-attr=-new-fw-exc-fun ;; fw-exc-fun + 'mumamo-chunk-attr=-new-find-borders-fun ;; find-borders-fun + ))))) + +;;;; style= + +(defconst mumamo-style=start-regex + (rx "<" + (0+ (not (any ">"))) + space + (submatch "style=") + (0+ space) + ?\" + (submatch + (0+ + (not (any "\"")))) + )) + +(defun mumamo-chunk-style=(pos min max) + "Find style=\"...\". Return range and 'css-mode." + (mumamo-chunk-attr= pos min max "style=" nil mumamo-style=start-regex + 'css-mode)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; HTML w html-mode + +(put 'mumamo-alt-php-tags-mode 'permanent-local t) +(define-minor-mode mumamo-alt-php-tags-mode + "Minor mode for using '(?php' instead of ' in strings. + +There is no reason to use this minor mode unless you want XML +validation and/or completion in your php file. If you do not +want that then you can simply use a multi major mode based on +`html-mode' instead of `nxml-mode'/`nxhtml-mode'. Or, of course, +just `php-mode' if there is no html code in the file." + :lighter "" nil t) + (replace-match "?)")) + (goto-char here)))) + (save-restriction + (let ((here (point))) + (widen) + (goto-char (point-min)) + (while (search-forward "(?php" nil t) + (replace-match "")) + (goto-char here))) + (remove-hook 'write-contents-functions 'mumamo-alt-php-write-contents t))) + +(defun mumamo-chunk-alt-php (pos min max) + "Find (?php ... ?), return range and `php-mode'. +Workaround for the problem that I can not tame `nxml-mode' to recognize ")) + (basic-save-buffer-1) + (signal 'mumamo-error-ind-0 nil))) + (mumamo-error-ind-0))) + (set-buffer-modified-p nil)) + (goto-char here)) + ;; saved, return t + t) + +;;;###autoload +(define-mumamo-multi-major-mode nxml-mumamo-mode + "Turn on multiple major modes for (X)HTML with main mode `nxml-mode'. +This covers inlined style and javascript and PHP. + +See also `mumamo-alt-php-tags-mode'." + ("nXml Family" nxml-mode + (mumamo-chunk-xml-pi + mumamo-chunk-alt-php + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) +(add-hook 'nxml-mumamo-mode-hook 'mumamo-define-html-file-wide-keys) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Mason (not ready) +;; http://www.masonhq.com/docs/manual/Devel.html#examples_and_recommended_usage + +(defun mumamo-chunk-mason-perl-line (pos min max) + (mumamo-whole-line-chunk pos min max "%" 'perl-mode)) + +(defun mumamo-chunk-mason-perl-single (pos min max) + (mumamo-quick-static-chunk pos min max "<% " " %>" t 'perl-mode t)) + +(defun mumamo-chunk-mason-perl-block (pos min max) + (mumamo-quick-static-chunk pos min max "<%perl>" "" t 'perl-mode t)) + +(defun mumamo-chunk-mason-perl-init (pos min max) + (mumamo-quick-static-chunk pos min max "<%init>" "" t 'perl-mode t)) + +(defun mumamo-chunk-mason-perl-once (pos min max) + (mumamo-quick-static-chunk pos min max "<%once>" "" t 'perl-mode t)) + +(defun mumamo-chunk-mason-perl-cleanup (pos min max) + (mumamo-quick-static-chunk pos min max "<%cleanup>" "" t 'perl-mode t)) + +(defun mumamo-chunk-mason-perl-shared (pos min max) + (mumamo-quick-static-chunk pos min max "<%shared>" "" t 'perl-mode t)) + +(defun mumamo-chunk-mason-simple-comp (pos min max) + (mumamo-quick-static-chunk pos min max "<& " " &>" t 'text-mode t)) + +(defun mumamo-chunk-mason-args (pos min max) + ;; Fix-me: perl-mode is maybe not the best here? + (mumamo-quick-static-chunk pos min max "<%args>" "" t 'perl-mode t)) + +(defun mumamo-chunk-mason-doc (pos min max) + (mumamo-quick-static-chunk pos min max "<%doc>" "" t 'mumamo-comment-mode t)) + +(defun mumamo-chunk-mason-text (pos min max) + (mumamo-quick-static-chunk pos min max "<%text>" "" t 'text-mode t)) + +;; component calls with content + +;; (defun mumamo-chunk-mason-compcont-bw-exc-start-fun (pos min) +;; (let ((exc-start (mumamo-chunk-start-bw-str-inc pos min "<&| "))) +;; (and exc-start +;; (<= exc-start pos) +;; (cons exc-start 'html-mode)))) + +;; (defun mumamo-chunk-mason-compcont-fw-exc-start-fun-old (pos max) +;; (mumamo-chunk-start-fw-str-inc pos max "<&| ")) + +(defun mumamo-chunk-mason-compcont-fw-exc-end-fun (pos max) + (mumamo-chunk-end-fw-str-inc pos max "")) + +(defun mumamo-chunk-mason-compcont-find-borders-fun (start end dummy) + (when dummy + (list + (when start + (save-match-data + (let ((here (point)) + ret) + (goto-char start) + (when (re-search-forward "[^>]* &>" end t) + (setq ret (point)) + (goto-char here) + ret)) + )) + (when end (- end 4)) + dummy))) + +;; (defun mumamo-chunk-mason-compcont-old (pos min max) +;; (mumamo-find-possible-chunk-new pos +;; max +;; 'mumamo-chunk-mason-compcont-bw-exc-start-fun +;; 'mumamo-chunk-mason-compcont-fw-exc-start-fun-old +;; 'mumamo-chunk-mason-compcont-fw-exc-end-fun +;; 'mumamo-chunk-mason-compcont-find-borders-fun)) + +(defun mumamo-chunk-mason-compcont-fw-exc-start-fun (pos max) + (let ((where (mumamo-chunk-start-fw-str-inc pos max "<&| "))) + (when where + (list where 'html-mode nil)))) + +(defun mumamo-chunk-mason-compcont (pos min max) + (mumamo-possible-chunk-forward pos max + 'mumamo-chunk-mason-compcont-fw-exc-start-fun + 'mumamo-chunk-mason-compcont-fw-exc-end-fun + 'mumamo-chunk-mason-compcont-find-borders-fun)) + +;;;###autoload +(define-mumamo-multi-major-mode mason-html-mumamo-mode + "Turn on multiple major modes for Mason using main mode `html-mode'. +This covers inlined style and javascript." + ("Mason html Family" html-mode + ( + mumamo-chunk-mason-perl-line + mumamo-chunk-mason-perl-single + mumamo-chunk-mason-perl-block + mumamo-chunk-mason-perl-init + mumamo-chunk-mason-perl-once + mumamo-chunk-mason-perl-cleanup + mumamo-chunk-mason-perl-shared + mumamo-chunk-mason-simple-comp + mumamo-chunk-mason-compcont + mumamo-chunk-mason-args + mumamo-chunk-mason-doc + mumamo-chunk-mason-text + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) +(add-hook 'mason-html-mumamo-mode-hook 'mumamo-define-html-file-wide-keys) +(mumamo-inherit-sub-chunk-family-locally 'mason-html-mumamo-mode 'mason-html-mumamo-mode) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Embperl + +(defun mumamo-chunk-embperl-<- (pos min max) + "Find [- ... -], return range and `perl-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "[-" "-]" t 'perl-mode t)) + +(defun mumamo-chunk-embperl-<+ (pos min max) + "Find [+ ... +], return range and `perl-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "[+" "+]" t 'perl-mode nil)) + +(defun mumamo-chunk-embperl-... and <% ... %>. + +(defun mumamo-chunk-ssjs-% (pos min max) + "Find <% ... %>. Return range and 'javascript-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "<%" "%>" t 'javascript-mode t)) + +(defconst mumamo-ssjs-tag-start-regex + (rx ""))) + "runat" + (0+ space) + "=" + (0+ space) + ?\" + ;;(or "text" "application") + ;;"/" + ;;(or "javascript" "ecmascript") + (or "server" "both" "server-proxy") + ?\" + (0+ (not (any ">"))) + ">" + ;; FIX-ME: Commented out because of bug in Emacs + ;; + ;;(optional (0+ space) ".... Return range and 'javascript-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-inlined-ssjs + ;; 'mumamo-search-bw-exc-end-inlined-script + ;; 'mumamo-search-fw-exc-start-inlined-ssjs-old + ;; 'mumamo-search-fw-exc-end-inlined-script) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-inlined-ssjs + 'mumamo-search-fw-exc-end-inlined-script)) + +;;;###autoload +(define-mumamo-multi-major-mode ssjs-html-mumamo-mode + "Turn on multiple major modes for SSJS with main mode `html-mode'. +This covers inlined style and javascript." + ("HTML Family" html-mode + (mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-inlined-ssjs + mumamo-chunk-ssjs-% + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) +(add-hook 'html-mumamo-mode-hook 'mumamo-define-html-file-wide-keys) +(mumamo-inherit-sub-chunk-family 'ssjs-html-mumamo-mode) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; gsp + +(defun mumamo-chunk-gsp (pos min max) + "Find <% ... %>. Return range and 'groovy-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "<%" "%>" t 'groovy-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode gsp-html-mumamo-mode + "Turn on multiple major modes for GSP with main mode `html-mode'. +This also covers inlined style and javascript." + ("GSP HTML Family" html-mode + (mumamo-chunk-gsp + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; jsp - Java Server Pages + +(defun mumamo-chunk-jsp (pos min max) + "Find <% ... %>. Return range and 'java-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "<%" "%>" t 'java-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode jsp-html-mumamo-mode + "Turn on multiple major modes for JSP with main mode `html-mode'. +This also covers inlined style and javascript." + ("JSP HTML Family" html-mode + (mumamo-chunk-jsp + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; eruby + +;; Fix-me: Maybe take care of <%= and <%- and -%>, but first ask the +;; ruby people if this is worth doing. +;; +;; See also http://wiki.rubyonrails.org/rails/pages/UnderstandingViews +(defun mumamo-chunk-eruby (pos min max) + "Find <% ... %>. Return range and 'ruby-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (let ((chunk (mumamo-quick-static-chunk pos min max "<%" "%>" t 'ruby-mode t))) + (when chunk + ;; Put indentation type on 'mumamo-next-indent on the chunk: + ;; Fix-me: use this! + (setcdr (last chunk) '(mumamo-template-indentor)) + chunk))) + +(defun mumamo-chunk-eruby-quoted (pos min max) + "Find \"<%= ... %>\". Return range and 'ruby-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX. + +This is a workaround for problems with strings." + (let ((chunk (mumamo-quick-static-chunk pos min max "\"<%=" "%>\"" t 'ruby-mode t))) + (when chunk + ;; Put indentation type on 'mumamo-next-indent on the chunk: + ;; Fix-me: use this! + (setcdr (last chunk) '(mumamo-template-indentor)) + chunk))) + +(defun mumamo-chunk-eruby-comment (pos min max) + "Find <%# ... %>. Return range and 'ruby-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX. + +This is needed since otherwise the end marker is thought to be +part of a comment." + (mumamo-quick-static-chunk pos min max "<%#" "%>" t 'mumamo-comment-mode t)) + +;; (defun mumamo-search-bw-exc-start-ruby (pos min) +;; "Helper for `mumamo-chunk-ruby'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min "<%"))) +;; (when (and exc-start +;; (<= exc-start pos)) +;; (cons exc-start 'ruby-mode)))) + +;;;###autoload +(define-mumamo-multi-major-mode eruby-mumamo-mode + "Turn on multiple major mode for eRuby with unspecified main mode. +Current major-mode will be used as the main major mode." + ("eRuby Family" nil + (mumamo-chunk-eruby-comment + mumamo-chunk-eruby + ))) + +;;;###autoload +(define-mumamo-multi-major-mode eruby-html-mumamo-mode + "Turn on multiple major modes for eRuby with main mode `html-mode'. +This also covers inlined style and javascript." + ("eRuby Html Family" html-mode + ( + mumamo-chunk-eruby-comment + mumamo-chunk-eruby + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + +;;;###autoload +(define-mumamo-multi-major-mode eruby-javascript-mumamo-mode + "Turn on multiple major modes for eRuby with main mode `javascript-mode'." + ("eRuby Html Family" javascript-mode + ( + mumamo-chunk-eruby-comment + mumamo-chunk-eruby-quoted + mumamo-chunk-eruby + ;;mumamo-chunk-inlined-style + ;;mumamo-chunk-inlined-script + ;;mumamo-chunk-style= + ;;mumamo-chunk-onjs= + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; heredoc + +(defcustom mumamo-heredoc-modes + '( + ("HTML" html-mode) + ("CSS" css-mode) + ("JAVASCRIPT" javascript-mode) + ("JAVA" java-mode) + ("GROOVY" groovy-mode) + ("SQL" sql-mode) + ) + "Matches for heredoc modes. +The entries in this list have the form + + (REGEXP MAJOR-MODE-SPEC) + +where REGEXP is a regular expression that should match the +heredoc marker line and MAJOR-MODE-SPEC is the major mode spec to +use in the heredoc part. + +The major mode spec is translated to a major mode using +`mumamo-major-mode-from-modespec'." + :type '(repeat + (list + regexp + (function :tag "Major mode"))) + :group 'mumamo-modes) + +(defun mumamo-mode-for-heredoc (marker) + "Return major mode associated with MARKER. +Use first match in `mumamo-heredoc-modes'. +If no match use `text-mode'." + (let ((mode (catch 'mode + (save-match-data + (dolist (rec mumamo-heredoc-modes) + (let ((regexp (nth 0 rec)) + (mode (nth 1 rec))) + (when (string-match regexp marker) + (throw 'mode mode)))))))) + (if mode + (mumamo-major-mode-from-modespec mode) + 'text-mode))) + +(defun mumamo-chunk-heredoc (pos min max lang) + "This should work similar to `mumamo-find-possible-chunk'. +POS, MIN and MAX have the same meaning as there. + +LANG is the programming language. +Supported values are 'perl." + ;; Fix-me: LANG + ;; Fix-me: use mumamo-end-in-code + (mumamo-condition-case err + (let ((old-point (point))) + (goto-char pos) + (beginning-of-line) + (let (next-<< + (want-<< t) + heredoc-mark + end-mark-len + heredoc-line + delimiter + skipped + (skip-b "") + start-inner + end + exc-mode + fw-exc-fun + border-fun + allow-code-after + start-outer + ps + ) + (goto-char pos) + (beginning-of-line) + (case lang + ('sh + (setq allow-code-after t) + (while want-<< + (setq next-<< (search-forward "<<" max t)) + (if (not next-<<) + (setq want-<< nil) ;; give up + ;; Check inside string or comment. + (setq ps (parse-partial-sexp (line-beginning-position) (point))) + (unless (or (nth 3 ps) (nth 4 ps)) + (setq want-<< nil)))) + (when next-<< + (setq start-outer (- (point) 2)) + (when (= (char-after) ?-) + (setq skip-b "\t*") + (unless (eolp) (forward-char))) + ;; fix-me: space + (setq skipped (skip-chars-forward " \t")) + (when (memq (char-after) '(?\" ?\')) + (setq delimiter (list (char-after)))) + (if (and (> skipped 0) (not delimiter)) + (setq heredoc-mark "") + (when (looking-at (rx-to-string + `(and (regexp ,(if delimiter + (concat delimiter "\\([^\n<>;]+\\)" delimiter) + "\\([^ \t\n<>;]+\\)")) + (or blank line-end)))) + (setq heredoc-mark (buffer-substring-no-properties + (match-beginning 1) + (match-end 1))))) + (when heredoc-mark + (setq heredoc-line (buffer-substring-no-properties (point-at-bol) (point-at-eol))) + (setq start-inner (1+ (point-at-eol))) + (setq end-mark-len (length heredoc-mark)) + ))) + ('w32-ps (error "No support for windows power shell yet")) + ('php + (while want-<< + (setq next-<< (search-forward "<<<" max t)) + ;; Check inside string or comment. + (if (not next-<<) + (setq want-<< nil) ;; give up + (setq ps (parse-partial-sexp (line-beginning-position) (- (point) 0))) + (unless (or (nth 3 ps) (nth 4 ps)) + (setq want-<< nil)))) + (when next-<< + (setq start-outer (- (point) 3)) + (skip-chars-forward " \t") + (when (looking-at (concat "\\([^\n;]*\\)[[:blank:]]*\n")) + (setq heredoc-mark (buffer-substring-no-properties + (match-beginning 1) + (match-end 1))) + (setq heredoc-line (buffer-substring-no-properties (point-at-bol) (point-at-eol))) + ;; fix-me: nowdoc + (when (and (= ?\' (string-to-char heredoc-mark)) + (= ?\' (string-to-char (substring heredoc-mark (1- (length heredoc-mark)))))) + (setq heredoc-mark (substring heredoc-mark 1 (- (length heredoc-mark) 1)))) + (setq end-mark-len (1+ (length heredoc-mark))) + (setq start-inner (match-end 0))))) + ('perl + (setq allow-code-after t) + (while want-<< + (setq next-<< (search-forward "<<" max t)) + (if (not next-<<) + (setq want-<< nil) ;; give up + ;; Check inside string or comment. + (setq ps (parse-partial-sexp (line-beginning-position) (point))) + (unless (or (nth 3 ps) (nth 4 ps)) + (setq want-<< nil)))) + (when next-<< + (setq start-outer (- (point) 2)) + ;; fix-me: space + (setq skipped (skip-chars-forward " \t")) + (when (memq (char-after) '(?\" ?\')) + (setq delimiter (list (char-after)))) + (if (and (> skipped 0) (not delimiter)) + (setq heredoc-mark "") ;; blank line + (when (looking-at (rx-to-string + `(and (regexp ,(if delimiter + (concat delimiter "\\([^\n;]*\\)" delimiter) + "\\([^ \t\n<>;]+\\)")) + (or blank ";")))) + (setq heredoc-mark (buffer-substring-no-properties + (match-beginning 1) + (match-end 1))))) + (when heredoc-mark + (setq heredoc-line (buffer-substring-no-properties (point-at-bol) (point-at-eol))) + ;;(setq start-inner (1+ (match-end 0))) + (setq start-inner (1+ (point-at-eol))) + (setq end-mark-len (length heredoc-mark)) + ))) + ('python + (unless (eobp) (forward-char)) + (while want-<< + (setq next-<< (re-search-forward "\"\"\"\\|'''" max t)) + (setq start-outer (- (point) 3)) + (if (not next-<<) + (setq want-<< nil) ;; give up + ;; Check inside string or comment. + (setq ps (parse-partial-sexp (line-beginning-position) (- (point) 3))) + (unless (or (nth 3 ps) (nth 4 ps)) + (setq want-<< nil))))) + ('ruby + (while want-<< + (setq next-<< (search-forward "<<" max t)) + (if (not next-<<) + (setq want-<< nil) ;; give up + ;; Check inside string or comment. + (setq ps (parse-partial-sexp (line-beginning-position) (point))) + (unless (or (nth 3 ps) (nth 4 ps)) + (setq want-<< nil)))) + (when next-<< + (setq start-outer (- (point) 2)) + (when (= (char-after) ?-) + (setq skip-b "[ \t]*") + (forward-char)) + (when (looking-at (concat "[^\n[:blank:]]*")) + (setq heredoc-mark (buffer-substring-no-properties + (match-beginning 0) + (match-end 0))) + (setq end-mark-len (length heredoc-mark)) + (setq heredoc-line (buffer-substring-no-properties (point-at-bol) (point-at-eol))) + (setq start-inner (match-end 0))))) + (t (error "next-<< not implemented for lang %s" lang))) + (when start-inner (assert (<= pos start-inner) t)) + (goto-char old-point) + (when (or start-inner end) + (let ((endmark-regexp + (case lang + ('sh (concat "^" skip-b heredoc-mark "$")) + ('php (concat "^" heredoc-mark ";?$")) + ('perl (concat "^" heredoc-mark "$")) + ('python (concat "^" heredoc-mark "[[:space:]]*")) + ('ruby (concat "^" skip-b heredoc-mark "$")) + (t (error "mark-regexp not implemented for %s" lang))))) + ;; Fix-me: rename start-inner <=> start-outer... + (setq border-fun `(lambda (start end exc-mode) + ;; Fix-me: use lengths... + (list + (if ,allow-code-after nil (+ start (- ,start-inner ,start-outer 1))) + (when end (- end ,end-mark-len))))) + (setq fw-exc-fun `(lambda (pos max) + (save-match-data + (let ((here (point))) + (goto-char pos) + (prog1 + (when (re-search-forward ,endmark-regexp max t) + (- (point) 1 ,(length heredoc-mark)) + (- (point) 0) + ) + (goto-char here))))))) + (setq exc-mode (mumamo-mode-for-heredoc heredoc-line)) + (list start-inner end exc-mode nil nil fw-exc-fun nil) + ;; Fix me: Add overriding for inner chunks (see + ;; http://www.emacswiki.org/emacs/NxhtmlMode#toc13). Maybe + ;; make fw-exc-fun a list (or a cons, since overriding is + ;; probably all that I want to add)? And make the + ;; corresponding chunk property a list too? + ;;(list start-outer end exc-mode (list start-inner end) nil fw-exc-fun border-fun 'heredoc) + (list (if allow-code-after start-inner start-outer) + end exc-mode (list start-inner end) nil fw-exc-fun border-fun 'heredoc) + ))) + (error (mumamo-display-error 'mumamo-chunk-heredoc + "%s" (error-message-string err))))) + + +;;;; Unix style sh heredoc + +(defun mumamo-chunk-sh-heredoc (pos min max) + "Find sh here docs. +See `mumamo-find-possible-chunk' for POS, MIN +and MAX." + (let ((r (mumamo-chunk-heredoc pos min max 'sh))) + r)) + +;;;###autoload +(define-mumamo-multi-major-mode sh-heredoc-mumamo-mode + "Turn on multiple major modes for sh heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("SH HereDoc" sh-mode + (mumamo-chunk-sh-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'sh-heredoc-mumamo-mode) + + +;;;; PHP heredoc + +(defun mumamo-chunk-php-heredoc (pos min max) + "Find PHP here docs. +See `mumamo-find-possible-chunk' for POS, MIN +and MAX." + (let ((r (mumamo-chunk-heredoc pos min max 'php))) + r)) + +;;;###autoload +(define-mumamo-multi-major-mode php-heredoc-mumamo-mode + "Turn on multiple major modes for PHP heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("PHP HereDoc" php-mode + (mumamo-chunk-php-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'php-heredoc-mumamo-mode) +(mumamo-inherit-sub-chunk-family-locally 'php-heredoc-mumamo-mode 'html-mumamo-mode) + + +;;;; Perl heredoc + +(defun mumamo-chunk-perl-heredoc (pos min max) + "Find perl here docs. +See `mumamo-find-possible-chunk' for POS, MIN +and MAX." + (let ((r (mumamo-chunk-heredoc pos min max 'perl))) + r)) + +;;;###autoload +(define-mumamo-multi-major-mode perl-heredoc-mumamo-mode + "Turn on multiple major modes for Perl heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("Perl HereDoc" perl-mode + (mumamo-chunk-perl-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'perl-heredoc-mumamo-mode) + +;;;###autoload +(define-mumamo-multi-major-mode cperl-heredoc-mumamo-mode + "Turn on multiple major modes for Perl heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("Perl HereDoc" cperl-mode + (mumamo-chunk-perl-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'cperl-heredoc-mumamo-mode) + + +;;;; Python heredoc + +(defun mumamo-chunk-python-heredoc (pos min max) + "Find python here docs. +See `mumamo-find-possible-chunk' for POS, MIN +and MAX." + (let ((r (mumamo-chunk-heredoc pos min max 'python))) + r)) + +;;;###autoload +(define-mumamo-multi-major-mode python-heredoc-mumamo-mode + "Turn on multiple major modes for Perl heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("Python HereDoc" python-mode + (mumamo-chunk-python-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'python-heredoc-mumamo-mode) + + +;;;; Ruby heredoc + +(defun mumamo-chunk-ruby-heredoc (pos min max) + "Find Ruby here docs. +See `mumamo-find-possible-chunk' for POS, MIN +and MAX." + (let ((r (mumamo-chunk-heredoc pos min max 'ruby))) + r)) + +;;;###autoload +(define-mumamo-multi-major-mode ruby-heredoc-mumamo-mode + "Turn on multiple major modes for Ruby heredoc document. +See `mumamo-heredoc-modes' for how to specify heredoc major modes." + ("Ruby HereDoc" ruby-mode + (mumamo-chunk-ruby-heredoc + ))) +(mumamo-inherit-sub-chunk-family 'ruby-heredoc-mumamo-mode) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Tex meta + +;; (defun mumamo-search-bw-textext-start (pos min) +;; "Helper for `mumamo-chunk-textext'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min "textext(\"")) +;; (exc-mode 'plain-tex-mode)) +;; (when exc-start +;; (when (<= exc-start pos) +;; (cons exc-start exc-mode))))) + +(defconst mumamo-textext-end-regex + (rx "textext(" + (0+ + (0+ (not (any "\"()"))) + ?\" + (0+ (not (any "\""))) + ?\" + ) + (0+ (not (any "\"()"))) + ")")) + +(defun mumamo-textext-test-is-end (pos) + "Helper for `mumamo-chunk-textext'. +Return POS if POS is at the end of textext chunk." + (when pos + (let ((here (point)) + hit) + (goto-char (+ 2 pos)) + (when (looking-back mumamo-textext-end-regex) + (setq hit t)) + (goto-char here) + (when hit pos)))) + +;; (defun mumamo-search-bw-textext-end (pos min) +;; "Helper for `mumamo-chunk-textext'. +;; POS is where to start search and MIN is where to stop." +;; (let ((end (mumamo-chunk-end-bw-str pos min "\")")) +;; res) +;; (while (and end +;; (not (setq res (mumamo-textext-test-is-end end)))) +;; (setq end (mumamo-chunk-end-bw-str (1- end) min "\")"))) +;; res)) + +;; (defun mumamo-search-fw-textext-start-old (pos max) +;; "Helper for `mumamo-chunk-textext'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "textext(\"")) + +(defun mumamo-search-fw-textext-start (pos max) + "Helper for `mumamo-chunk-textext'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max "textext(\""))) + (when where + (list where 'plain-tex-mode)))) + +(defun mumamo-search-fw-textext-end (pos max) + "Helper for `mumamo-chunk-textext'. +POS is where to start search and MAX is where to stop." + (save-match-data + (let ((end (mumamo-chunk-end-fw-str pos max "\")"))) + (mumamo-textext-test-is-end end)))) + +(defun mumamo-chunk-textext (pos min max) + "Find textext or TEX chunks. Return range and 'plain-tex-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-textext-start + ;; 'mumamo-search-bw-textext-end + ;; 'mumamo-search-fw-textext-start-old + ;; 'mumamo-search-fw-textext-end) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-textext-start + 'mumamo-search-fw-textext-end)) + +;; (defun mumamo-search-bw-verbatimtex-start (pos min) +;; "Helper for `mumamo-chunk-verbatimtextext'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min "\nverbatimtex")) +;; (exc-mode 'plain-tex-mode)) +;; (when exc-start +;; (when (<= exc-start pos) +;; (cons exc-start exc-mode))))) + +;; (defun mumamo-search-bw-verbatimtex-end (pos min) +;; "Helper for `mumamo-chunk-verbatimtextext'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "\netex")) + +;; (defun mumamo-search-fw-verbatimtex-start-old (pos max) +;; "Helper for `mumamo-chunk-verbatimtextext'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "\nverbatimtex")) + +(defun mumamo-search-fw-verbatimtex-start (pos max) + "Helper for `mumamo-chunk-verbatimtextext'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max "\nverbatimtex"))) + (when where + (list where 'plain-tex-mode)))) + +(defun mumamo-search-fw-verbatimtex-end (pos max) + "Helper for `mumamo-chunk-verbatimtextext'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "\netex"))) + +(defun mumamo-chunk-verbatimtex (pos min max) + "Find verbatimtex - etex chunks. Return range and 'plain-tex-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-verbatimtex-start + ;; 'mumamo-search-bw-verbatimtex-end + ;; 'mumamo-search-fw-verbatimtex-start-old + ;; 'mumamo-search-fw-verbatimtex-end) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-verbatimtex-start + 'mumamo-search-fw-verbatimtex-end)) + +;; (defun mumamo-search-bw-btex-start (pos min) +;; "Helper for `mumamo-chunk-btex'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min "\nverbatimtex")) +;; (exc-mode 'plain-tex-mode)) +;; (when exc-start +;; (when (<= exc-start pos) +;; (cons exc-start exc-mode))))) + +;; (defun mumamo-search-bw-btex-end (pos min) +;; "Helper for `mumamo-chunk-btex'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "\netex")) + +;; (defun mumamo-search-fw-btex-start-old (pos max) +;; "Helper for `mumamo-chunk-btex'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "\nverbatimtex")) + +(defun mumamo-search-fw-btex-start (pos max) + "Helper for `mumamo-chunk-btex'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max "\nverbatimtex"))) + (when where + (list where 'plain-tex-mode)))) + +(defun mumamo-search-fw-btex-end (pos max) + "Helper for `mumamo-chunk-btex'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "\netex"))) + +(defun mumamo-chunk-btex (pos min max) + "Find btex - etex chunks. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-btex-start + ;; 'mumamo-search-bw-btex-end + ;; 'mumamo-search-fw-btex-start-old + ;; 'mumamo-search-fw-btex-end) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-btex-start + 'mumamo-search-fw-btex-end)) + +;;;###autoload +(define-mumamo-multi-major-mode metapost-mumamo-mode + "Turn on multiple major modes for MetaPost." + ("MetaPost TeX Family" metapost-mode + (mumamo-chunk-textext + mumamo-chunk-verbatimtex + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; OpenLaszlo + +(defconst mumamo-lzx-method-tag-start-regex + (rx "")))) + ">" + ;; FIX-ME: Commented out because of bug in Emacs + ;; + ;;(optional (0+ space) "")) + +;; (defun mumamo-search-fw-exc-start-inlined-lzx-method-old (pos max) +;; "Helper for `mumamo-chunk-inlined-lzx-method'. +;; POS is where to start search and MAX is where to stop." +;; (goto-char (1+ pos)) +;; (skip-chars-backward "^<") +;; ;; Handle "))) + +(defun mumamo-chunk-inlined-lzx-method (pos min max) + "Find .... Return range and 'javascript-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-inlined-lzx-method + ;; 'mumamo-search-bw-exc-end-inlined-lzx-method + ;; 'mumamo-search-fw-exc-start-inlined-lzx-method-old + ;; 'mumamo-search-fw-exc-end-inlined-lzx-method) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-inlined-lzx-method + 'mumamo-search-fw-exc-end-inlined-lzx-method)) + +(defconst mumamo-lzx-handler-tag-start-regex + (rx "")))) + ">" + ;; FIX-ME: Commented out because of bug in Emacs + ;; + ;;(optional (0+ space) "")) + +;; (defun mumamo-search-fw-exc-start-inlined-lzx-handler-old (pos max) +;; "Helper for `mumamo-chunk-inlined-lzx-handler'. +;; POS is where to start search and MAX is where to stop." +;; (goto-char (1+ pos)) +;; (skip-chars-backward "^<") +;; ;; Handle "))) + +(defun mumamo-chunk-inlined-lzx-handler (pos min max) + "Find .... Return range and 'javascript-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-inlined-lzx-handler + ;; 'mumamo-search-bw-exc-end-inlined-lzx-handler + ;; 'mumamo-search-fw-exc-start-inlined-lzx-handler-old + ;; 'mumamo-search-fw-exc-end-inlined-lzx-handler) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-inlined-lzx-handler + 'mumamo-search-fw-exc-end-inlined-lzx-handler)) + + +;;;###autoload +(define-mumamo-multi-major-mode laszlo-nxml-mumamo-mode + "Turn on multiple major modes for OpenLaszlo." + ("OpenLaszlo Family" nxml-mode + (mumamo-chunk-inlined-script + mumamo-chunk-inlined-lzx-method + mumamo-chunk-inlined-lzx-handler + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; csound + +;; (defun mumamo-search-bw-exc-start-csound-orc (pos min) +;; "Helper for `mumamo-chunk-csound-orc'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min ""))) +;; (and exc-start +;; (<= exc-start pos) +;; (cons exc-start 'csound-orc-mode)))) + +;; (defun mumamo-search-bw-exc-end-csound-orc (pos min) +;; "Helper for `mumamo-chunk-csound-orc'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "")) + +;; (defun mumamo-search-fw-exc-start-csound-orc-old (pos max) +;; "Helper for `mumamo-chunk-csound-orc'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "")) + +(defun mumamo-search-fw-exc-start-csound-orc (pos max) + "Helper for `mumamo-chunk-csound-orc'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max ""))) + (when where + (list where 'csound-orc-mode)))) + +(defun mumamo-search-fw-exc-end-csound-orc (pos max) + "Helper for `mumamo-chunk-csound-orc'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max ""))) + +(defun mumamo-chunk-csound-orc (pos min max) + "Find .... Return range and 'csound-orc-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-csound-orc + ;; 'mumamo-search-bw-exc-end-csound-orc + ;; 'mumamo-search-fw-exc-start-csound-orc-old + ;; 'mumamo-search-fw-exc-end-csound-orc) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-csound-orc + 'mumamo-search-fw-exc-end-csound-orc)) + +;; (defun mumamo-search-bw-exc-start-csound-sco (pos min) +;; "Helper for `mumamo-chunk-csound-sco'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-str pos min ""))) +;; (and exc-start +;; (<= exc-start pos) +;; (cons exc-start 'csound-sco-mode)))) + +;; (defun mumamo-search-bw-exc-end-csound-sco (pos min) +;; "Helper for `mumamo-chunk-csound-sco'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "")) + +;; (defun mumamo-search-fw-exc-start-csound-sco-old (pos max) +;; "Helper for `mumamo-chunk-csound-sco'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "")) + +(defun mumamo-search-fw-exc-start-csound-sco (pos max) + "Helper for `mumamo-chunk-csound-sco'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max ""))) + (when where + (list where 'csound-sco-mode)))) + +(defun mumamo-search-fw-exc-end-csound-sco (pos max) + "Helper for `mumamo-chunk-csound-sco'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max ""))) + +(defun mumamo-chunk-csound-sco (pos min max) + "Found .... Return range and 'csound-sco-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-csound-sco + ;; 'mumamo-search-bw-exc-end-csound-sco + ;; 'mumamo-search-fw-exc-start-csound-sco-old + ;; 'mumamo-search-fw-exc-end-csound-sco) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-csound-sco + 'mumamo-search-fw-exc-end-csound-sco)) + +;;;###autoload +(define-mumamo-multi-major-mode csound-sgml-mumamo-mode + "Turn on mutiple major modes for CSound orc/sco Modes." + ("CSound orc/sco Modes" sgml-mode + (mumamo-chunk-csound-sco + mumamo-chunk-csound-orc + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; noweb + +;;;###autoload +(defgroup mumamo-noweb2 nil + "Customization group for `noweb2-mumamo-mode'." + :group 'mumamo-modes) + +(defcustom mumamo-noweb2-mode-from-ext + '( + ("php" . php-mode) + ("c" . c-mode) + ) + "File extension regexp to major mode mapping. +Used by `noweb2-mumamo-mode'." + :type '(repeat + (cons regexp major-mode-function)) + :group 'mumamo-noweb2) + +(defvar mumamo-noweb2-found-mode-from-ext nil + "Major modes determined from file names. Internal use.") + +(defun mumamo-noweb2-chunk-start-fw (pos max) + "Helper for `mumamo-noweb2-chunk'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-re pos max "^<<\\(.*?\\)>>=")) + (exc-mode 'text-mode)) + (when where + (let* ((file-name (match-string-no-properties 1)) + (file-ext (when file-name (file-name-extension file-name)))) + (when file-ext + (setq exc-mode (catch 'major + (dolist (rec mumamo-noweb2-mode-from-ext) + (when (string-match (car rec) file-ext) + (throw 'major (cdr rec)))) + nil)))) + (list where exc-mode)))) + +;; (defun mumamo-noweb2-chunk-start-bw (pos min) +;; "Helper for `mumamo-noweb2-chunk'. +;; POS is where to start search and MIN is where to stop." +;; (let ((exc-start (mumamo-chunk-start-bw-re pos min "^<<\\(.*?\\)>>=")) +;; (exc-mode 'text-mode)) +;; (when exc-start +;; (let* ((file-name (match-string 1)) +;; (file-ext (when file-name (file-name-extension file-name)))) +;; (when file-ext +;; (setq exc-mode (catch 'major +;; (dolist (rec mumamo-noweb2-mode-from-ext) +;; (when (string-match (car rec) file-ext) +;; (throw 'major (cdr rec)))) +;; nil)) +;; (unless exc-mode +;; (setq exc-mode +;; (cdr (assoc file-ext mumamo-noweb2-found-mode-from-ext))) +;; (unless exc-mode +;; ;; Get the major mode from file name +;; (with-temp-buffer +;; (setq buffer-file-name file-name) +;; (condition-case err +;; (normal-mode) +;; (error (message "error (normal-mode): %s" +;; (error-message-string err)))) +;; (setq exc-mode (or major-mode +;; 'text-mode)) +;; (add-to-list 'mumamo-noweb2-found-mode-from-ext +;; (cons file-ext exc-mode))) +;; )))) +;; (cons exc-start exc-mode)))) + +(defun mumamo-noweb2-chunk-end-fw (pos max) + "Helper for `mumamo-noweb2-chunk'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-re pos max "^@"))) + +;; (defun mumamo-noweb2-chunk-end-bw (pos min) +;; "Helper for `mumamo-noweb2-chunk'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-re pos min "^@")) + +(defun mumamo-noweb2-code-chunk (pos min max) + "Find noweb chunks. Return range and found mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (save-match-data + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-noweb2-chunk-start-bw + ;; 'mumamo-noweb2-chunk-end-bw + ;; 'mumamo-noweb2-chunk-start-fw-old + ;; 'mumamo-noweb2-chunk-end-fw) + (mumamo-possible-chunk-forward pos max + 'mumamo-noweb2-chunk-start-fw + 'mumamo-noweb2-chunk-end-fw))) + + +;;;###autoload +(define-mumamo-multi-major-mode noweb2-mumamo-mode + "Multi major mode for noweb files." + ("noweb Family" latex-mode + (mumamo-noweb2-code-chunk))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Template-Toolkit + + + +;; (setq auto-mode-alist +;; (append '(("\\.tt2?$" . tt-mode)) auto-mode-alist )) + +;;(require 'tt-mode) +(defun mumamo-chunk-tt (pos min max) + "Find [% ... %], return range and `tt-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX. + +This is for Template Toolkit. +See URL `http://dave.org.uk/emacs/' for `tt-mode'." + (mumamo-quick-static-chunk pos min max "[%" "%]" t 'tt-mode nil)) + +(define-mumamo-multi-major-mode tt-html-mumamo-mode + "Turn on multiple major modes for TT files with main mode `nxhtml-mode'. +TT = Template-Toolkit. + +This also covers inlined style and javascript." + ("TT HTML Family" html-mode + (mumamo-chunk-tt + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Asp + +;;;; asp <%@language="javscript"%> + +(defvar mumamo-asp-default-major 'asp-js-mode) +(make-variable-buffer-local 'mumamo-asp-default-major) +(put 'mumamo-asp-default-major 'permanent-local t) + +(defconst mumamo-asp-lang-marker + (rx "<%@" + (0+ space) + "language" + (0+ space) + "=" + (0+ space) + "\"" + (submatch (1+ (not (any "\"")))) + "\"" + (0+ space))) + +(defun mumamo-search-fw-exc-start-jsp (pos min max) + ;; fix-me + ) +(defun mumamo-chunk-asp (pos min max) + "Find <% ... %>. Return range and 'asp-js-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; Fix-me: this is broken! + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-exc-start-asp + ;; 'mumamo-search-bw-exc-end-jsp + ;; 'mumamo-search-fw-exc-start-jsp-old + ;; 'mumamo-search-fw-exc-end-jsp) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-exc-start-asp + 'mumamo-search-fw-exc-end-jsp)) + + +;;;; asp <% ...> + +(defun mumamo-chunk-asp% (pos min max) + "Find <% ... %>. Return range and 'asp-js-mode or 'asp-vb-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (let* ((chunk (mumamo-quick-static-chunk pos min max "<%" "%>" t 'java-mode t)) + (beg (nth 0 chunk)) + (here (point)) + glang) + (when chunk + (goto-char beg) + (if (looking-at mumamo-asp-lang-marker) + (progn + (setq glang (downcase (match-string 1))) + (cond + ((string= glang "javascript") + (setq mumamo-asp-default-major 'asp-js-mode)) + ((string= glang "vbscript") + (setq mumamo-asp-default-major 'asp-vb-mode)) + ) + (setcar (nthcdr 2 chunk) 'mumamo-comment-mode)) + (setcar (nthcdr 2 chunk) mumamo-asp-default-major)) + chunk))) + +;;;; asp . Return 'asp-js-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-asp-search-bw-exc-start-inlined-script + ;; 'mumamo-search-bw-exc-end-inlined-script + ;; 'mumamo-asp-search-fw-exc-start-inlined-script-old + ;; 'mumamo-search-fw-exc-end-inlined-script) + (mumamo-possible-chunk-forward pos max + 'mumamo-asp-search-fw-exc-start-inlined-script + 'mumamo-search-fw-exc-end-inlined-script)) + +;;;###autoload +(define-mumamo-multi-major-mode asp-html-mumamo-mode + "Turn on multiple major modes for ASP with main mode `html-mode'. +This also covers inlined style and javascript." + ("ASP Html Family" html-mode + (mumamo-chunk-asp% + mumamo-asp-chunk-inlined-script + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Org-mode + +(defcustom mumamo-org-submodes + '( + (emacs-lisp emacs-lisp-mode) + (ruby ruby-mode) + (python python-mode) + (sh sh-mode) + (R R-mode) + (ditaa picture-mode) + ) + "Alist for conversion of org #+BEGIN_SRC specifier to major mode. +Works kind of like `mumamo-major-modes'. + +This may be used for example for org-babel \(see URL +`http://orgmode.org/worg/org-contrib/babel/')." + :type '(alist + :key-type (symbol :tag "Symbol in #BEGIN_SRC specifier") + :value-type (repeat (choice + (command :tag "Major mode") + (symbol :tag "Major mode (not yet loaded)"))) + ) + :group 'mumamo-modes) + +(defun mumamo-org-mode-from-spec (major-spec) + "Translate MAJOR-SPEC to a major mode. +Translate MAJOR-SPEC used in #BEGIN_SRC to a major mode. + +See `mumamo-org-submodes' for an explanation." + (mumamo-major-mode-from-spec major-spec mumamo-org-submodes)) + +(defun mumamo-chunk-org-html (pos min max) + "Find #+BEGIN_HTML ... #+END_HTML, return range and `html-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "#+BEGIN_HTML" "#+END_HTML" nil 'html-mode nil)) + +;; (defun mumamo-search-bw-org-src-start (pos min) +;; "Helper for `mumamo-chunk-org-src'. +;; POS is where to start search and MIN is where to stop." +;; (let* ((exc-start (mumamo-chunk-start-bw-str pos min "#+BEGIN_SRC")) +;; (exc-mode (when exc-start +;; (let ((here (point))) +;; (goto-char exc-start) +;; (prog1 +;; (read (current-buffer)) +;; (goto-char here)))))) +;; (setq exc-mode (mumamo-org-mode-from-spec exc-mode)) +;; ;;(setq exc-mode (eval exc-mode)) +;; ;;(setq exc-mode 'text-mode) +;; ;;(when exc-mode (setq exc-mode (quote exc-mode))) +;; ;;(assert (eq exc-mode 'emacs-lisp-mode) t) +;; (when exc-start +;; (when (<= exc-start pos) +;; (cons exc-start exc-mode))))) + +;; (defun mumamo-search-bw-org-src-end (pos min) +;; "Helper for `mumamo-chunk-org-src'. +;; POS is where to start search and MIN is where to stop." +;; (mumamo-chunk-end-bw-str pos min "#+END_SRC")) + +;; (defun mumamo-search-fw-org-src-start-old (pos max) +;; "Helper for `mumamo-chunk-org-src'. +;; POS is where to start search and MAX is where to stop." +;; (mumamo-chunk-start-fw-str pos max "#+BEGIN_SRC")) + +(defun mumamo-search-fw-org-src-start (pos max) + "Helper for `mumamo-chunk-org-src'. +POS is where to start search and MAX is where to stop." + (let ((where (mumamo-chunk-start-fw-str pos max "#+BEGIN_SRC"))) + (when where + (let ((exc-mode (let ((here (point))) + (goto-char where) + (prog1 + (read (current-buffer)) + (goto-char here))))) + (setq exc-mode (mumamo-org-mode-from-spec exc-mode)) + (list where exc-mode))))) + +(defun mumamo-search-fw-org-src-end (pos max) + "Helper for `mumamo-chunk-org-src'. +POS is where to start search and MAX is where to stop." + (save-match-data + (mumamo-chunk-end-fw-str pos max "#+END_SRC"))) + +(defun mumamo-chunk-org-src (pos min max) + "Find #+BEGIN_SRC ... #+END_SRC, return range and choosen major mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX. + +See Info node `(org) Literal Examples' for how to specify major +mode." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-search-bw-org-src-start + ;; 'mumamo-search-bw-org-src-end + ;; 'mumamo-search-fw-org-src-start-old + ;; 'mumamo-search-fw-org-src-end) + (mumamo-possible-chunk-forward pos max + 'mumamo-search-fw-org-src-start + 'mumamo-search-fw-org-src-end)) + +;;;###autoload +(define-mumamo-multi-major-mode org-mumamo-mode + "Turn on multiple major modes for `org-mode' files with main mode `org-mode'. +** Note about HTML subchunks: +Unfortunately this only allows `html-mode' (not `nxhtml-mode') in +sub chunks." + ("Org Mode + Html" org-mode + (mumamo-chunk-org-html + mumamo-chunk-org-src + ))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Mako + +;; See http://www.makotemplates.org/docs/syntax.html + +;;; Comments mode +;; Fix-me: move to mumamo.el +(defconst mumamo-comment-font-lock-keywords + (list + (cons "\\(.*\\)" (list 1 font-lock-comment-face)) + )) +(defvar mumamo-comment-font-lock-defaults + '(mumamo-comment-font-lock-keywords t t)) + +(define-derived-mode mumamo-comment-mode nil "Comment chunk" + "For comment blocks." + (set (make-local-variable 'font-lock-defaults) mumamo-comment-font-lock-defaults)) + + + +(defun mumamo-chunk-mako-<% (pos min max) + "Find <% ... %> and <%! ... %>. Return range and `python-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;; (mumamo-find-possible-chunk pos min max + ;; 'mumamo-mako-<%-bw-start + ;; 'mumamo-mako-<%-bw-end + ;; 'mumamo-mako-<%-fw-start-old + ;; 'mumamo-mako-<%-fw-end + ;; 'mumamo-mako-<%-find-borders) + (let ((chunk (mumamo-possible-chunk-forward pos max + 'mumamo-mako-<%-fw-start + 'mumamo-mako-<%-fw-end + 'mumamo-mako-<%-find-borders + ))) + (when chunk + (setcdr (last chunk) '(mumamo-template-indentor)) + chunk))) + +(defun mumamo-mako-<%-find-borders (start end exc-mode) + (when exc-mode + (list + (when start + (+ start + (if (eq ?! (char-after (+ start 2))) + 3 + 2))) + (when end (- end 2)) + exc-mode))) + +;; (defun mumamo-mako-<%-bw-start (pos min) +;; (let ((here (point)) +;; start +;; ret +;; ) +;; (goto-char (+ pos 3)) +;; (setq start (re-search-backward "<%!?\\(?:[ \t]\\|$\\)" min t)) +;; (when (and start (<= start pos)) +;; (setq ret (list start 'python-mode))) +;; (goto-char here) +;; ret)) + +;; (defun mumamo-mako-<%-bw-end (pos min) +;; (mumamo-chunk-end-bw-str-inc pos min "%>")) ;; ok + +;; (defun mumamo-mako-<%-fw-start-old (pos max) +;; (let ((here (point)) +;; start +;; ret) +;; (goto-char pos) +;; (setq start +;; (re-search-forward "<%!?\\(?:[ \t]\\|$\\)" max t)) +;; (when start +;; (setq ret (match-beginning 0))) +;; (goto-char here) +;; ret)) + +(defun mumamo-mako-<%-fw-start (pos max) + (let ((here (point)) + start + ret) + (goto-char pos) + (setq start + (re-search-forward "<%!?\\(?:[ \t]\\|$\\)" max t)) + (when start + (setq ret (match-beginning 0))) + (goto-char here) + (when ret + (list ret 'python-mode)))) + +(defun mumamo-mako-<%-fw-end (pos max) + (save-match-data + (mumamo-chunk-end-fw-str-inc pos max "%>"))) ;; ok + + + +(defun mumamo-chunk-mako-% (pos min max) + "Find % python EOL. Return range and `python-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (let ((chunk (mumamo-whole-line-chunk pos min max "%" 'python-mode))) + (when chunk + (setcdr (last chunk) '(mumamo-template-indentor)) + chunk))) + +(defun mumamo-chunk-mako-one-line-comment (pos min max) + "Find ## comment EOL. Return range and `python-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-whole-line-chunk pos min max "##" 'mumamo-comment-mode)) + +;; Fix-me: Move this to mumamo.el +;; Fix-me: does not work with new chunk div +(defun mumamo-whole-line-chunk-fw-exc-end-fun (pos max) + (let ((here (point))) + (goto-char pos) + (prog1 + (line-end-position) + (goto-char here)))) + +(defun mumamo-whole-line-chunk (pos min max marker mode) + (let* ((here (point)) + (len-marker (length marker)) + (pattern (rx-to-string `(and bol (0+ blank) ,marker blank) t)) + (whole-line-chunk-borders-fun + `(lambda (start end dummy) + (let ((start-border (+ start ,len-marker))) + (list start-border nil)))) + beg + end + ret) + (goto-char pos) + (setq beg (re-search-forward pattern max t)) + (when beg + (setq beg (- beg len-marker 1)) + (setq end (line-end-position)) + (setq ret (list beg + end + mode + (let ((start-border (+ beg len-marker))) + (list start-border nil)) + nil + 'mumamo-whole-line-chunk-fw-exc-end-fun + whole-line-chunk-borders-fun + ))) + (goto-char here) + ret)) + +;; (defun mumamo-single-regexp-chunk (pos min max begin-mark end-mark mode) +;; "Not ready yet. `mumamo-quick-static-chunk'" +;; (let ((here (point)) +;; (len-marker (length marker)) +;; beg +;; end +;; ret) +;; (goto-char pos) +;; (setq beg (line-beginning-position)) +;; (setq end (line-end-position)) +;; (unless (or (when min (< beg min)) +;; (when max (> end max)) +;; (= pos end)) +;; (goto-char beg) +;; (skip-chars-forward " \t") +;; (when (and +;; (string= marker (buffer-substring-no-properties (point) (+ (point) len-marker))) +;; (memq (char-after (+ (point) len-marker)) +;; '(?\ ?\t ?\n)) +;; (>= pos (point))) +;; (setq ret +;; (list (point) +;; end +;; mode +;; (let ((start-border (+ (point) len-marker))) +;; (list start-border nil)))))) +;; (unless ret +;; (let ((range-regexp +;; (concat "^[ \t]*" +;; "\\(" +;; (regexp-quote marker) +;; "[ \t\n].*\\)$"))) +;; ;; Backward +;; (goto-char pos) +;; (unless (= pos (line-end-position)) +;; (goto-char (line-beginning-position))) +;; (setq beg (re-search-backward range-regexp min t)) +;; (when beg (setq beg (match-end 1))) +;; ;; Forward, take care of indentation part +;; (goto-char pos) +;; (unless (= pos (line-end-position)) +;; (goto-char (line-beginning-position))) +;; (setq end (re-search-forward range-regexp max t)) +;; (when end (setq end (match-beginning 1)))) +;; (setq ret (list beg end))) +;; (goto-char here) +;; ;;(setq ret nil) +;; ret)) + + +(defun mumamo-chunk-mako-<%doc (pos min max) + (mumamo-quick-static-chunk pos min max "<%doc>" "" t 'mumamo-comment-mode t)) + +(defun mumamo-chunk-mako-<%include (pos min max) + (mumamo-quick-static-chunk pos min max "<%include" "/>" t 'html-mode t)) + +(defun mumamo-chunk-mako-<%inherit (pos min max) + (mumamo-quick-static-chunk pos min max "<%inherit" "/>" t 'html-mode t)) + +(defun mumamo-chunk-mako-<%namespace (pos min max) + (mumamo-quick-static-chunk pos min max "<%namespace" "/>" t 'html-mode t)) + +(defun mumamo-chunk-mako-<%page (pos min max) + (mumamo-quick-static-chunk pos min max "<%page" "/>" t 'html-mode t)) + +;; Fix-me: this is not correct +(defun mumamo-chunk-mako-<%def (pos min max) + (mumamo-quick-static-chunk pos min max "<%def" "" t 'html-mode t)) + +(defun mumamo-chunk-mako$(pos min max) + "Find ${ ... }, return range and `python-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (mumamo-quick-static-chunk pos min max "${" "}" t 'python-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode mako-html-mumamo-mode + "Turn on multiple major modes for Mako with main mode `html-mode'. +This also covers inlined style and javascript." +;; Fix-me: test case +;; +;; Fix-me: Add chunks for the tags, but make sure these are made +;; invisible to nxml-mode parser. +;; +;; Fix-me: Maybe finally add that indentation support for one-line chunks? + ("Mako HTML Family" html-mode + ( + mumamo-chunk-mako-one-line-comment + mumamo-chunk-mako-<%doc + mumamo-chunk-mako-<%include + mumamo-chunk-mako-<%inherit + mumamo-chunk-mako-<%namespace + mumamo-chunk-mako-<%page + + mumamo-chunk-mako-<%def + ;;mumamo-chunk-mako-<%namesp:name + ;;mumamo-chunk-mako-<%call + ;;mumamo-chunk-mako-<%text + + mumamo-chunk-mako-<% + mumamo-chunk-mako-% + mumamo-chunk-mako$ + + mumamo-chunk-xml-pi + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + mumamo-chunk-style= + mumamo-chunk-onjs= + ))) +(mumamo-inherit-sub-chunk-family-locally 'mako-html-mumamo-mode 'mako-html-mumamo-mode) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; XSL + +;;;###autoload +(define-mumamo-multi-major-mode xsl-nxml-mumamo-mode + "Turn on multi major mode for XSL with main mode `nxml-mode'. +This covers inlined style and javascript." + ("XSL nXtml Family" nxml-mode + ( + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + ))) + +;;;###autoload +(define-mumamo-multi-major-mode xsl-sgml-mumamo-mode + "Turn on multi major mode for XSL with main mode `sgml-mode'. +This covers inlined style and javascript." + ("XSL SGML Family" sgml-mode + ( + mumamo-chunk-inlined-style + mumamo-chunk-inlined-script + ))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Markdown + +(defun mumamo-chunk-markdown-html-1 (pos min max) + (save-restriction + (goto-char pos) + (narrow-to-region (or min (point)) (or max (point-max))) + (save-match-data + (let ((here (point))) + (when (re-search-forward (rx (* space) + (submatch "<") + (* (any "a-z")) + (or ">" (any " \t\n"))) + nil t) + (let ((beg (match-beginning 1)) + (end)) + (goto-char beg) + (condition-case err + (progn + (while (not (sgml-skip-tag-forward 1))) + (setq end (point))) + (error (message "mumamo-chunk-markdown-html-1: %s" err))) + (goto-char here) + (when (and beg end) + (cons beg end)))))))) + +(defun mumamo-chunk-markdown-html-fw-exc-fun (pos max) + (let ((beg-end (mumamo-chunk-markdown-html-1 pos nil max))) + (cdr beg-end))) + +(defun mumamo-chunk-markdown-html (pos min max) + "Find a chunk of html code in `markdown-mode'. +Return range and `html-mode'. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + (let ((beg-end (mumamo-chunk-markdown-html-1 pos nil max))) + (when beg-end + (let ((beg (car beg-end)) + (end (cdr beg-end))) + (list beg end 'html-mode + nil ;; borders + nil ;; parseable y + 'mumamo-chunk-markdown-html-fw-exc-fun + nil ;; find-borders fun + ))))) + +;;;###autoload +(define-mumamo-multi-major-mode markdown-html-mumamo-mode + "Turn on multi major markdown mode in buffer. +Main major mode will be `markdown-mode'. +Inlined html will be in `html-mode'. + +You need `markdown-mode' which you can download from URL +`http://jblevins.org/projects/markdown-mode/'." + ("Markdown HTML Family" markdown-mode + ( + mumamo-chunk-markdown-html + ))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Latex related + +(defun mumamo-latex-closure-chunk (pos min max) + (mumamo-quick-static-chunk pos min max "\\begin{clojure}" "\\end{clojure}" t 'clojure-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode latex-clojure-mumamo-mode + "Turn on multi major mode latex+clojure. +Main major mode will be `latex-mode'. +Subchunks will be in `clojure-mode'. + +You will need `clojure-mode' which you can download from URL +`http://github.com/jochu/clojure-mode/tree'." + ("Latex+clojur Family" latex-mode + ( + mumamo-latex-closure-chunk + ))) + +(add-to-list 'auto-mode-alist '("\\.lclj\\'" . latex-clojure-mumamo-mode)) + + +(defun mumamo-latex-haskell-chunk (pos min max) + (mumamo-quick-static-chunk pos min max "\\begin{code}" "\\end{code}" t 'haskell-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode latex-haskell-mumamo-mode + "Turn on multi major mode latex+haskell. +Main major mode will be `latex-mode'. +Subchunks will be in `haskell-mode'. + +You will need `haskell-mode' which you can download from URL +`http://projects.haskell.org/haskellmode-emacs/'." + ("Latex+haskell Family" latex-mode + ( + mumamo-latex-haskell-chunk + ))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Python + ReST + +;; From Martin Soto + +(defun python-rst-long-string-chunk (pos min max) + "Find Python long strings. Return range and 'mumamo-comment-mode. +See `mumamo-find-possible-chunk' for POS, MIN and MAX." + ;;(mumamo-quick-static-chunk pos min max "\"\"\"((" "))\"\"\"" nil 'rst-mode nil)) + (mumamo-quick-static-chunk pos min max "\"\"\"" "\"\"\"" t 'rst-mode t)) + +;;;###autoload +(define-mumamo-multi-major-mode python-rst-mumamo-mode + "Turn on multiple major modes for Python with RestructuredText docstrings." + ("Python ReST Family" python-mode + ( + python-rst-long-string-chunk + ))) + + +(provide 'mumamo-fun) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; mumamo-fun.el ends here diff --git a/emacs.d/nxhtml/util/mumamo-regions.el b/emacs.d/nxhtml/util/mumamo-regions.el new file mode 100644 index 0000000..077be60 --- /dev/null +++ b/emacs.d/nxhtml/util/mumamo-regions.el @@ -0,0 +1,311 @@ +;;; mumamo-regions.el --- user defined regions with mumamo +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Created: 2009-05-31 Sun +;; Version: 0.5 +;; Last-Updated: 2009-06-01 Mon +;; URL: +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; None +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Commentary: +;; +;; Add temporary mumamo chunks (called mumamo regions). This are +;; added interactively from a highlighted region. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; 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 3, 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 'cl)) +(eval-when-compile (require 'mumamo)) +(eval-when-compile (require 'ourcomments-widgets)) +(require 'ps-print) ;; For ps-print-ensure-fontified + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Internal side functions etc + +(defvar mumamo-regions nil + "List of active mumamo regions. Internal use only. +The entries in this list should be like this + + \(OVL-DEF OVL-CHUNK) + +where OVL-DEF is an overlay containing the definitions, ie `major-mode'. +OVL-CHUNK is the definitions set up temporarily for mumamo chunks. + +The fontification functions in mumamo looks in this list, but the +chunk dividing functions defined by +`define-mumamo-multi-major-mode' does not. The effect is that +the normal chunks exists regardless of what is in this list, but +fontification etc is overridden by what this list says.") +(make-variable-buffer-local 'mumamo-regions) +(put 'mumamo-regions 'permanent-local t) + +(defun mumamo-add-region-1 (major start end buffer) + "Add a mumamo region with major mode MAJOR from START to END. +Return the region. The returned value can be used in +`mumamo-clear-region'. + +START and END should be markers in the buffer BUFFER. They may +also be nil in which case they extend the region to the buffer +boundaries." + (unless mumamo-multi-major-mode + (mumamo-temporary-multi-major)) + (or (not start) + (markerp start) + (eq (marker-buffer start) buffer) + (error "Bad arg start: %s" start)) + (or (not end) + (markerp end) + (eq (marker-buffer end) buffer) + (error "Bad arg end: %s" end)) + (let ((ovl (make-overlay start end))) + (overlay-put ovl 'mumamo-region 'defined) + (overlay-put ovl 'face 'mumamo-region) + (overlay-put ovl 'priority 2) + (mumamo-region-set-major ovl major) + (setq mumamo-regions (cons (list ovl nil) mumamo-regions)) + (mumamo-mark-for-refontification (overlay-start ovl) (overlay-end ovl)) + (message "Added mumamo region from %d to %d" (+ 0 start) (+ 0 end)) + ovl)) + +(defun mumamo-clear-region-1 (region-entry) + "Clear mumamo region REGION-ENTRY. +The entry must have been returned from `mumamo-add-region-1'." + (let ((buffer (overlay-buffer (car region-entry))) + (entry (cdr region-entry))) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (let ((ovl1 (car region-entry)) + (ovl2 (cadr region-entry))) + (delete-overlay ovl1) + (when ovl2 + (mumamo-mark-for-refontification (overlay-start ovl2) (overlay-end ovl2)) + (delete-overlay ovl2)) + (setq mumamo-regions (delete region-entry mumamo-regions))))))) + +(defvar mumamo-region-priority 0) +(make-variable-buffer-local 'mumamo-region-priority) +(put 'mumamo-region-priority 'permanent-local t) + +(defun mumamo-get-region-from-1 (point) + "Return mumamo region values for POINT. +The return value is either mumamo chunk or a cons with +information about where regions starts to hide normal chunks. +Such a cons has the format \(BELOW . OVER) where each of them is +a position or nil." + (when mumamo-regions + (save-restriction + (widen) + (let* ((start nil) + (end nil) + (major nil) + hit-reg + ret-val) + (catch 'found-major + (dolist (reg mumamo-regions) + (assert (eq (overlay-get (car reg) 'mumamo-region) 'defined) t) + (assert (or (not (cadr reg)) (overlayp (cadr reg)))) + (let* ((this-ovl (car reg)) + (this-start (overlay-start this-ovl)) + (this-end (overlay-end this-ovl))) + (when (<= this-end point) + (setq start this-end)) + (when (< point this-start) + (setq end this-start)) + (when (and (<= this-start point) + (< point this-end)) + (setq major (overlay-get this-ovl 'mumamo-major-mode)) + (setq start (max this-start (or start this-start))) + (setq end (min this-end (or end this-end))) + (setq hit-reg reg) + (throw 'found-major nil))))) + (if major + (progn + (setq ret-val (nth 1 hit-reg)) + (when ret-val (assert (eq (overlay-get ret-val 'mumamo-region) 'used) t)) + (if ret-val + (move-overlay ret-val start end) + (setq ret-val (make-overlay start end nil t nil)) ;; fix-me + (setcar (cdr hit-reg) ret-val) + (overlay-put ret-val 'mumamo-region 'used) + (overlay-put ret-val 'priority ;; above normal chunks + chunks on chunks + (setq mumamo-region-priority (1+ mumamo-region-priority))) + ;;(overlay-put ret-val 'face '(:background "chocolate")) ;; temporary + (overlay-put ret-val 'mumamo-major-mode + (overlay-get (car hit-reg) 'mumamo-major-mode)))) + (setq ret-val (cons start end))) + ;;(message "mumamo-get-region-from-1, point=%s ret-val=%s" point ret-val) + ret-val)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; User side functions + +(defun mumamo-temporary-multi-major () + "Turn on a temporary multi major mode from buffers current mode. +Define one if no one exists. It will have no chunk dividing +routines. It is meant mainly to be used with mumamo regions when +there is no mumamo multi major mode in the buffer and the user +wants to add a mumamo region \(which requires a multi major mode +to work)." + (when mumamo-multi-major-mode + (error "Mumamo is already active in buffer")) + (let* ((temp-mode-name (concat "mumamo-1-" + (symbol-name major-mode))) + (temp-mode-sym (intern-soft temp-mode-name))) + (unless (and temp-mode-sym + (fboundp temp-mode-sym)) + (setq temp-mode-sym (intern temp-mode-name)) + (eval + `(define-mumamo-multi-major-mode ,temp-mode-sym + "Temporary multi major mode." + ("Temporary" ,major-mode nil)))) + (put temp-mode-sym 'mumamo-temporary major-mode) + (funcall temp-mode-sym))) + +(defface mumamo-region + '((t (:background "white"))) + "Face for mumamo-region regions." + :group 'mumamo) + +;;;###autoload +(defun mumamo-add-region () + "Add a mumamo region from selection. +Mumamo regions are like another layer of chunks above the normal chunks. +They does not affect the normal chunks, but they overrides them. + +To create a mumamo region first select a visible region and then +call this function. + +If the buffer is not in a multi major mode a temporary multi +major mode will be created applied to the buffer first. +To get out of this and get back to a single major mode just use + + M-x normal-mode" + (interactive) + (if (not mark-active) + (message (propertize "Please select a visible region first" 'face 'secondary-selection)) + (let ((beg (region-beginning)) + (end (region-end)) + (maj (mumamo-region-read-major))) + (mumamo-add-region-1 maj (copy-marker beg) (copy-marker end) (current-buffer)) + (setq deactivate-mark t)))) + +;;;###autoload +(defun mumamo-add-region-from-string () + "Add a mumamo region from string at point. +Works as `mumamo-add-region' but for string or comment at point. + +Buffer must be fontified." + (interactive) + ;; assure font locked. + (require 'ps-print) + (ps-print-ensure-fontified (point-min) (point-max)) + (let ((the-face (get-text-property (point) 'face))) + (if (not (memq the-face + '(font-lock-doc-face + font-lock-string-face + font-lock-comment-face))) + (message "No string or comment at point") + (let ((beg (previous-single-property-change (point) 'face)) + (end (next-single-property-change (point) 'face)) + (maj (mumamo-region-read-major))) + (setq beg (or (when beg (1+ beg)) + (point-min))) + (setq end (or (when end (1- end)) + (point-max))) + (mumamo-add-region-1 maj (copy-marker beg) (copy-marker end) (current-buffer)))))) +;; (dolist (o (overlays-in (point-min) (point-max))) (delete-overlay o)) +(defun mumamo-clear-all-regions () + "Clear all mumamo regions in buffer. +For information about mumamo regions see `mumamo-add-region'." + (interactive) + (unless mumamo-multi-major-mode + (error "There can be no mumamo regions to clear unless in multi major modes")) + (while mumamo-regions + (mumamo-clear-region-1 (car mumamo-regions)) + (setq mumamo-regions (cdr mumamo-regions))) + (let ((old (get mumamo-multi-major-mode 'mumamo-temporary))) + (when old (funcall old))) + (message "Cleared all mumamo regions")) + +(defun mumamo-region-read-major () + "Prompt user for major mode. +Accept only single major mode, not mumamo multi major modes." + (let ((major (read-command "Major mode: "))) + (unless (major-modep major) (error "Not a major mode: %s" major)) + (when (mumamo-multi-major-modep major) (error "Multi major modes not allowed: %s" major)) + (when (let ((major-mode major)) + (derived-mode-p 'nxml-mode)) + (error "%s is based on nxml-mode and can't be used here" major)) + major)) + +(defun mumamo-region-at (point) + "Return mumamo region at POINT." + (let ((ovls (overlays-at (point)))) + (catch 'overlay + (dolist (o ovls) + (when (overlay-get o 'mumamo-region) + (throw 'overlay o))) + nil))) + +(defun mumamo-region-set-major (ovl major) + "Change major mode for mumamo region at point. +For information about mumamo regions see `mumamo-add-region'. + +If run non-interactively then OVL should be a mumamo region and +MAJOR the major mode to set for that region." + (interactive + (list (or (mumamo-region-at (point)) + (error "There is no mumamo region at point")) + (mumamo-region-read-major))) + (overlay-put ovl 'mumamo-major-mode `(,major)) + (overlay-put ovl 'help-echo (format "Mumamo region, major mode `%s'" major))) + +(defun mumamo-clear-region (ovl) + "Clear the mumamo region at point. +For information about mumamo regions see `mumamo-add-region'. + +If run non-interactively then OVL should be the mumamo region to +clear." + (interactive + (list (or (mumamo-region-at (point)) + (error "There is no mumamo region at point")))) + (let ((region-entry (rassoc (list ovl) mumamo-regions))) + (unless region-entry + (error "No mumamo region found at point")) + (mumamo-clear-region-1 region-entry))) + + +(provide 'mumamo-regions) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; mumamo-regions.el ends here diff --git a/emacs.d/nxhtml/util/mumamo-trace.el b/emacs.d/nxhtml/util/mumamo-trace.el new file mode 100644 index 0000000..72b839b --- /dev/null +++ b/emacs.d/nxhtml/util/mumamo-trace.el @@ -0,0 +1,6 @@ +(trace-function-background 'mumamo-fontify-region-1) +(trace-function-background 'mumamo-fontify-region-with) +(trace-function-background 'mumamo-mark-for-refontification) +(trace-function-background 'syntax-ppss-flush-cache) + +;;(untrace-all) diff --git a/emacs.d/nxhtml/util/mumamo.el b/emacs.d/nxhtml/util/mumamo.el new file mode 100644 index 0000000..3fefa1a --- /dev/null +++ b/emacs.d/nxhtml/util/mumamo.el @@ -0,0 +1,9100 @@ +;;; mumamo.el --- Multiple major modes in a buffer +;; +;; Author: Lennart Borgman (lennart O borgman A gmail O com) +;; Maintainer: +;; Created: Fri Mar 09 2007 +(defconst mumamo:version "0.91") ;;Version: +;; Last-Updated: 2009-10-19 Mon +;; URL: http://OurComments.org/Emacs/Emacs.html +;; Keywords: +;; Compatibility: +;; +;; Features that might be required by this library: +;; +;; `appmenu', `apropos', `backquote', `button', `bytecomp', `cl', +;; `comint', `compile', `easymenu', `flyspell', `grep', `ido', +;; `ispell', `mail-prsvr', `mlinks', `mm-util', `nxml-enc', +;; `nxml-glyph', `nxml-mode', `nxml-ns', `nxml-outln', +;; `nxml-parse', `nxml-rap', `nxml-util', `ourcomments-util', +;; `recentf', `ring', `rng-dt', `rng-loc', `rng-match', +;; `rng-parse', `rng-pttrn', `rng-uri', `rng-util', `rng-valid', +;; `rx', `sgml-mode', `timer', `tool-bar', `tree-widget', +;; `url-expand', `url-methods', `url-parse', `url-util', +;; `url-vars', `wid-edit', `xmltok'. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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 3, 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 GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +;; Boston, MA 02110-1301, USA. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Commentary: +;; +;; In some cases you may find that it is quite hard to write one major +;; mode that does everything for the type of file you want to handle. +;; That is the case for example for a PHP file where there comes +;; useful major modes with Emacs for the html parts, and where you can +;; get a major mode for PHP from other sources (see EmacsWiki for +;; Aaron Hawleys php-mode.el, or the very similar version that comes +;; with nXhtml). +;; +;; Using one major mode for the HTML part and another for the PHP part +;; sounds like a good solution. But this means you want to use (at +;; least) two major modes in the same buffer. +;; +;; This file implements just that, support for MUltiple MAjor MOdes +;; (mumamo) in a buffer. +;; +;; +;;;; Usage: +;; +;; The multiple major mode support is turned on by calling special +;; functions which are used nearly the same way as major modes. See +;; `mumamo-defined-multi-major-modes' for more information about those +;; functions. +;; +;; Each such function defines how to take care of a certain mix of +;; major functions in the buffer. We call them "multi major modes". +;; +;; You may call those functions directly (like you can with major mode +;; functions) or you may use them in for example `auto-mode-alist'. +;; +;; You can load mumamo in your .emacs with +;; +;; (require 'mumamo-fun) +;; +;; or you can generate an autoload file from mumamo-fun.el +;; +;; Note that no multi major mode functions are defined in this file. +;; Together with this file comes the file mumamo-fun.el that defines +;; some such functions. All those functions defined in that file are +;; marked for autoload. +;; +;; +;; +;; Thanks to Stefan Monnier for beeing a good and knowledgeable +;; speaking partner for some difficult parts while I was trying to +;; develop this. +;; +;; Thanks to RMS for giving me support and ideas about the programming +;; interface. That simplified the code and usage quite a lot. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; How to add support for a new mix of major modes +;; +;; This is done by creating a new function using +;; `define-mumamo-multi-major-mode'. See that function for more +;; information. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Information for major mode authors +;; +;; There are a few special requirements on major modes to make them +;; work with mumamo: +;; +;; - fontification-functions should be '(jit-lock-function). However +;; nxml-mode derivates can work too, see the code for more info. +;; +;; - narrowing should be respected during fontification and +;; indentation when font-lock-dont-widen is non-nil. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Information for minor mode authors +;; +;; Some minor modes are written to be specific for the file edited in +;; the buffer and some are written to be specific for a major +;; modes. Others are emulating another editor. Those are probably +;; global, but might still have buffer local values. +;; +;; Those minor modes that are not meant to be specific for a major +;; mode should probably survive changing major mode in the +;; buffer. That is mostly not the case in Emacs today. +;; +;; There are (at least) two type of values for those minor modes that +;; sometimes should survive changing major mode: buffer local +;; variables and functions added locally to hooks. +;; +;; * Some buffer local variables are really that - buffer local. Other +;; are really meant not for the buffer but for the major mode or +;; some minor mode that is local to the buffer. +;; +;; If the buffer local variable is meant for the buffer then it is +;; easy to make them survive changing major mode: just add +;; +;; (put 'VARIABLE 'permanent-local t) +;; +;; to those variables. That will work regardless of the way major +;; mode is changed. +;; +;; If one only wants the variables to survive the major mode change +;; that is done when moving between chunks with different major +;; modes then something different must be used. To make a variable +;; survive this, but not a major mode change for the whole buffer, +;; call any the function `mumamo-make-variable-buffer-permanent': +;; +;; (mumamo-make-variable-buffer-permanent 'VARIABLE) +;; +;; * For functions entered to local hooks use this +;; +;; (put 'FUNSYM 'permanent-local-hook t) +;; (add-hook 'HOOKSYM 'FUNSYM nil t) +;; +;; where HOOKSYM is the hook and FUNSYM is the function. +;; +;; * Some functions that are run in `change-major-mode' and dito +;; after- must be avoided when mumamo changes major mode. The +;; functions to avoid should be listed in +;; +;; `mumamo-change-major-mode-no-nos' +;; `mumamo-after-change-major-mode-no-nos' +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Comments on code etc: +;; +;; This is yet another way to try to get different major modes for +;; different chunks of a buffer to work. (I borrowed the term "chunk" +;; here from multi-mode.el.) I am aware of two main previous elisp +;; packages that tries to do this, multi-mode.el and mmm-mode.el. +;; (See http://www.emacswiki.org/cgi-bin/wiki/MultipleModes where +;; there are also some other packages mentioned.) The solutions in +;; those are a bit different from the approach here. +;; +;; The idea of doing it the way mumamo does it is of course based on a +;; hope that switching major mode when moving between chunks should be +;; quick. I found that it took from 0 - 62 000 ms, typically 0 - 16 +;; 000 ms on a 3ghz cpu. However unfortunately this is not the whole +;; truth. It could take longer time, depending on what is run in the +;; hooks: The major mode specific hook, `after-change-major-mode-hook' +;; and `change-major-mode-hook'. +;; +;; Because it currently may take long enough time switching major mode +;; when moving between chunks to disturb smooth moving around in the +;; buffer I have added a way to let the major mode switching be done +;; after moving when Emacs is idle. This is currently the default, but +;; see the custom variable `mumamo-set-major-mode-delay'. +;; +;; Since the intention is to set up the new major mode the same way as +;; it should have been done if this was a major mode for the whole +;; buffer these hooks must be run. However if this idea is developed +;; further some of the things done in these hooks (like switching on +;; minor modes) could perhaps be streamlined so that switching minor +;; modes off and then on again could be avoided. In fact there is +;; already tools for this in mumamo.el, see the section below named +;; "Information for minor mode authors". +;; +;; Another problem is that the major modes must use +;; `font-lock-fontify-region-function'. Currently the only major +;; modes I know that does not do this are `nxml-mode' and its +;; derivatives. +;; +;; The indentation is currently working rather ok, but with the price +;; that buffer modified is sometimes set even though there are no +;; actual changes. That seems a bit unnecessary and it could be +;; avoided if the indentation functions for the the various major +;; modes were rewritten so that you could get the indentation that +;; would be done instead of actually doing the indentation. (Or +;; mumamo could do this better, but I do not know how right now.) +;; +;; See also "Known bugs and problems etc" below. +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Known bugs: +;; +;; - See the various FIX-ME for possible bugs. See also below. +;; +;; +;;;; Known problems and ideas: +;; +;; - There is no way in Emacs to tell a mode not to change +;; fontification when changing to or from that mode. +;; +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;;; Code: + +(eval-when-compile (require 'cl)) +(eval-when-compile (require 'cc-engine)) +(eval-when-compile (require 'desktop)) +(eval-when-compile (require 'flyspell)) +(eval-when-compile (require 'rngalt nil t)) +(eval-when-compile (require 'nxml-mode nil t)) +(eval-when-compile + (when (featurep 'nxml-mode) + (require 'rng-valid nil t) + ;;(require 'rngalt nil t) + )) +(eval-when-compile (require 'sgml-mode)) ;; For sgml-xml-mode +;; For `define-globalized-minor-mode-with-on-off': +;;(require 'ourcomments-util) + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; rng-valid.el support + +(defvar rng-get-major-mode-chunk-function nil + "Function to use to get major mode chunk. +It should take one argument, the position where to get the major +mode chunk. + +This is to be set by multiple major mode frame works, like +mumamo. + +See also `rng-valid-nxml-major-mode-chunk-function' and +`rng-end-major-mode-chunk-function'. Note that all three +variables must be set.") +(make-variable-buffer-local 'rng-get-major-mode-chunk-function) +(put 'rng-get-major-mode-chunk-function 'permanent-local t) + +(defvar rng-valid-nxml-major-mode-chunk-function nil + "Function to use to check if nxml can parse major mode chunk. +It should take one argument, the chunk. + +For more info see also `rng-get-major-mode-chunk-function'.") +(make-variable-buffer-local 'rng-valid-nxml-major-mode-chunk-function) +(put 'rng-valid-nxml-major-mode-chunk-function 'permanent-local t) + +(defvar rng-end-major-mode-chunk-function nil + "Function to use to get the end of a major mode chunk. +It should take one argument, the chunk. + +For more info see also `rng-get-major-mode-chunk-function'.") +(make-variable-buffer-local 'rng-end-major-mode-chunk-function) +(put 'rng-end-major-mode-chunk-function 'permanent-local t) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Some variables + +(defvar mumamo-major-mode-indent-line-function nil) +(make-variable-buffer-local 'mumamo-major-mode-indent-line-function) + +(defvar mumamo-buffer-locals-per-major nil) +(make-variable-buffer-local 'mumamo-buffer-locals-per-major) +(put 'mumamo-buffer-locals-per-major 'permanent-local t) + +(defvar mumamo-just-changed-major nil + "Avoid refontification when switching major mode. +Set to t by `mumamo-set-major'. Checked and reset to nil by +`mumamo-jit-lock-function'.") +(make-variable-buffer-local 'mumamo-just-changed-major) + +(defvar mumamo-multi-major-mode nil + "The function that handles multiple major modes. +If this is nil then multiple major modes in the buffer is not +handled by mumamo. + +Set by functions defined by `define-mumamo-multi-major-mode'.") +(make-variable-buffer-local 'mumamo-multi-major-mode) +(put 'mumamo-multi-major-mode 'permanent-local t) + +(defvar mumamo-set-major-running nil + "Internal use. Handling of mumamo turn off.") + +(defun mumamo-chunk-car (chunk prop) + (car (overlay-get chunk prop))) + +(defun mumamo-chunk-cadr (chunk prop) + (cadr (overlay-get chunk prop))) + +;; (let ((l '(1 2))) (setcar (nthcdr 1 l) 10) l) +;; setters +(defsubst mumamo-chunk-value-set-min (chunk-values min) + "In CHUNK-VALUES set min value to MIN. +CHUNK-VALUES should have the format return by +`mumamo-create-chunk-values-at'." + (setcar (nthcdr 0 chunk-values) min)) +(defsubst mumamo-chunk-value-set-max (chunk-values max) + "In CHUNK-VALUES set max value to MAX. +See also `mumamo-chunk-value-set-min'." + (setcar (nthcdr 1 chunk-values) max)) +(defsubst mumamo-chunk-value-set-syntax-min (chunk-values min) + "In CHUNK-VALUES set min syntax diff value to MIN. +See also `mumamo-chunk-value-set-min'." + (setcar (nthcdr 3 chunk-values) min)) +(defsubst mumamo-chunk-value-set-syntax-max (chunk-values max) + "In CHUNK-VALUES set max syntax diff value to MAX. +See also `mumamo-chunk-value-set-min'." + (setcar (nthcdr 3 chunk-values) max)) +;; getters +(defsubst mumamo-chunk-value-min (chunk-values) + "Get min value from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 0 chunk-values)) +(defsubst mumamo-chunk-value-max (chunk-values) + "Get max value from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 1 chunk-values)) +(defsubst mumamo-chunk-value-major (chunk-values) + "Get major value from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 2 chunk-values)) +(defsubst mumamo-chunk-value-syntax-min (chunk-values) + "Get min syntax diff value from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 3 chunk-values)) +(defsubst mumamo-chunk-value-syntax-max (chunk-values) + "Get max syntax diff value from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 4 chunk-values)) +(defsubst mumamo-chunk-value-parseable-by (chunk-values) + "Get parseable-by from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'. +For parseable-by see `mumamo-find-possible-chunk'." + (nth 5 chunk-values)) +;; (defsubst mumamo-chunk-prev-chunk (chunk-values) +;; "Get previous chunk from CHUNK-VALUES. +;; See also `mumamo-chunk-value-set-min'." +;; (nth 6 chunk-values)) +(defsubst mumamo-chunk-value-fw-exc-fun (chunk-values) + "Get function that find chunk end from CHUNK-VALUES. +See also `mumamo-chunk-value-set-min'." + (nth 6 chunk-values)) + +(defsubst mumamo-chunk-major-mode (chunk) + "Get major mode specified in CHUNK." + ;;(assert chunk) + ;;(assert (overlay-buffer chunk)) + (let ((mode-spec (if chunk + (mumamo-chunk-car chunk 'mumamo-major-mode) + (mumamo-main-major-mode)))) + (mumamo-major-mode-from-modespec mode-spec))) + +(defsubst mumamo-chunk-syntax-min-max (chunk no-obscure) + (when chunk + (let* ((ovl-end (overlay-end chunk)) + (ovl-start (overlay-start chunk)) + (syntax-min (min ovl-end + (+ ovl-start + (or (overlay-get chunk 'mumamo-syntax-min-d) + 0)))) + ;;(dummy (msgtrc "chunk-syntax-min-max:syntax-min=%s, chunk=%S" syntax-min chunk)) + (syntax-max + (max ovl-start + (- (overlay-end chunk) + (or (overlay-get chunk 'mumamo-syntax-max-d) + 0) + (if (= (1+ (buffer-size)) + (overlay-end chunk)) + 0 + ;; Note: We must subtract one here because + ;; overlay-end is +1 from the last point in the + ;; overlay. + ;; + ;; This cured the problem with + ;; kubica-freezing-i.html that made Emacs loop + ;; in `font-lock-extend-region-multiline'. But + ;; was it really this one, I can't find any + ;; 'font-lock-multiline property. So it should + ;; be `font-lock-extend-region-whole-lines'. + ;; + ;; Should not the problem then be the value of font-lock-end? + ;; + ;; Fix-me: however this is not correct since it + ;; leads to not fontifying the last character in + ;; the chunk, see bug 531324. + ;; + ;; I think this is cured by now. I have let + ;; bound `font-lock-extend-region-functions' + ;; once more before the call to + ;; `font-lock-fontify-region'. + 0 + ;;0 + )))) + (obscure (unless no-obscure (overlay-get chunk 'obscured))) + (region-info (cadr obscure)) + (obscure-min (car region-info)) + (obscure-max (cdr region-info)) + ;;(dummy (message "syn-mn-mx:obs=%s r-info=%s ob=%s/%s" obscure region-info obscure-min obscure-max )) + (actual-min (max (or obscure-min ovl-start) + (or syntax-min ovl-start))) + (actual-max (min (or obscure-max ovl-end) + (or syntax-max ovl-end))) + (maj (mumamo-chunk-car chunk 'mumamo-major-mode)) + ;;(dummy (message "syn-mn-mx:obs=%s r-info=%s ob=%s/%s ac=%s/%s" obscure region-info obscure-min obscure-max actual-min actual-max)) + ) + (cons actual-min actual-max)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Macros + +;; Borrowed from font-lock.el +(defmacro mumamo-save-buffer-state (varlist &rest body) + "Bind variables according to VARLIST and eval BODY restoring buffer state. +Do not record undo information during evaluation of BODY." + (declare (indent 1) (debug let)) + (let ((modified (make-symbol "modified"))) + `(let* ,(append varlist + `((,modified (buffer-modified-p)) + (buffer-undo-list t) + (inhibit-read-only t) + (inhibit-point-motion-hooks t) + (inhibit-modification-hooks t) + deactivate-mark + buffer-file-name + buffer-file-truename)) + (progn + ,@body) + (unless ,modified + (restore-buffer-modified-p nil))))) + +;; From jit-lock.el: +(defmacro mumamo-jit-with-buffer-unmodified (&rest body) + "Eval BODY, preserving the current buffer's modified state." + (declare (debug t)) + (let ((modified (make-symbol "modified"))) + `(let ((,modified (buffer-modified-p))) + (unwind-protect + (progn ,@body) + (unless ,modified + (restore-buffer-modified-p nil)))))) + +(defmacro mumamo-with-buffer-prepared-for-jit-lock (&rest body) + "Execute BODY in current buffer, overriding several variables. +Preserves the `buffer-modified-p' state of the current buffer." + (declare (debug t)) + `(mumamo-jit-with-buffer-unmodified + (let ((buffer-undo-list t) + (inhibit-read-only t) + (inhibit-point-motion-hooks t) + (inhibit-modification-hooks t) + deactivate-mark + buffer-file-name + buffer-file-truename) + ,@body))) + +(defmacro mumamo-condition-case (var body-form &rest handlers) + "Like `condition-case', but optional. +If `mumamo-use-condition-case' is non-nil then do + + (condition-case VAR + BODY-FORM + HANDLERS). + +Otherwise just evaluate BODY-FORM." + (declare (indent 2) (debug t)) + `(if (not mumamo-use-condition-case) + (let* ((debugger (or mumamo-debugger 'debug)) + (debug-on-error (if debugger t debug-on-error))) + ,body-form) + (condition-case ,var + ,body-form + ,@handlers))) + +(defmacro mumamo-msgfntfy (format-string &rest args) + "Give some messages during fontification. +This macro should just do nothing during normal use. However if +there are any problems you can uncomment one of the lines in this +macro and recompile/reeval mumamo.el to get those messages. + +You have to search the code to see where you will get them. All +uses are in this file. + +FORMAT-STRING and ARGS have the same meaning as for the function +`message'." + ;;(list 'apply (list 'quote 'msgtrc) format-string (append '(list) args)) + ;;(list 'apply (list 'quote 'message) format-string (append '(list) args)) + ;;(list 'progn 'apply (list 'quote 'message) format-string (append '(list) args) nil) + ;; (condition-case err + ;; (list 'apply (list 'quote 'message) format-string (append '(list) args)) ;; <-- + ;; (error (message "err in msgfntfy %S" err))) + ;;(message "%s %S" format-string args) + ;;(list 'apply (list 'quote 'message) (list 'concat "%s: " format-string) + ;; (list 'get-internal-run-time) (append '(list) args)) + ) +;;(mumamo-msgfntfy "my-format=%s" (get-internal-run-time)) + +(defmacro mumamo-msgindent (format-string &rest args) + "Give some messages during indentation. +This macro should just do nothing during normal use. However if +there are any problems you can uncomment one of the lines in this +macro and recompile/reeval mumamo.el to get those messages. + +You have to search the code to see where you will get them. All +uses are in this file. + +FORMAT-STRING and ARGS have the same meaning as for the function +`message'." + ;;(list 'apply (list 'quote 'msgtrc) format-string (append '(list) args)) + ;;(list 'apply (list 'quote 'message) format-string (append '(list) args)) ;; <--- + ;;(list 'apply (list 'quote 'message) (list 'concat "%s: " format-string) + ;; (list 'get-internal-run-time) (append '(list) args)) + ) + +(defmacro mumamo-with-major-mode-setup (major for-what &rest body) + "Run code with some local variables set as in specified major mode. +Set variables as needed for major mode MAJOR when doing FOR-WHAT +and then run BODY using `with-syntax-table'. + +FOR-WHAT is used to choose another major mode than MAJOR in +certain cases. It should be 'fontification or 'indentation. + +Note: We must let-bind the variables here instead of make them buffer +local since they otherwise could be wrong at \(point) in top +level \(ie user interaction level)." + (declare (indent 2) (debug t)) + `(let ((need-major-mode (mumamo-get-major-mode-substitute ,major ,for-what))) + ;;(msgtrc "mumamo-with-major-mode-setup %s => %s, modified=%s" ,major need-major-mode (buffer-modified-p)) + ;;(msgtrc "with-major-mode-setup <<<<<<<<<< body=%S\n>>>>>>>>>>" '(progn ,@body)) + ;;(msgtrc "with-major-mode-setup:in buffer %s after-chunk=%s" (current-buffer) (when (boundp 'after-chunk) after-chunk)) + (let ((major-mode need-major-mode) + (evaled-set-mode (mumamo-get-major-mode-setup need-major-mode))) + ;;(message ">>>>>> before %s" evaled-set-mode) + ;;(message ">>>>>> before %s, body=%s" evaled-set-mode (list ,@body)) + (funcall (symbol-value evaled-set-mode) + (list 'progn + ,@body)) + ;;(mumamo-msgfntfy "<<<<<< after evaled-set-mode modified=%s" (buffer-modified-p)) + ))) + +(defmacro mumamo-with-major-mode-fontification (major &rest body) + "With fontification variables set as major mode MAJOR eval BODY. +This is used during font locking and indentation. The variables +affecting those are set as they are in major mode MAJOR. + +See the code in `mumamo-fetch-major-mode-setup' for exactly which +local variables that are set." + (declare (indent 1) (debug t)) + `(mumamo-with-major-mode-setup ,major 'fontification + ,@body)) +;; Fontification disappears in for example *grep* if +;; font-lock-mode-major-mode is 'permanent-local t. +;;(put 'font-lock-mode-major-mode 'permanent-local t) + +(defmacro mumamo-with-major-mode-indentation (major &rest body) + "With indentation variables set as in another major mode do things. +Same as `mumamo-with-major-mode-fontification' but for +indentation. See that function for some notes about MAJOR and +BODY." + (declare (indent 1) (debug t)) + `(mumamo-with-major-mode-setup ,major 'indentation ,@body)) + +;; fix-me: tell no sub-chunks in sub-chunks +;;;###autoload +(defmacro define-mumamo-multi-major-mode (fun-sym spec-doc chunks) + "Define a function that turn on support for multiple major modes. +Define a function FUN-SYM that set up to divide the current +buffer into chunks with different major modes. + +The documentation string for FUN-SYM should contain the special +documentation in the string SPEC-DOC, general documentation for +functions of this type and information about chunks. + +The new function will use the definitions in CHUNKS \(which is +called a \"chunk family\") to make the dividing of the buffer. + +The function FUN-SYM can be used to setup a buffer instead of a +major mode function: + +- The function FUN-SYM can be called instead of calling a major + mode function when you want to use multiple major modes in a + buffer. + +- The defined function can be used instead of a major mode + function in for example `auto-mode-alist'. + +- As the very last thing FUN-SYM will run the hook FUN-SYM-hook, + just as major modes do. + +- There is also a general hook, `mumamo-turn-on-hook', which is + run when turning on mumamo with any of these functions. This + is run right before the hook specific to any of the functions + above that turns on the multiple major mode support. + +- The multi major mode FUN-SYM has a keymap named FUN-SYM-map. + This overrides the major modes' keymaps since it is handled as + a minor mode keymap. + +- There is also a special mumamo keymap, `mumamo-map' that is + active in every buffer with a multi major mode. This is also + handled as a minor mode keymap and therefor overrides the major + modes' keymaps. + +- However when this support for multiple major mode is on the + buffer is divided into chunks, each with its own major mode. + +- The chunks are fontified according the major mode assigned to + them for that. + +- Indenting is also done according to the major mode assigned to + them for that. + +- The actual major mode used in the buffer is changed to the one + in the chunk when moving point between these chunks. + +- When major mode is changed the hooks for the new major mode, + `after-change-major-mode-hook' and `change-major-mode-hook' are + run. + +- There will be an alias for FUN-SYM called mumamo-alias-FUN-SYM. + This can be used to check whic multi major modes have been + defined. + +** A little bit more technical description: + +The dividing of a buffer into chunks is done during fontification +by `mumamo-get-chunk-at'. + +The name of the function is saved in in the buffer local variable +`mumamo-multi-major-mode' when the function is called. + +All functions defined by this macro is added to the list +`mumamo-defined-multi-major-modes'. + +Basically Mumamo handles only major modes that uses jit-lock. +However as a special effort also `nxml-mode' and derivatives +thereof are handled. Since it seems impossible to me to restrict +those major modes fontification to only a chunk without changing +`nxml-mode' the fontification is instead done by +`html-mode'/`sgml-mode' for chunks using `nxml-mode' and its +derivates. + +CHUNKS is a list where each entry have the format + + \(CHUNK-DEF-NAME MAIN-MAJOR-MODE SUBMODE-CHUNK-FUNCTIONS) + +CHUNK-DEF-NAME is the key name by which the entry is recognized. +MAIN-MAJOR-MODE is the major mode used when there is no chunks. +If this is nil then `major-mode' before turning on this mode will +be used. + +SUBMODE-CHUNK-FUNCTIONS is a list of the functions that does the +chunk division of the buffer. They are tried in the order they +appear here during the chunk division process. + +If you want to write new functions for chunk divisions then +please see `mumamo-find-possible-chunk'. You can perhaps also +use `mumamo-quick-static-chunk' which is more easy-to-use +alternative. See also the file mumamo-fun.el where there are +many routines for chunk division. + +When you write those new functions you may want to use some of +the functions for testing chunks: + + `mumamo-test-create-chunk-at' `mumamo-test-create-chunks-at-all' + `mumamo-test-easy-make' `mumamo-test-fontify-region' + +These are in the file mumamo-test.el." + ;;(let ((c (if (symbolp chunks) (symbol-value chunks) chunks))) (message "c=%S" c)) + (let* (;;(mumamo-describe-chunks (make-symbol "mumamo-describe-chunks")) + (turn-on-fun (if (symbolp fun-sym) + fun-sym + (error "Parameter FUN-SYM must be a symbol"))) + (turn-on-fun-alias (intern (concat "mumamo-alias-" (symbol-name fun-sym)))) + ;; Backward compatibility nXhtml v 1.60 + (turn-on-fun-old (when (string= (substring (symbol-name fun-sym) -5) + "-mode") + (intern (substring (symbol-name fun-sym) 0 -5)))) + (turn-on-hook (intern (concat (symbol-name turn-on-fun) "-hook"))) + (turn-on-map (intern (concat (symbol-name turn-on-fun) "-map"))) + (turn-on-hook-doc (concat "Hook run at the very end of `" + (symbol-name turn-on-fun) "'.")) + (chunks2 (if (symbolp chunks) + (symbol-value chunks) + chunks)) + (docstring + (concat + spec-doc + " + + + +This function is called a multi major mode. It sets up for +multiple major modes in the buffer in the following way: + +" + ;; Fix-me: During byte compilation the next line is not + ;; expanded as I thought because the functions in CHUNKS + ;; are not defined. How do I fix this? Move out the + ;; define-mumamo-multi-major-mode calls? + (funcall 'mumamo-describe-chunks chunks2) + " +At the very end this multi major mode function runs first the hook +`mumamo-turn-on-hook' and then `" (symbol-name turn-on-hook) "'. + +There is a keymap specific to this multi major mode, but it is +not returned by `current-local-map' which returns the chunk's +major mode's local keymap. + +The multi mode keymap is named `" (symbol-name turn-on-map) "'. + + + +The main use for a multi major mode is to use it instead of a +normal major mode in `auto-mode-alist'. \(You can of course call +this function directly yourself too.) + +The value of `mumamo-multi-major-mode' tells you which multi +major mode if any has been turned on in a buffer. For more +information about multi major modes please see +`define-mumamo-multi-major-mode'. + +Note: When adding new font-lock keywords for major mode chunks +you should use the function `mumamo-refresh-multi-font-lock' +afterwards. +" ))) + `(progn + ;;(add-to-list 'mumamo-defined-multi-major-modes (cons (car ',chunks2) ',turn-on-fun)) + (mumamo-add-to-defined-multi-major-modes (cons (car ',chunks2) ',turn-on-fun)) + (defvar ,turn-on-hook nil ,turn-on-hook-doc) + (defvar ,turn-on-map (make-sparse-keymap) + ,(concat "Keymap for multi major mode function `" + (symbol-name turn-on-fun) "'")) + (defvar ,turn-on-fun nil) + (make-variable-buffer-local ',turn-on-fun) + (put ',turn-on-fun 'permanent-local t) + (put ',turn-on-fun 'mumamo-chunk-family (copy-tree ',chunks2)) + (put ',turn-on-fun-alias 'mumamo-chunk-family (copy-tree ',chunks2)) + (defun ,turn-on-fun nil ,docstring + (interactive) + (let ((old-major-mode (or mumamo-major-mode + major-mode))) + (kill-all-local-variables) + (run-hooks 'change-major-mode-hook) + (setq mumamo-multi-major-mode ',turn-on-fun) + (setq ,turn-on-fun t) + (mumamo-add-multi-keymap ',turn-on-fun ,turn-on-map) + (setq mumamo-current-chunk-family (copy-tree ',chunks2)) + (mumamo-turn-on-actions old-major-mode) + (run-hooks ',turn-on-hook))) + (defalias ',turn-on-fun-alias ',turn-on-fun) + (when (intern-soft ',turn-on-fun-old) + (defalias ',turn-on-fun-old ',turn-on-fun)) + ))) + +;;;###autoload +(defun mumamo-add-to-defined-multi-major-modes (entry) + (add-to-list 'mumamo-defined-multi-major-modes entry)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Debugging etc + +(defsubst mumamo-while (limit counter where) + (let ((count (symbol-value counter))) + (if (= count limit) + (progn + (msgtrc "Reached (while limit=%s, where=%s)" limit where) + nil) + (set counter (1+ count))))) + +;; (defun dbg-smarty-err () +;; ;; (insert "}{") + +;; ;; (insert "}{") +;; ;; (backward-char) +;; ;; (backward-char) +;; ;; (search-backward "}") + +;; ;; This gives an error rather often, but not always: +;; (delete-char 3) +;; (search-backward "}") +;; ) + +;; (defun dbg-smarty-err2 () +;; (forward-char 5) +;; (insert "}{") +;; ;; Start in nxhtml part and make sure the insertion is in smarty +;; ;; part. Gives reliably an error if moved backward so point stay in +;; ;; the new nxhtml-mode part, otherwise not. +;; ;; +;; ;; Eh, no. If chunk family is changed and reset there is no more an +;; ;; error. +;; ;; +;; ;; Seems to be some race condition, but I am unable to understand +;; ;; how. I believed that nxml always left in a reliable state. Is +;; ;; this a state problem in mumamo or nxml? I am unable to make it +;; ;; happen again now. +;; ;; +;; ;; I saw one very strange thing: The error message got inserted in +;; ;; the .phps buffer once. How could this happen? Is this an Emacs +;; ;; bug? Can't see how this could happen since it is the message +;; ;; function that outputs the message. A w32 race condition? Are +;; ;; people aware that the message queue runs in parallell? (I have +;; ;; tried to ask on the devel list, but got no answer at that time.) +;; (backward-char 2) +;; ) + + +(defvar msgtrc-buffer + "*Messages*" + ;;"*trace-output*" + "Buffer or name of buffer for trace messages. +See `msgtrc'." + ) + +(defun msgtrc (format-string &rest args) + "Print message to `msgtrc-buffer'. +Arguments FORMAT-STRING and ARGS are like for `message'." + (if nil + nil ;;(apply 'message format-string args) + ;; bug#3350 prevents use of this: + (let ((trc-buffer (get-buffer-create msgtrc-buffer)) + ;; Cure 3350: Stop insert from deactivating the mark + (deactivate-mark)) + (with-current-buffer trc-buffer + (goto-char (point-max)) + (insert "MU:" (apply 'format format-string args) "\n") + ;;(insert "constant string\n") + (when buffer-file-name (write-region nil nil buffer-file-name)))))) + +(defvar mumamo-message-file-buffer nil) +(defsubst mumamo-msgtrc-to-file () + "Start writing message to file. Erase `msgtrc-buffer' first." + (unless mumamo-message-file-buffer + (setq mumamo-message-file-buffer (find-file-noselect "c:/emacs/bugs/temp-messages.txt")) + (setq msgtrc-buffer mumamo-message-file-buffer) + (with-current-buffer mumamo-message-file-buffer + (erase-buffer)))) + +(defvar mumamo-display-error-lwarn nil + "Set to t to call `lwarn' on fontification errors. +If this is t then `*Warnings*' buffer will popup on fontification +errors.") +(defvar mumamo-display-error-stop nil + "Set to t to stop fontification on errors.") + +(defun mumamo-message-with-face (msg face) + "Put MSG with face FACE in *Messages* buffer." + (let ((start (+ (with-current-buffer msgtrc-buffer + (point-max)) + 1)) + ;; This is for the echo area: + (msg-with-face (propertize (format "%s" msg) + 'face face))) + + (msgtrc "%s" msg-with-face) + ;; This is for the buffer: + (with-current-buffer msgtrc-buffer + (goto-char (point-max)) + (backward-char) + (put-text-property start (point) + 'face face)))) + +;;(run-with-idle-timer 1 nil 'mumamo-show-report-message) +(defun mumamo-show-report-message () + "Tell the user there is a long error message." + (save-match-data ;; runs in timer + (mumamo-message-with-face + "MuMaMo error, please look in the *Messages* buffer" + 'highlight))) + +;; This code can't be used now because `debugger' is currently not +;; useable in timers. I keep it here since I hope someone will make it +;; possible in the future. +;; +;; (defmacro mumamo-get-backtrace-if-error (bodyform) +;; "Evaluate BODYFORM, return a list with error message and backtrace. +;; If there is an error in BODYFORM then return a list with the +;; error message and the backtrace as a string. Otherwise return +;; nil." +;; `(let* ((debugger +;; (lambda (&rest debugger-args) +;; (let ((debugger-ret (with-output-to-string (backtrace)))) +;; ;; I believe we must put the result in a buffer, +;; ;; otherwise `condition-case' might erase it: +;; (with-current-buffer (get-buffer-create "TEMP GET BACKTRACE") +;; (erase-buffer) +;; (insert debugger-ret))))) +;; (debug-on-error t) +;; (debug-on-signal t)) +;; (mumamo-condition-case err +;; (progn +;; ,bodyform +;; nil) +;; (error +;; (let* ((errmsg (error-message-string err)) +;; (dbg1-ret +;; (with-current-buffer +;; (get-buffer "TEMP GET BACKTRACE") (buffer-string))) +;; ;; Remove lines from this routine: +;; (debugger-lines (split-string dbg1-ret "\n")) +;; (dbg-ret (mapconcat 'identity (nthcdr 6 debugger-lines) "\n")) +;; ) +;; (list errmsg (concat errmsg "\n" dbg-ret))))))) + +;;(mumamo-display-error 'test-lwarn-type "testing 1=%s, 2=%s" "one" 'two) +(defun mumamo-display-error (lwarn-type format-string &rest args) + "Display a message plus traceback in the *Messages* buffer. +Use this for errors that happen during fontification or when +running a timer. + +LWARN-TYPE is used as the type argument to `lwarn' if warnings +are displayed. FORMAT-STRING and ARGS are used as the +corresponding arguments to `message' and `lwarn'. + +All the output from this function in the *Messages* buffer is +displayed with the highlight face. After the message printed by +`message' is traceback from where this function was called. +Note: There is no error generated, just a traceback that is put +in *Messages* as above. + +Display an error message using `message' and colorize it using +the `highlight' face to make it more prominent. Add a backtrace +colored with the `highlight' face to the buffer *Messages*. Then +display the error message once again after this so that the user +can see it. + +If `mumamo-display-error-lwarn' is non-nil, indicate the error by +calling `lwarn'. This will display the `*Warnings*' buffer and +thus makes it much more easy to spot that there was an error. + +If `mumamo-display-error-stop' is non-nil raise an error that may +stop fontification." + + ;; Warnings are sometimes disturbning, make it optional: + (when mumamo-display-error-lwarn + (apply 'lwarn lwarn-type :error format-string args)) + + (let ((format-string2 (concat "%s: " format-string)) + (bt (with-output-to-string (backtrace)))) + + (mumamo-message-with-face + (concat + (apply 'format format-string2 lwarn-type args) + "\n" + (format "** In buffer %s\n" (current-buffer)) + bt) + 'highlight) + + ;; Output message once again so the user can see it: + (apply 'message format-string2 lwarn-type args) + ;; But ... there might be more messages so wait until things has + ;; calmed down and then show a message telling that there was an + ;; error and that there is more information in the *Messages* + ;; buffer. + (run-with-idle-timer 1 nil 'mumamo-show-report-message) + + ;; Stop fontifying: + (when mumamo-display-error-stop + ;;(font-lock-mode -1) + (setq font-lock-mode nil) + (when (timerp jit-lock-context-timer) + (cancel-timer jit-lock-context-timer)) + (when (timerp jit-lock-defer-timer) + (cancel-timer jit-lock-defer-timer)) + (apply 'error format-string2 lwarn-type args)))) + + +(defun mumamo-debug-to-backtrace (&rest debugger-args) + "This function should give a backtrace during fontification errors. +The variable `debugger' should then be this function. See the +function `debug' for an explanation of DEBUGGER-ARGS. + +Fix-me: Can't use this function yet since the display routines +uses safe_eval and safe_call." + (mumamo-display-error 'mumamo-debug-to-backtrace + "%s" + (nth 1 debugger-args))) + +;; (defun my-test-err3 () +;; (interactive) +;; (let ((debugger 'mumamo-debug-to-backtrace) +;; (debug-on-error t)) +;; (my-err) +;; )) +;;(my-test-err3() + +;;(set-default 'mumamo-use-condition-case nil) +;;(set-default 'mumamo-use-condition-case t) +(defvar mumamo-use-condition-case t) +(make-variable-buffer-local 'mumamo-use-condition-case) +(put 'mumamo-use-condition-case 'permanent-local t) + +(defvar mumamo-debugger 'mumamo-debug-to-backtrace) +(make-variable-buffer-local 'mumamo-debugger) +(put 'mumamo-debugger 'permanent-local t) + +;; (defun my-test-err4 () +;; (interactive) +;; (mumamo-condition-case err +;; (my-errx) +;; (arith-error (message "here")) +;; (error (message "%s, %s" err (error-message-string err))) +;; )) + +(defvar mumamo-warned-once nil) +(make-variable-buffer-local 'mumamo-warned-once) +(put 'mumamo-warned-once 'permanent-local t) + + ; (append '(0 1) '(a b)) +(defun mumamo-warn-once (type message &rest args) + "Warn only once with TYPE, MESSAGE and ARGS. +If the same problem happens again then do not warn again." + (let ((msgrec (append (list type message) args))) + (unless (member msgrec mumamo-warned-once) + (setq mumamo-warned-once + (cons msgrec mumamo-warned-once)) + ;;(apply 'lwarn type :warning message args) + (apply 'message (format "%s: %s" type message) args) + ))) + +(defun mumamo-add-help-tabs () + "Add key bindings for moving between buttons. +Add bindings similar to those in `help-mode' for moving between +text buttons." + (local-set-key [tab] 'forward-button) + (local-set-key [(meta tab)] 'backward-button) + (local-set-key [(shift tab)] 'backward-button) + (local-set-key [backtab] 'backward-button)) + +(defun mumamo-insert-describe-button (symbol type) + "Insert a text button that describes SYMBOL of type TYPE." + (let ((func `(lambda (btn) + (funcall ',type ',symbol)))) + (mumamo-add-help-tabs) + (insert-text-button + (symbol-name symbol) + :type 'help-function + 'face 'link + 'action func))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Custom group + +;;;###autoload +(defgroup mumamo nil + "Customization group for multiple major modes in a buffer." + :group 'editing + :group 'languages + :group 'sgml + :group 'nxhtml + ) + +;;(setq mumamo-set-major-mode-delay -1) +;;(setq mumamo-set-major-mode-delay 5) +(defcustom mumamo-set-major-mode-delay idle-update-delay + "Delay this number of seconds before setting major mode. +When point enters a region where the major mode should be +different than the current major mode, wait until Emacs has been +idle this number of seconds before switching major mode. + +If negative switch major mode immediately. + +Ideally the switching of major mode should occur immediately when +entering a region. However this can make movements a bit unsmooth +for some major modes on a slow computer. Therefore on a slow +computer use a short delay. + +If you have a fast computer and want to use mode specific +movement commands then set this variable to -1. + +I tried to measure the time for switching major mode in mumamo. +For most major modes it took 0 ms, but for `nxml-mode' and its +derivate it took 20 ms on a 3GHz CPU." + :type 'number + :group 'mumamo) + + +(defgroup mumamo-display nil + "Customization group for mumamo chunk display." + :group 'mumamo) + +(defun mumamo-update-this-buffer-margin-use () + (mumamo-update-buffer-margin-use (current-buffer))) + +(define-minor-mode mumamo-margin-info-mode + "Display chunk info in margin when on. +Display chunk depth and major mode where a chunk begin in left or +right margin. \(The '-mode' part of the major mode is stripped.) + +See also `mumamo-margin-use'. + +Note: When `linum-mode' is on the right margin is always used +now \(since `linum-mode' uses the left)." + :group 'mumamo-display + (mumamo-update-this-buffer-margin-use) + (if mumamo-margin-info-mode + (progn + ;;(add-hook 'window-configuration-change-hook 'mumamo-update-this-buffer-margin-use nil t) + (add-hook 'linum-mode-hook 'mumamo-update-this-buffer-margin-use nil t) + ) + ;;(remove-hook 'window-configuration-change-hook 'mumamo-update-this-buffer-margin-use t) + (remove-hook 'linum-mode-hook 'mumamo-update-this-buffer-margin-use t) + )) +;;(put 'mumamo-margin-info-mode 'permanent-local t) + +(defun mumamo-margin-info-mode-turn-off () + (mumamo-margin-info-mode -1)) +(put 'mumamo-margin-info-mode-turn-off 'permanent-local-hook t) + +(define-globalized-minor-mode mumamo-margin-info-global-mode mumamo-margin-info-mode + (lambda () (when (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode) + (mumamo-margin-info-mode 1))) + :group 'mumamo-display) + +(defcustom mumamo-margin-use '(left-margin 13) + "Display chunk info in left or right margin if non-nil." + :type '(list (radio (const :tag "Display chunk info in left margin" left-margin) + (const :tag "Display chunk info in right margin" right-margin)) + (integer :tag "Margin width (when used)" :value 13)) + :set (lambda (sym val) + (set-default sym val) + (when (fboundp 'mumamo-update-all-buffers-margin-use) + (mumamo-update-all-buffers-margin-use))) + :group 'mumamo-display) + +(defun mumamo-update-all-buffers-margin-use () + (dolist (buf (buffer-list)) + (mumamo-update-buffer-margin-use buf))) + +(define-minor-mode mumamo-no-chunk-coloring + "Use no background colors to distinguish chunks. +When this minor mode is on in a buffer no chunk coloring is done +in that buffer. This is overrides `mumamo-chunk-coloring'. It +is meant for situations when you temporarily need to remove the +background colors." + :lighter " ø" + :group 'mumamo-display + (font-lock-mode -1) + (font-lock-mode 1)) +(put 'mumamo-no-chunk-coloring 'permanent-local t) + + +;; (setq mumamo-chunk-coloring 4) +(defcustom mumamo-chunk-coloring 0 + "Color chunks with depth greater than or equal to this. +When 0 all chunks will be colored. If 1 all sub mode chunks will +be colored, etc." + :type '(integer :tag "Color chunks with depth greater than this") + :group 'mumamo-display) + +(defface mumamo-background-chunk-major + '((((class color) (min-colors 88) (background dark)) + ;;:background "blue3") + :background "MidnightBlue") + (((class color) (min-colors 88) (background light)) + ;;:background "lightgoldenrod2") + :background "cornsilk") + (((class color) (min-colors 16) (background dark)) + :background "blue4") + (((class color) (min-colors 16) (background light)) + :background "cornsilk") + (((class color) (min-colors 8)) + :background "blue") + (((type tty) (class mono)) + :inverse-video t) + (t :background "gray")) + "Background colors for chunks in sub modes. +You should only specify :background here, otherwise it will +interfere with syntax highlighting." + :group 'mumamo-display) + +(defface mumamo-background-chunk-submode1 + '((((class color) (min-colors 88) (background dark)) + ;;:background "blue3") + :background "DarkGreen" + ;;:background "#081010" + ) + (((class color) (min-colors 88) (background light)) + ;;:background "lightgoldenrod2") + :background "Azure") + (((class color) (min-colors 16) (background dark)) + :background "blue3") + (((class color) (min-colors 16) (background light)) + :background "azure") + (((class color) (min-colors 8)) + :background "Blue") + (((type tty) (class mono)) + :inverse-video t) + (t :background "gray")) + "Background colors for chunks in major mode. +You should only specify :background here, otherwise it will +interfere with syntax highlighting." + :group 'mumamo-display) + +(defface mumamo-background-chunk-submode2 + '((((class color) (min-colors 88) (background dark)) + ;;:background "blue3") + :background "dark green") + (((class color) (min-colors 88) (background light)) + ;;:background "lightgoldenrod2") + :background "#e6ff96") + (((class color) (min-colors 16) (background dark)) + :background "blue3") + (((class color) (min-colors 16) (background light)) + :background "azure") + (((class color) (min-colors 8)) + :background "blue") + (((type tty) (class mono)) + :inverse-video t) + (t :background "gray")) + "Background colors for chunks in major mode. +You should only specify :background here, otherwise it will +interfere with syntax highlighting." + :group 'mumamo-display) + +(defface mumamo-background-chunk-submode3 + '((((class color) (min-colors 88) (background dark)) + ;;:background "blue3") + :background "dark green") + (((class color) (min-colors 88) (background light)) + ;;:background "lightgoldenrod2") + :background "#f7d1f4") + ;;:background "green") + (((class color) (min-colors 16) (background dark)) + :background "blue3") + (((class color) (min-colors 16) (background light)) + :background "azure") + (((class color) (min-colors 8)) + :background "blue") + (((type tty) (class mono)) + :inverse-video t) + (t :background "gray")) + "Background colors for chunks in major mode. +You should only specify :background here, otherwise it will +interfere with syntax highlighting." + :group 'mumamo-display) + +(defface mumamo-background-chunk-submode4 + '((((class color) (min-colors 88) (background dark)) + ;;:background "blue3") + :background "dark green") + (((class color) (min-colors 88) (background light)) + ;;:background "lightgoldenrod2") + :background "orange") + (((class color) (min-colors 16) (background dark)) + :background "blue3") + (((class color) (min-colors 16) (background light)) + :background "azure") + (((class color) (min-colors 8)) + :background "blue") + (((type tty) (class mono)) + :inverse-video t) + (t :background "gray")) + "Background colors for chunks in major mode. +You should only specify :background here, otherwise it will +interfere with syntax highlighting." + :group 'mumamo-display) + +(defcustom mumamo-background-chunk-major 'mumamo-background-chunk-major + "Background colors for chunks in major mode. +Pointer to face with background color. + +If you do not want any special background color use the face named +default." + :type 'face + :group 'mumamo-display) + +(defcustom mumamo-background-chunk-submode1 'mumamo-background-chunk-submode1 + "Background colors for chunks in sub modes. +Pointer to face with background color. + +If you do not want any special background color use the face named +default." + :type 'face + :group 'mumamo-display) + +(defcustom mumamo-background-chunk-submode2 'mumamo-background-chunk-submode2 + "Background colors for chunks in sub modes. +Pointer to face with background color. + +If you do not want any special background color use the face named +default." + :type 'face + :group 'mumamo-display) + +(defcustom mumamo-background-chunk-submode3 'mumamo-background-chunk-submode3 + "Background colors for chunks in sub modes. +Pointer to face with background color. + +If you do not want any special background color use the face named +default." + :type 'face + :group 'mumamo-display) + +(defcustom mumamo-background-chunk-submode4 'mumamo-background-chunk-submode4 + "Background colors for chunks in sub modes. +Pointer to face with background color. + +If you do not want any special background color use the face named +default." + :type 'face + :group 'mumamo-display) + +;; Fix-me: use and enhance this +(defcustom mumamo-background-colors '(mumamo-background-chunk-major + mumamo-background-chunk-submode1 + mumamo-background-chunk-submode2 + mumamo-background-chunk-submode3 + mumamo-background-chunk-submode4 + ) + "List of background colors in order of use. +First color is for main major mode chunks, then for submode +chunks, sub-submode chunks etc. Colors are reused in cyclic +order. + +The default colors are choosen so that inner chunks has a more +standing out color the further in you get. This is supposed to +be helpful when you make mistakes and the chunk nesting is not +what you intended. + +Note: Only the light background colors have been set by me. The +dark background colors might currently be unuseful. +Contributions and suggestions are welcome! + +The values in the list should be symbols. Each symbol should either be + + 1: a variable symbol pointing to a face (or beeing nil) + 2: a face symbol + 3: a function with one argument (subchunk depth) returning a + face symbol" + :type '(repeat symbol) + :group 'mumamo-display) + +;;(mumamo-background-color 0) +;;(mumamo-background-color 1) +;;(mumamo-background-color 2) +(defun mumamo-background-color (sub-chunk-depth) + (when (and (not mumamo-no-chunk-coloring) + (or (not (integerp mumamo-chunk-coloring)) ;; Old values + (>= sub-chunk-depth mumamo-chunk-coloring))) + (let* ((idx (when mumamo-background-colors + (mod sub-chunk-depth (length mumamo-background-colors)))) + (sym (when idx (nth idx mumamo-background-colors))) + fac) + (when sym + (when (boundp sym) + (setq fac (symbol-value sym)) + (unless (facep fac) (setq fac nil))) + (unless fac + (when (facep sym) + (setq fac sym))) + (unless fac + (when (fboundp sym) + (setq fac (funcall sym sub-chunk-depth)))) + (when fac + (unless (facep fac) + (setq fac nil))) + fac + )))) + +(defface mumamo-border-face-in + '((t (:inherit font-lock-preprocessor-face :bold t :italic t :underline t))) + "Face for marking borders." + :group 'mumamo-display) + +(defface mumamo-border-face-out + '((t (:inherit font-lock-preprocessor-face :bold t :italic t :underline t))) + "Face for marking borders." + :group 'mumamo-display) + + +(defgroup mumamo-indentation nil + "Customization group for mumamo chunk indentation." + :group 'mumamo) + +(defcustom mumamo-submode-indent-offset 2 + "Indentation of submode relative outer major mode. +If this is nil then indentation first non-empty line in a +subchunk will \(normally) be 0. See however +`mumamo-indent-line-function-1' for special handling of first +line in subsequent subchunks. + +See also `mumamo-submode-indent-offset-0'." + :type '(choice integer + (const :tag "No special")) + :group 'mumamo-indentation) + +(defcustom mumamo-submode-indent-offset-0 0 + "Indentation of submode at column 0. +This value overrides `mumamo-submode-indent-offset' when the +outer major mode above has indentation 0." + :type '(choice integer + (const :tag "No special")) + :group 'mumamo-indentation) + +(defcustom mumamo-indent-major-to-use + '( + ;;(nxhtml-mode html-mode) + (html-mode nxhtml-mode) + ) + "Major mode to use for indentation. +This is normally the major mode specified for the chunk. Here you +can make exceptions." + :type '(repeat + (list (symbol :tag "Major mode symbol specified") + (command :tag "Major mode to use"))) + :group 'mumamo-indentation) + +;;(mumamo-indent-get-major-to-use 'nxhtml-mode) +;;(mumamo-indent-get-major-to-use 'html-mode) +(defun mumamo-indent-get-major-to-use (major depth) + (or (and (= depth 0) + (cadr (assq major mumamo-indent-major-to-use))) + major)) + +(defcustom mumamo-indent-widen-per-major + '( + (php-mode (use-widen)) + (nxhtml-mode (use-widen (html-mumamo-mode nxhtml-mumamo-mode))) + (html-mode (use-widen (html-mumamo-mode nxhtml-mumamo-mode))) + ) + "Wether do widen buffer during indentation. +If not then the buffer is narrowed to the current chunk when +indenting a line in a chunk." + :type '(repeat + (list (symbol :tag "Major mode symbol") + (set + (const :tag "Widen buffer during indentation" use-widen) + (repeat (command :tag "Widen if multi major is any of those")) + ))) + :group 'mumamo-indentation) + + +;;;###autoload +(defgroup mumamo-hi-lock-faces nil + "Faces for hi-lock that are visible in mumamo multiple modes. +This is a workaround for the problem that text properties are +always hidden behind overlay dito. + +This faces are not as visible as those that defines background +colors. However they use underlining so they are at least +somewhat visible." + :group 'hi-lock + :group 'mumamo-display + :group 'faces) + +(defface hi-mumamo-yellow + '((((min-colors 88) (background dark)) + (:underline "yellow1")) + (((background dark)) (:underline "yellow")) + (((min-colors 88)) (:underline "yellow1")) + (t (:underline "yellow"))) + "Default face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-pink + '((((background dark)) (:underline "pink")) + (t (:underline "pink"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-green + '((((min-colors 88) (background dark)) + (:underline "green1")) + (((background dark)) (:underline "green")) + (((min-colors 88)) (:underline "green1")) + (t (:underline "green"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-blue + '((((background dark)) (:underline "light blue")) + (t (:underline "light blue"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-black-b + '((t (:weight bold :underline t))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-blue-b + '((((min-colors 88)) (:weight bold :underline "blue1")) + (t (:weight bold :underline "blue"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-green-b + '((((min-colors 88)) (:weight bold :underline "green1")) + (t (:weight bold :underline "green"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + +(defface hi-mumamo-red-b + '((((min-colors 88)) (:weight bold :underline "red1")) + (t (:weight bold :underline "red"))) + "Face for hi-lock mode." + :group 'mumamo-hi-lock-faces) + + +;; (defcustom mumamo-check-chunk-major-same nil +;; "Check if main major mode is the same as normal mode." +;; :type 'boolean +;; :group 'mumamo) + +;; (customize-option 'mumamo-major-modes) +;;(require 'django) + +(defgroup mumamo-modes nil + "Customization group for mumamo chunk modes." + :group 'mumamo) + +(defcustom mumamo-major-modes + '( + (asp-js-mode + js-mode ;; Not autoloaded in the pretest + javascript-mode + espresso-mode + ecmascript-mode) + (asp-vb-mode + visual-basic-mode) + ;;(css-mode fundamental-mode) + (javascript-mode + js-mode ;; Not autoloaded in the pretest + javascript-mode + espresso-mode + ;;js2-fl-mode + ecmascript-mode) + (java-mode + jde-mode + java-mode) + (groovy-mode + groovy-mode) + ;; For Emacs 22 that do not have nxml by default + ;; Fix me: fallback when autoload fails! + (nxhtml-mode + nxhtml-mode + html-mode) + ) + "Alist for conversion of chunk major mode specifier to major mode. +Each entry has the form + + \(MAJOR-SPEC MAJORMODE ...) + +where the symbol MAJOR-SPEC specifies the code type and should +match the value returned from `mumamo-find-possible-chunk'. The +MAJORMODE symbols are major modes that can be used for editing +that code type. The first available MAJORMODE is the one that is +used. + +The MAJOR-SPEC symbols are used by the chunk definitions in +`define-mumamo-multi-major-mode'. + +The major modes are not specified directly in the chunk +definitions. Instead a chunk definition contains a symbol that +is looked up in this list to find the chunk's major mode. + +The reason for doing it this way is to make it possible to use +new major modes with existing multi major modes. If for example +someone writes a new CSS mode that could easily be used instead +of the current one in `html-mumamo-mode'. + +Lookup in this list is done by `mumamo-major-mode-from-modespec'." + :type '(alist + :key-type (symbol :tag "Symbol for major mode spec in chunk") + :value-type (repeat (choice + (command :tag "Major mode") + (symbol :tag "Major mode (not yet loaded)"))) + ) + :group 'mumamo-modes) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; JIT lock functions + +(defun mumamo-jit-lock-function (start) + "This function is added to `fontification-functions' by mumamo. +START is a parameter given to functions in that hook." + (mumamo-msgfntfy "mumamo-jit-lock-function %s, ff=%s, just-changed=%s" + start + (when start + (save-restriction + (widen) + (get-text-property start 'fontified))) + mumamo-just-changed-major) + ;;(msgtrc "jit-lock-function %s, ff=%s, just-changed=%s" start (get-text-property start 'fontified) mumamo-just-changed-major) + ;;(msgtrc "mumamo-jit-lock-function enter: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + (if mumamo-just-changed-major + (setq mumamo-just-changed-major nil)) + (let ((ret (jit-lock-function start))) + (mumamo-msgfntfy "mumamo-jit-lock-function EXIT %s, ff=%s, just-changed=%s" + start + (when start + (save-restriction + (widen) + (get-text-property start 'fontified))) + mumamo-just-changed-major) + ;;(msgtrc "mumamo-jit-lock-function exit: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + ret)) + +(defun mumamo-jit-lock-register (fun &optional contextual) + "Replacement for `jit-lock-register'. +Avoids refontification, otherwise same. FUN and CONTEXTUAL has +the some meaning as there." + (add-hook 'jit-lock-functions fun nil t) + (when (and contextual jit-lock-contextually) + (set (make-local-variable 'jit-lock-contextually) t)) + + ;;(jit-lock-mode t) + ;; + ;; Replace this with the code below from jit-lock-mode t part: + (setq jit-lock-mode t) + + ;; Mark the buffer for refontification. + ;; This is what we want to avoid in mumamo: + ;;(jit-lock-refontify) + + ;; Install an idle timer for stealth fontification. + (when (and jit-lock-stealth-time (null jit-lock-stealth-timer)) + (setq jit-lock-stealth-timer + (run-with-idle-timer jit-lock-stealth-time t + 'jit-lock-stealth-fontify))) + + ;; Create, but do not activate, the idle timer for repeated + ;; stealth fontification. + (when (and jit-lock-stealth-time (null jit-lock-stealth-repeat-timer)) + (setq jit-lock-stealth-repeat-timer (timer-create)) + (timer-set-function jit-lock-stealth-repeat-timer + 'jit-lock-stealth-fontify '(t))) + + ;; Init deferred fontification timer. + (when (and jit-lock-defer-time (null jit-lock-defer-timer)) + (setq jit-lock-defer-timer + (run-with-idle-timer jit-lock-defer-time t + 'jit-lock-deferred-fontify))) + + ;; Initialize contextual fontification if requested. + (when (eq jit-lock-contextually t) + (unless jit-lock-context-timer + (setq jit-lock-context-timer + (run-with-idle-timer jit-lock-context-time t + 'jit-lock-context-fontify))) + (setq jit-lock-context-unfontify-pos + (or jit-lock-context-unfontify-pos (point-max)))) + + ;; Setup our hooks. + ;;(add-hook 'after-change-functions 'jit-lock-after-change t t) + ;;(add-hook 'after-change-functions 'mumamo-jit-lock-after-change t t) + (add-hook 'after-change-functions 'mumamo-after-change t t) + ;; Set up fontification to call jit: + (let ((ff (reverse fontification-functions))) + (mapc (lambda (f) + ;;(unless (eq f 'jit-lock-function) + (remove-hook 'fontification-functions f t)) + ;;) + ff)) + (add-hook 'fontification-functions 'mumamo-jit-lock-function nil t) + ) + +;; Fix-me: integrate this with fontify-region! +(defvar mumamo-find-chunks-timer nil) +(make-variable-buffer-local 'mumamo-find-chunks-timer) +(put 'mumamo-find-chunks-timer 'permanent-local t) + +(defvar mumamo-find-chunk-delay idle-update-delay) +(make-variable-buffer-local 'mumamo-find-chunk-delay) +(put 'mumamo-find-chunk-delay 'permanent-local t) + +(defun mumamo-stop-find-chunks-timer () + "Stop timer that find chunks." + (when (and mumamo-find-chunks-timer + (timerp mumamo-find-chunks-timer)) + (cancel-timer mumamo-find-chunks-timer)) + (setq mumamo-find-chunks-timer nil)) + +(defun mumamo-start-find-chunks-timer () + "Start timer that find chunks." + (mumamo-stop-find-chunks-timer) + ;; (setq mumamo-find-chunks-timer + ;; (run-with-idle-timer mumamo-find-chunk-delay nil + ;; 'mumamo-find-chunks-in-timer (current-buffer))) + ) + +(defun mumamo-find-chunks-in-timer (buffer) + "Run `mumamo-find-chunks' in buffer BUFFER in a timer." + (mumamo-msgfntfy "mumamo-find-chunks-in-timer %s" buffer) + ;;(message "mumamo-find-chunks-in-timer %s" buffer) + (condition-case err + (when (buffer-live-p buffer) + (with-current-buffer buffer + (mumamo-find-chunks nil "mumamo-find-chunks-in-timer"))) + (error (message "mumamo-find-chunks error: %s" err)))) + + +(defvar mumamo-last-chunk nil) +(make-variable-buffer-local 'mumamo-last-chunk) +(put 'mumamo-last-chunk 'permanent-local t) + +(defvar mumamo-last-change-pos nil) +(make-variable-buffer-local 'mumamo-last-change-pos) +(put 'mumamo-last-change-pos 'permanent-local t) + +;; Fix-me: maybe this belongs to contextual fontification? Eh, +;; no. Unfortunately there is not way to make that handle more than +;; multiple lines. +(defvar mumamo-find-chunk-is-active nil + "Protect from recursive calls.") + +;; Fix-me: temporary things for testing new chunk routines. +(defvar mumamo-find-chunks-level 0) +(setq mumamo-find-chunks-level 0) + +(defvar mumamo-old-tail nil) +(make-variable-buffer-local 'mumamo-old-tail) +(put 'mumamo-old-tail 'permanent-local t) + +(defun mumamo-update-obscure (chunk pos) + "Update obscure cache." + (let ((obscured (overlay-get chunk 'obscured)) + region-info) + (unless (and obscured (= (car obscured) pos)) + (setq region-info (mumamo-get-region-from pos)) + ;;(msgtrc "update-obscure:region-info=%s" region-info) + ;; This should not be a chunk here + (mumamo-put-obscure chunk pos region-info)))) + +(defun mumamo-put-obscure (chunk pos region-or-chunk) + "Cache obscure info." + (assert (overlayp chunk) t) + (when pos (assert (or (markerp pos) (integerp pos)) t)) + (let* ((region-info (if (overlayp region-or-chunk) + (cons (overlay-start region-or-chunk) + (overlay-end region-or-chunk)) + region-or-chunk)) + (obscured (when pos (list pos region-info)))) + ;;(msgtrc "put-obscure:region-info=%s, obscured=%s" region-info obscured) + (when region-info (assert (consp region-info) t)) + (assert (not (overlayp region-info)) t) + (overlay-put chunk 'obscured obscured) + (setq obscured (overlay-get chunk 'obscured)) + ;;(msgtrc " obscured=%s" obscured) + )) + +(defun mumamo-get-region-from (point) + "Return mumamo region values for POINT." + ;; Note: `mumamo-get-region-from-1' is defined in mumamo-regions.el + (when (fboundp 'mumamo-get-region-from-1) + (mumamo-get-region-from-1 point))) + +(defun mumamo-clear-chunk-ppss-cache (chunk) + (overlay-put chunk 'mumamo-ppss-cache nil) + (overlay-put chunk 'mumamo-ppss-last nil) + (overlay-put chunk 'mumamo-ppss-stats nil)) + +(defun mumamo-find-chunks (end tracer) + "Find or create chunks from last known chunk. +Ie, start from the end of `mumamo-last-chunk' if this is +non-nil, otherwise 1. + +If END is nil then continue till end of buffer or until any input +is available. In this case the return value is undefined. + +Otherwise END must be a position in the buffer. Return the +mumamo chunk containing the position. If `mumamo-last-chunk' +ends before END then create chunks upto END." + (when mumamo-multi-major-mode + (let ((chunk (mumamo-find-chunks-1 end tracer)) + region-info) + (when (and end chunk (featurep 'mumamo-regions)) + (setq region-info (mumamo-get-region-from end)) + ;;(msgtrc "find-chunks:region-info=%s" region-info) + (if (overlayp region-info) + (setq chunk region-info) + ;;(overlay-put chunk 'obscured (list end region-info)))) + (mumamo-put-obscure chunk end region-info))) + ;;(msgtrc "find-chunks ret chunk=%s" chunk) + chunk))) + +(defun mumamo-move-to-old-tail (first-check-from) + "Divide the chunk list. +Make it two parts. The first, before FIRST-CHECK-FROM is still +correct but we want to check those after. Put thosie in +`mumamo-old-tail'." + (let ((while-n0 0)) + (while (and (mumamo-while 500 'while-n0 "mumamo-last-chunk first-check-from") + mumamo-last-chunk + first-check-from + (< first-check-from (overlay-end mumamo-last-chunk))) + (overlay-put mumamo-last-chunk 'mumamo-next-chunk mumamo-old-tail) + (setq mumamo-old-tail mumamo-last-chunk) + (overlay-put mumamo-old-tail 'mumamo-is-new nil) + (when nil ;; For debugging + (overlay-put mumamo-old-tail + 'face + (list :background + (format "red%d" (overlay-get mumamo-old-tail 'mumamo-depth))))) + (setq mumamo-last-chunk + (overlay-get mumamo-last-chunk 'mumamo-prev-chunk))))) + +(defun mumamo-delete-empty-chunks-at-end () + ;; fix-me: later? Delete empty chunks at end, will be recreated if really needed + (let ((while-n1 0)) + (while (and (mumamo-while 500 'while-n1 "mumamo-last-chunk del empty chunks") + mumamo-last-chunk + ;;(= (point-max) (overlay-end mumamo-last-chunk)) + (= (overlay-end mumamo-last-chunk) (overlay-start mumamo-last-chunk))) + ;;(msgtrc "delete-overlay at end") + (delete-overlay mumamo-last-chunk) + (setq mumamo-last-chunk (overlay-get mumamo-last-chunk 'mumamo-prev-chunk)) + (when mumamo-last-chunk (overlay-put mumamo-last-chunk 'mumamo-next-chunk nil))))) + + +(defun mumamo-delete-chunks-upto (ok-pos) + "Delete old chunks upto OK-POS." + (or (not mumamo-old-tail) + (overlay-buffer mumamo-old-tail) + (setq mumamo-old-tail nil)) + (let ((while-n2 0)) + (while (and (mumamo-while 500 'while-n2 "mumamo-old-tail") + (and mumamo-old-tail (< (overlay-start mumamo-old-tail) ok-pos))) + (mumamo-mark-for-refontification (overlay-start mumamo-old-tail) (overlay-end mumamo-old-tail)) + ;;(msgtrc "find-chunks:ok-pos=%s, not eq delete %s" ok-pos mumamo-old-tail) + (delete-overlay mumamo-old-tail) + (setq mumamo-old-tail (overlay-get mumamo-old-tail 'mumamo-next-chunk)) + (or (not mumamo-old-tail) + (overlay-buffer mumamo-old-tail) + (setq mumamo-old-tail nil))))) + +(defun mumamo-reuse-old-tail-head () + ;;(msgtrc "reusing %S" mumamo-old-tail) + (setq mumamo-last-chunk mumamo-old-tail) + (overlay-put mumamo-last-chunk 'mumamo-is-new t) + (mumamo-clear-chunk-ppss-cache mumamo-last-chunk) + (overlay-put mumamo-last-chunk 'face (mumamo-background-color (overlay-get mumamo-last-chunk 'mumamo-depth))) + (setq mumamo-old-tail (overlay-get mumamo-old-tail 'mumamo-next-chunk))) + +(defun mumamo-old-tail-fits (this-new-values) + (and mumamo-old-tail + (overlay-buffer mumamo-old-tail) + (mumamo-new-chunk-equal-chunk-values mumamo-old-tail this-new-values))) + +(defun mumamo-find-chunks-1 (end tracer) ;; min max) + ;; Note: This code must probably be reentrant. The globals changed + ;; here are `mumamo-last-chunk' and `mumamo-old-tail'. They must be + ;; handled as a pair. + (mumamo-msgfntfy "") + (setq mumamo-find-chunks-level (1+ mumamo-find-chunks-level)) + (unless (and (overlayp mumamo-last-chunk) (overlay-buffer mumamo-last-chunk)) (setq mumamo-last-chunk nil)) + (save-restriction + (widen) + (let* ((mumamo-find-chunks-1-active t) + (here (point)) + ;; Any changes? + (change-min (car mumamo-last-change-pos)) + (change-max (cdr mumamo-last-change-pos)) + (chunk-at-change-min (when change-min (mumamo-get-existing-new-chunk-at change-min nil))) + (chunk-at-change-min-start (when chunk-at-change-min (overlay-start chunk-at-change-min))) + ;; Check if change is near border + (this-syntax-min-max + (when chunk-at-change-min + (mumamo-update-obscure chunk-at-change-min chunk-at-change-min-start) + (mumamo-chunk-syntax-min-max chunk-at-change-min nil))) + (this-syntax-min (car this-syntax-min-max)) + (in-min-border (when this-syntax-min (>= this-syntax-min change-min))) + (first-check-from (if chunk-at-change-min + (if (or in-min-border + ;; Fix-me: 20? + (> 20 (- change-min chunk-at-change-min-start))) + (max 1 + (- chunk-at-change-min-start 1)) + chunk-at-change-min-start) + (when change-min + (goto-char change-min) + (skip-chars-backward "^\n") + (unless (bobp) (backward-char)) + (prog1 (point) (goto-char here)))))) + (when (and chunk-at-change-min (= 0 (- (overlay-end chunk-at-change-min) + (overlay-start chunk-at-change-min)))) + (assert in-min-border)) ;; 0 len must be in border + (setq mumamo-last-change-pos nil) + (when chunk-at-change-min + (mumamo-move-to-old-tail first-check-from) + (mumamo-delete-empty-chunks-at-end)) + ;; Now mumamo-last-chunk is the last in the top chain and + ;; mumamo-old-tail the first in the bottom chain. + + (let* ( + ;;(last-chunk-is-closed (when mumamo-last-chunk (overlay-get mumamo-last-chunk 'mumamo-is-closed))) + (last-chunk-is-closed t) + (ok-pos (or (and mumamo-last-chunk + (- (overlay-end mumamo-last-chunk) + ;;(or (and last-chunk-is-closed 1) + (or (and (/= (overlay-end mumamo-last-chunk) + (1+ (buffer-size))) + 1) + 0))) + 0)) + (end-param end) + (end (or end (point-max))) + this-new-values + this-new-chunk + prev-chunk + first-change-pos + interrupted + (while-n3 0)) + (when (>= ok-pos end) + (setq this-new-chunk (mumamo-get-existing-new-chunk-at end nil)) + (unless this-new-chunk + (error "Could not find new chunk ok-pos-new=%s > end=%s (ovls at end=%s), level=%d, old-tail=%s, %S" + ok-pos end (overlays-in end end) + mumamo-find-chunks-level mumamo-old-tail tracer))) + (unless this-new-chunk + (save-match-data + (unless mumamo-find-chunk-is-active + ;;(setq mumamo-find-chunk-is-active t) + (mumamo-stop-find-chunks-timer) + (mumamo-save-buffer-state nil + (progn + + ;; Loop forward until end or buffer end ... + (while (and (mumamo-while 1500 'while-n3 "until end") + (or (not end) + (<= ok-pos end)) + ;;(prog1 t (msgtrc "ok-pos=%s in while" ok-pos)) + (< ok-pos (point-max)) + (not (setq interrupted (and (not end) + (input-pending-p))))) + ;; Narrow to speed up. However the chunk divider may be + ;; before ok-pos here. Assume that the marker is not + ;; longer than 200 chars. fix-me. + (narrow-to-region (max (- ok-pos 200) 1) + (1+ (buffer-size))) + ;; If this was after a change within one chunk then tell that: + (let ((use-change-max (when (and change-max + chunk-at-change-min + (overlay-buffer chunk-at-change-min) + (< change-max + (overlay-end chunk-at-change-min)) + (or (not mumamo-last-chunk) + (> change-max (overlay-end mumamo-last-chunk)))) + change-max)) + (use-chunk-at-change-min (when (or (not mumamo-last-chunk) + (not (overlay-buffer mumamo-last-chunk)) + (not chunk-at-change-min) + (not (overlay-buffer chunk-at-change-min)) + (> (overlay-end chunk-at-change-min) + (overlay-end mumamo-last-chunk))) + chunk-at-change-min + ))) + (setq this-new-values (mumamo-find-next-chunk-values + mumamo-last-chunk + first-check-from + use-change-max + use-chunk-at-change-min))) + (if (not this-new-values) + (setq ok-pos (point-max)) + (setq first-check-from nil) + (setq ok-pos (or (mumamo-new-chunk-value-max this-new-values) ;;(overlay-end this-chunk) + (point-max))) + ;;(msgtrc "ok-pos=%s, point-max=%s max=%s" ok-pos (point-max) (mumamo-new-chunk-value-max this-new-values)) + ;; With the new organization all chunks are created here. + (if (mumamo-old-tail-fits this-new-values) + (mumamo-reuse-old-tail-head) + (mumamo-delete-chunks-upto ok-pos) + ;; Create chunk and chunk links + (setq mumamo-last-chunk (mumamo-new-create-chunk this-new-values)) + ;;(setq last-chunk-is-closed (overlay-get mumamo-last-chunk 'mumamo-is-closed)) + (unless first-change-pos + (setq first-change-pos (mumamo-new-chunk-value-min this-new-values)))))) + (setq this-new-chunk mumamo-last-chunk))) + (widen) + (when (or interrupted + (and mumamo-last-chunk + (overlayp mumamo-last-chunk) + (overlay-buffer mumamo-last-chunk) + (buffer-live-p (overlay-buffer mumamo-last-chunk)) + (< (overlay-end mumamo-last-chunk) (point-max)))) + (mumamo-start-find-chunks-timer) + ) + (when first-change-pos + (setq jit-lock-context-unfontify-pos + (if jit-lock-context-unfontify-pos + (min jit-lock-context-unfontify-pos first-change-pos) + first-change-pos)))) + (goto-char here) + (setq mumamo-find-chunk-is-active nil))) + + ;; fix-me: continue here + (when chunk-at-change-min (mumamo-clear-chunk-ppss-cache chunk-at-change-min)) + (setq mumamo-find-chunks-level (1- mumamo-find-chunks-level)) + ;; Avoid empty overlays at the end of the buffer. Those can + ;; come from for example deleting to the end of the buffer. + (when this-new-chunk + ;; Fix-me: can this happen now? + (setq prev-chunk (overlay-get this-new-chunk 'mumamo-prev-chunk)) + (when (and prev-chunk + (overlay-buffer prev-chunk) + (= (overlay-start this-new-chunk) (overlay-end this-new-chunk)) + (= (overlay-start prev-chunk) (overlay-end prev-chunk))) + (overlay-put prev-chunk 'mumamo-next-chunk nil) + (overlay-put prev-chunk 'mumamo-prev-chunk nil) + ;;(msgtrc "find-chunks:deleting this-new-chunk %s" this-new-chunk) + (delete-overlay this-new-chunk) + (setq this-new-chunk prev-chunk) + ) + (while (and mumamo-old-tail + (overlay-buffer mumamo-old-tail) + (= (overlay-start mumamo-old-tail) (overlay-end mumamo-old-tail))) + (assert (not (eq mumamo-old-tail (overlay-get mumamo-old-tail 'mumamo-next-chunk))) t) + (setq prev-chunk mumamo-old-tail) + (setq mumamo-old-tail (overlay-get mumamo-old-tail 'mumamo-next-chunk)) + ;;(msgtrc "mumamo-find-chunks-1:after mumamo-old-tail=%s" mumamo-old-tail) + (delete-overlay prev-chunk) + ) + ) + ;;(unless (overlay-get mumamo-last-chunk 'mumamo-is-closed) + (unless t ;(= (overlay-end mumamo-last-chunk) (save-restriction (widen) (point-max))) + ;; Check that there are no left-over old chunks + (save-restriction + (widen) + (dolist (o (overlays-in (point-min) (point-max))) + (when (and (overlay-get o 'mumamo-depth) + (not (overlay-get o 'mumamo-is-new))) + (error "mumamo-find-chunks: left over chunk: %s end=%s, last-chunk=%s" o end mumamo-last-chunk))))) + (when end-param + ;;(msgtrc "find-chunks:Exit.end-param=%s, this-new-chunk=%s, point-max=%s, last=%s" end-param this-new-chunk (point-max) mumamo-last-chunk) + (let* ((ret this-new-chunk) + (ret-beg (overlay-start ret)) + (ret-end (overlay-end ret))) + (unless (and (<= ret-beg end-param) + (<= end-param ret-end)) + (error "mumamo-find-chunks: Bad ret=%s, end=%s" ret end-param)) + ;;(msgtrc "find-chunks=>%S" ret) + ret)))))) + +(defun mumamo-find-chunk-after-change (min max) + "Save change position after a buffer change. +This should be run after a buffer change. For MIN see +`after-change-functions'." + ;; Fix-me: Maybe use a list of all min, max instead? + (mumamo-start-find-chunks-timer) + ;;(msgtrc "(mumamo-find-chunk-after-change %s %s)" min max) + (setq min (copy-marker min nil)) + (setq max (copy-marker max t)) + (setq mumamo-last-change-pos + (if mumamo-last-change-pos + (let* ((old-min (car mumamo-last-change-pos)) + (old-max (cdr mumamo-last-change-pos)) + (new-min (min min old-min)) + (new-max (max max old-max))) + (cons new-min new-max)) + (cons min max)))) + +(defun mumamo-after-change (min max old-len) + "Everything that needs to be done in mumamo after a change. +This is run in the `after-change-functions' hook. For MIN, MAX +and OLD-LEN see that variable." + ;;(msgtrc "mumamo-after-change BEGIN min/max/old-len=%s/%s/%s" min max old-len) + ;;(msgtrc "mumamo-after-change BEGIN") + (mumamo-find-chunk-after-change min max) + (mumamo-jit-lock-after-change min max old-len) + (mumamo-msgfntfy "mumamo-after-change EXIT") + ;;(msgtrc "mumamo-after-change EXIT mumamo-last-change-pos=%s" mumamo-last-change-pos) + ) + +(defun mumamo-jit-lock-after-change (min max old-len) + ;; Fix-me: Should not this be on + ;; jit-lock-after-change-externd-region-functions?? + "Replacement for `jit-lock-after-change'. +Does the nearly the same thing as that function, but takes +care of that there might be different major modes at MIN and MAX. +It also marks for refontification only in the current mumamo chunk. + +OLD-LEN is the pre-change length. + +Jit-lock after change functions is organized this way: + +`jit-lock-after-change' (doc: Mark the rest of the buffer as not +fontified after a change) is added locally to the hook +`after-change-functions'. This function runs +`jit-lock-after-change-extend-region-functions'." + (when (and jit-lock-mode (not memory-full)) + (mumamo-msgfntfy "mumamo-jit-lock-after-change ENTER %s %s %s" min max old-len) + ;; Why is this nil?: + (mumamo-msgfntfy " mumamo-jit-lock-after-change: font-lock-extend-after-change-region-function=%s" font-lock-extend-after-change-region-function) + (let* ((ovl-min (mumamo-get-existing-new-chunk-at min nil)) + (ovl-max (when (or (not ovl-min) + (< (overlay-end ovl-min) max)) + (mumamo-get-existing-new-chunk-at max nil))) + (major-min (when ovl-min (mumamo-chunk-major-mode ovl-min))) + (major-max (when ovl-max (mumamo-chunk-major-mode ovl-max))) + (r-min nil) + (r-max nil) + (new-min min) + (new-max max)) + (if (and major-min (eq major-min major-max)) + (setq r-min + (when major-min + (mumamo-jit-lock-after-change-1 min max old-len major-min))) + (setq r-min + (when major-min + (mumamo-jit-lock-after-change-1 min max old-len major-min))) + (setq r-max + (when major-max + (mumamo-jit-lock-after-change-1 min max old-len major-max)))) + (mumamo-msgfntfy "mumamo-jit-lock-after-change r-min,max=%s,%s major-min,max=%s,%s" r-min r-max major-min major-max) + (when r-min + (setq new-min (min new-min (car r-min))) + (setq new-max (max new-max (cdr r-min)))) + (when r-max + (setq new-min (min new-min (car r-max))) + (setq new-max (max new-max (cdr r-max)))) + (setq new-min (max new-min (point-min))) + (setq new-max (min new-max (point-max))) + ;; Make sure we change at least one char (in case of deletions). + (setq new-max (min (max new-max (1+ new-min)) (point-max))) + (mumamo-msgfntfy "mumamo-jit-lock-after-change new-min,max=%s,%s" new-min new-max) + (mumamo-mark-for-refontification new-min new-max) + + ;; Mark the change for deferred contextual refontification. + ;;(setq jit-lock-context-unfontify-pos nil) (setq message-log-max t) + (when jit-lock-context-unfontify-pos + (setq jit-lock-context-unfontify-pos + ;; Here we use `start' because nothing guarantees that the + ;; text between start and end will be otherwise refontified: + ;; usually it will be refontified by virtue of being + ;; displayed, but if it's outside of any displayed area in the + ;; buffer, only jit-lock-context-* will re-fontify it. + (min jit-lock-context-unfontify-pos new-min)) + ;;(with-current-buffer (get-buffer "*Messages*") (erase-buffer)) + (mumamo-msgfntfy "mumamo-jit-lock-after-change EXIT unfontify-pos=%s" jit-lock-context-unfontify-pos) + ;;(message "mumamo-jit-lock-after-change.unfontify-pos=%s" jit-lock-context-unfontify-pos) + )))) +;;(min jit-lock-context-unfontify-pos jit-lock-start)))))) +;;(put 'mumamo-jit-lock-after-change 'permanent-local-hook t) +(put 'mumamo-after-change 'permanent-local-hook t) + +(defun mumamo-jit-lock-after-change-1 (min max old-len major) + "Extend the region the same way jit-lock does it. +This function tries to extend the region between MIN and MAX the +same way jit-lock does it after a change. OLD-LEN is the +pre-change length. + +The extending of the region is done as if MAJOR was the major +mode." + (mumamo-with-major-mode-fontification major + `(progn + (let ((jit-lock-start ,min) + (jit-lock-end ,max)) + ;;(mumamo-msgfntfy "mumamo-mumamo-jit-lock-after-change-1 jlacer=%s" ,jit-lock-after-change-extend-region-functions) + (mumamo-with-buffer-prepared-for-jit-lock + ;;(font-lock-extend-jit-lock-region-after-change ,min ,max ,old-len) + (run-hook-with-args 'jit-lock-after-change-extend-region-functions min max old-len) + ;;(setq jit-lock-end (min (max jit-lock-end (1+ min)) (point-max))) + +;;; ;; Just run the buffer local function: +;;; (dolist (extend-fun jit-lock-after-change-extend-region-functions) +;;; (when (fboundp extend-fun) +;;; (funcall extend-fun ,min ,max ,old-len))) + ) + (setq min jit-lock-start) + (setq max jit-lock-end) + ;;(syntax-ppss-flush-cache min) + ))) + (mumamo-msgfntfy "mumamo-mumamo-jit-lock-after-change-1 EXIT %s" (cons min max)) + (cons min max)) + +(defun mumamo-mark-chunk () + "Mark chunk and move point to beginning of chunk." + (interactive) + (let ((chunk (mumamo-find-chunks (point) "mumamo-mark-chunk"))) + (unless chunk (error "There is no MuMaMo chunk here")) + (goto-char (overlay-start chunk)) + (push-mark (overlay-end chunk) t t))) + +(defun mumamo-narrow-to-chunk-inner () + (interactive) + (let* ((chunk (mumamo-find-chunks (point) "mumamo-narrow-to-chunk-innner")) + (syntax-min-max (mumamo-chunk-syntax-min-max chunk t)) + (syntax-min (car syntax-min-max)) + (syntax-max (cdr syntax-min-max))) + (narrow-to-region syntax-min syntax-max))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Font lock functions + +(defadvice hi-lock-set-pattern (around use-overlays activate) + (if mumamo-multi-major-mode + (let ((font-lock-fontified nil)) + ad-do-it) + ad-do-it)) + +;;;###autoload +(defun mumamo-mark-for-refontification (min max) + "Mark region between MIN and MAX for refontification." + ;;(msgtrc "mark-for-refontification A min,max=%s,%s point-min,max=%s,%s modified=%s" min max (point-min) (point-max) (buffer-modified-p) ) + ;;(mumamo-backtrace "mark-for-refontification") + (mumamo-msgfntfy "mumamo-mark-for-refontification A min,max=%s,%s point-min,max=%s,%s modified=%s" min max (point-min) (point-max) (buffer-modified-p) ) + (assert (<= min max)) + (when (< min max) + (save-restriction + (widen) + (mumamo-msgfntfy "mumamo-mark-for-refontification B min,max=%s,%s point-min,max=%s,%s modified=%s" min max (point-min) (point-max) (buffer-modified-p) ) + ;;(mumamo-with-buffer-prepared-for-jit-lock + (mumamo-save-buffer-state nil + (put-text-property min max 'fontified nil) + )))) + + +;; Fix me: The functions in this list must be replaced by variables +;; pointing to anonymous functions for buffer local values of +;; fontification keywords to be supported. And that is of course +;; necessary for things like hi-lock etc. (Or..., perhaps some kind of +;; with-variable-values... as RMS suggested once... but that will not +;; help here...) +;; +;; Seems like font-lock-add-keywords must be advised... +(defvar mumamo-internal-major-modes-alist nil + "Alist with info for different major modes. +Internal use only. This is automatically set up by +`mumamo-get-major-mode-setup'.") +(setq mumamo-internal-major-modes-alist nil) +(put 'mumamo-internal-major-modes-alist 'permanent-local t) + +(defvar mumamo-ppss-last-chunk nil + "Internal variable used to avoid unnecessary flushing.") +(defvar mumamo-ppss-last-major nil + "Internal variable used to avoid unnecessary flushing.") + +;;(mumamo-get-major-mode-substitute 'nxhtml-mode 'fontification) +;;(mumamo-get-major-mode-substitute 'nxhtml-mode 'indentation) +;;(mumamo-get-major-mode-substitute 'css-mode 'fontification) +;;(mumamo-get-major-mode-substitute 'css-mode 'indentation) +;; (assq 'nxml-mode mumamo-major-mode-substitute) +(defconst mumamo-major-mode-substitute + '( + (nxhtml-mode (html-mode nxhtml-mode)) + ;;(nxhtml-mode (html-mode)) + (nxhtml-genshi-mode (html-mode nxhtml-mode)) + (nxhtml-mjt-mode (html-mode nxhtml-mode)) + (nxml-mode (sgml-mode)) + ) + "Major modes substitute to use for fontification and indentation. +The entries in this list has either of the formats + + \(MAJOR (FONT-MODE INDENT-MODE)) + \(MAJOR (FONT-MODE)) + +where major is the major mode in a mumamo chunk and FONT-MODE is +the major mode for fontification of that chunk and INDENT-MODE is +dito for indentation. In the second form the same mode is used +for indentation as for fontification.") + +;;(mumamo-get-major-mode-substitute 'nxhtml-mode 'indentation) +;;(mumamo-get-major-mode-substitute 'nxhtml-mode 'fontification) +(defun mumamo-get-major-mode-substitute (major for-what) + "For major mode MAJOR return major mode to use for FOR-WHAT. +FOR-WHAT can be either 'fontification or indentation. + +mumamo must handle fontification and indentation for `major-mode' +by using other major mode if the functions for this in +`major-mode' are not compatible with mumamo. This functions +looks in the table `mumamo-major-mode-substitute' for get major +mode to use." + ;;(when (eq for-what 'indentation) (message "subst.major=%s" major)) + (let ((m (assq major mumamo-major-mode-substitute)) + ret-major) + (if (not m) + (setq ret-major major) + (setq m (nth 1 m)) + (setq ret-major + (cond + ((eq for-what 'fontification) + (nth 0 m)) + ((eq for-what 'indentation) + (nth 1 m)) + (t + (mumamo-display-error 'mumamo-get-major-mode-substitute + "Bad parameter, for-what=%s" for-what)))) + (unless ret-major (setq ret-major major))) + (unless (commandp ret-major) (setq ret-major 'mumamo-bad-mode)) + ;;(when (eq for-what 'indentation) (message "ret.ind=%s, major=%s, m=%s" ret major m)) + ret-major)) + +(defun mumamo-assert-fontified-t (start end) + "Assert that the region START to END has 'fontified t." + (let ((start-ok (get-text-property start 'fontified)) + (first-not-ok + (next-single-property-change (1+ start) 'fontified nil end))) + (when (not start-ok) + (message "==== mumamo-assert-fontified-t %s-%s start not ok" start end)) + (when (not (= first-not-ok end)) + (message "==== mumamo-assert-fontified-t %s-%s first not ok=%s" start end first-not-ok)))) + +;; Keep this separate for easier debugging. +(defun mumamo-do-fontify (start end verbose chunk-syntax-min chunk-syntax-max chunk-major) + "Fontify region between START and END. +If VERBOSE is non-nil then print status messages during +fontification. + +CHUNK-SYNTAX-MIN, CHUNK-SYNTAX-MAX and CHUNK-MAJOR are the +chunk's min point, max point and major mode. + +During fontification narrow the buffer to the chunk to make +syntactic fontification work. If chunks starts or end with \" +then the first respective last char then exclude those chars from +from the narrowed part, since otherwise the syntactic +fontification can't find out where strings start and stop. + +Note that this function is run under +`mumamo-with-major-mode-fontification'. + +This function takes care of `font-lock-dont-widen' and +`font-lock-extend-region-functions'. Normally +`font-lock-default-fontify-region' does this, but that function +is not called when mumamo is used! + +PS: `font-lock-fontify-syntactically-region' is the main function +that does syntactic fontification." + ;;(msgtrc "mumamo-do-fontify enter: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + ;;(msgtrc "mumamo-do-fontify <<<<<<< %s %s %s %s %s %s" start end verbose chunk-syntax-min chunk-syntax-max chunk-major) + ;;(msgtrc "font-lock-keywords=%S" font-lock-keywords) + ;;(mumamo-assert-fontified-t start end) + (mumamo-condition-case err + (let* ((font-lock-dont-widen t) + (font-lock-extend-region-functions + ;; nil + font-lock-extend-region-functions + ) + ;; Extend like in `font-lock-default-fontify-region': + (funs font-lock-extend-region-functions) + (font-lock-beg (max chunk-syntax-min start)) + (font-lock-end (min chunk-syntax-max end)) + (while-n1 0)) + ;;(while (and (> 500 (setq while-n1 (1+ while-n1))) + (while (and (mumamo-while 500 'while-n1 "funs") + funs) + (setq funs (if (or (not (funcall (car funs))) + (eq funs font-lock-extend-region-functions)) + (cdr funs) + ;; If there's been a change, we should go through + ;; the list again since this new position may + ;; warrant a different answer from one of the fun + ;; we've already seen. + font-lock-extend-region-functions))) + ;; But we must restrict to the chunk here: + (let ((new-start (max chunk-syntax-min font-lock-beg)) + (new-end (min chunk-syntax-max font-lock-end))) + ;;(msgtrc "do-fontify %s %s, chunk-syntax-min,max=%s,%s, new: %s %s" start end chunk-syntax-min chunk-syntax-max new-start new-end) + ;; A new condition-case just to catch errors easier: + (when (< new-start new-end) + (mumamo-condition-case err + (save-restriction + ;;(when (and (>= 625 (point-min)) (<= 625 (point-max))) (msgtrc "multi at 625=%s" (get-text-property 625 'font-lock-multiline))) + ;;(msgtrc "(narrow-to-region %s %s)" chunk-syntax-min chunk-syntax-max) + (when (< chunk-syntax-min chunk-syntax-max) + (narrow-to-region chunk-syntax-min chunk-syntax-max) + ;; Now call font-lock-fontify-region again but now + ;; with the chunk font lock parameters: + (setq font-lock-syntactically-fontified (1- new-start)) + (mumamo-msgfntfy "ENTER font-lock-fontify-region %s %s %s" new-start new-end verbose) + ;;(msgtrc "mumamo-do-fontify: font-lock-keywords-only =%s in buffer %s, def=%s" font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + (let (font-lock-extend-region-functions) + (font-lock-fontify-region new-start new-end verbose)) + (mumamo-msgfntfy "END font-lock-fontify-region %s %s %s" new-start new-end verbose) + ) + ) + (error + (mumamo-display-error 'mumamo-do-fontify-2 + "mumamo-do-fontify m=%s, s/e=%s/%s syn-min/max=%s/%s: %s" + chunk-major + start end + chunk-syntax-min chunk-syntax-max + (error-message-string err))))))) + (error + (mumamo-display-error 'mumamo-do-fontify + "mumamo-do-fontify m=%s, s=%s, e=%s: %s" + chunk-major start end (error-message-string err))) + ) + (mumamo-msgfntfy "mumamo-do-fontify exit >>>>>>> %s %s %s %s %s %s" start end verbose chunk-syntax-min chunk-syntax-max chunk-major) + ;;(msgtrc "mumamo-do-fontify exit: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + ) + +(defun mumamo-do-unfontify (start end) + "Unfontify region between START and END." + (mumamo-condition-case err + (font-lock-unfontify-region start end) + (error + (mumamo-display-error 'mumamo-do-unfontify "%s" + (error-message-string err))))) + +(defun mumamo-fontify-region-with (start end verbose major chunk-syntax-min chunk-syntax-max) + "Fontify from START to END. +If VERBOSE is non-nil then print status messages during +fontification. + +Do the fontification as in major mode MAJOR. + +Narrow to region CHUNK-SYNTAX-MIN and CHUNK-SYNTAX-MAX during +fontification." + ;; The text property 'fontified is always t here due to the way + ;; jit-lock works! + + ;;(msgtrc "fontify-region-with %s %s %s %s, ff=%s" start end verbose major (get-text-property start 'fontified)) + ;;(mumamo-assert-fontified-t start end) + ;;(msgtrc "mumamo-fontify-region-with enter: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + (mumamo-condition-case err + (progn + ;;(msgtrc "mumamo-fontify-region-with: font-lock-keywords-only =%s in buffer %s, def=%s" font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + (mumamo-with-major-mode-fontification major + `(mumamo-do-fontify ,start ,end ,verbose ,chunk-syntax-min ,chunk-syntax-max major)) + ) + (error + (mumamo-display-error 'mumamo-fontify-region-with "%s" + (error-message-string err)))) + ;;(msgtrc "mumamo-fontify-region-with exit: font-lock-keywords-only def=%s" (default-value 'font-lock-keywords-only)) + ) + +(defun mumamo-unfontify-region-with (start end major) + "Unfontify from START to END as in major mode MAJOR." + (mumamo-msgfntfy "mumamo-unfontify-region-with %s %s %s, ff=%s" + start + end + major + (when start + (save-restriction + (widen) + (get-text-property start 'fontified)))) + (mumamo-with-major-mode-fontification major + `(mumamo-do-unfontify ,start ,end))) + + + +(defun mumamo-backtrace (label) + (msgtrc "%s:backtrace in START buffer %s <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n%s" + label (current-buffer) (with-output-to-string (backtrace))) + (msgtrc "%s:backtrace in END buffer %s >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" label (current-buffer))) + +(defun mumamo-unfontify-buffer () + "Unfontify buffer. +This function is called when the minor mode function +`font-lock-mode' is turned off. \(It is the value of +`font-lock-unfontify-uffer-function')." + (when (and mumamo-multi-major-mode + (not (and (boundp 'mumamo-find-chunks-1-active) + mumamo-find-chunks-1-active))) + ;;(mumamo-backtrace "unfontify-buffer") + ;;(msgtrc "mumamo-unfontify-buffer:\n%s" (with-output-to-string (backtrace))) + (save-excursion + (save-restriction + (widen) + (let ((ovls (overlays-in (point-min) (point-max))) + (main-major (mumamo-main-major-mode))) + (dolist (o ovls) + (when (overlay-get o 'mumamo-is-new) + (let ((major (mumamo-chunk-major-mode o))) + (when major + (unless (mumamo-fun-eq major main-major) + (mumamo-unfontify-chunk o)) + ;;(msgtrc "delete-overlay 1") + (delete-overlay o) + )))) + (mumamo-unfontify-region-with (point-min) (point-max) + (mumamo-main-major-mode))))))) + + +(defun mumamo-fontify-buffer () + "For `font-lock-fontify-buffer-function' call. +Not sure when this normally is done. However some functions call +this to ensure that the whole buffer is fontified." + (mumamo-msgfntfy "===> mumamo-fontify-buffer-function called") + ;;(font-lock-default-fontify-buffer) + (unless mumamo-set-major-running + ;; This function is normally not called, but when new patterns + ;; have been added by hi-lock it will be called. In this case we + ;; need to make buffer local fontification variables: + (set (make-local-variable 'mumamo-internal-major-modes-alist) nil) + (jit-lock-refontify))) + + +(defun mumamo-unfontify-chunk (chunk) ; &optional start end) + "Unfontify mumamo chunk CHUNK." + (let* ((major (mumamo-chunk-major-mode chunk)) + ;;(start (overlay-start chunk)) + ;;(end (overlay-end chunk)) + (syntax-min-max (mumamo-chunk-syntax-min-max chunk t)) + (syntax-min (car syntax-min-max)) + (syntax-max (cdr syntax-min-max)) + (font-lock-dont-widen t)) + (when (< syntax-min syntax-max) + (save-restriction + (narrow-to-region syntax-min syntax-max) + (mumamo-unfontify-region-with syntax-min syntax-max major))))) + +(defun mumamo-fontify-region (start end &optional verbose) + "Fontify between START and END. +Take the major mode chunks into account while doing this. + +If VERBOSE do the verbously. + +The value of `font-lock-fontify-region-function' when +mumamo is used is this function." + (mumamo-msgfntfy "++++++ mumamo-fontify-regionX %s %s %s, skip=%s" start end verbose mumamo-just-changed-major) + ;;(msgtrc "mumamo-fontify-region: font-lock-keywords-only =%s in buffer %s, def=%s" font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + ;;(mumamo-assert-fontified-t start end) + ;; If someone else tries to fontify the buffer ... + (if (and mumamo-just-changed-major + ;; The above variable is reset in `post-command-hook' so + ;; check if we are in a recursive search. (Note: There are + ;; other situation when this can occur. It might be best to + ;; remove this test later, or make it optional.) + ;; + ;; skip the test for now: + nil + (= 0 (recursion-depth))) + (mumamo-display-error 'mumamo-fontify-region + "Just changed major, should not happen") + (mumamo-condition-case err + (mumamo-fontify-region-1 start end verbose) + (error + (mumamo-display-error 'mumamo-fontify-region "%s" + (error-message-string err)))))) + +(defconst mumamo-dbg-pretend-fontified nil + "Set this to t to be able to debug more easily. +This is for debugging `mumamo-fontify-region-1' more easily by +just calling it. It will make that function believe that the text +has a non-nil 'fontified property.") + +(defun mumamo-exc-mode (chunk) + "Return sub major mode for CHUNK. +If chunk is a main major mode chunk return nil, otherwise return +the major mode for the chunk." + (let ((major (mumamo-chunk-major-mode chunk))) + (unless (mumamo-fun-eq major (mumamo-main-major-mode)) + major))) + +;;; Chunk in chunk needs push/pop relative prev chunk +(defun mumamo-chunk-push (chunk prop val) + (let* ((prev-chunk (overlay-get chunk 'mumamo-prev-chunk)) + (prev-val (when prev-chunk (overlay-get prev-chunk prop)))) + (overlay-put chunk prop (cons val prev-val)))) +(defun mumamo-chunk-pop (chunk prop) + (overlay-put chunk prop (cdr (overlay-get (overlay-get chunk 'mumamo-prev-chunk) + prop)))) + +;; (defvar mumamo-chunks-to-remove nil +;; "Internal. Chunk overlays marked for removal.") +;; (make-variable-buffer-local 'mumamo-chunks-to-remove) + +(defun mumamo-flush-chunk-syntax (chunk chunk-min chunk-max) + "Flush syntax cache for chunk CHUNK. +This includes removing text property 'syntax-table between +CHUNK-MIN and CHUNK-MAX." + ;; syntax-ppss-flush-cache + (overlay-put chunk 'syntax-ppss-last nil) + (overlay-put chunk 'syntax-ppss-cache nil) + (overlay-put chunk 'syntax-ppss-stats nil) + (mumamo-save-buffer-state nil + (remove-list-of-text-properties chunk-min chunk-max '(syntax-table)))) + +;; Fix-me: If I open nxhtml-changes.html and then go to the bottom of +;; the file at once syntax-ppss seems to be upset. It is however cured +;; by doing some change above the region that is badly fontified. +(defun mumamo-fontify-region-1 (start end verbose) + "Fontify region between START and END. +If VERBOSE is non-nil then print status messages during +fontification. + +This is called from `mumamo-fontify-region' which is the value of +`font-lock-fontify-region-function' when mumamo is used. \(This +means that it ties into the normal font lock framework in Emacs.) + +Note: The purpose of extracting this function from +`mumamo-fontify-region' \(which is the only place where it is +called) is to make debugging easier. Edebug will without this +function just step over the `condition-case' in +`mumamo-fontify-region'. + +The fontification is done in steps: + +- First a mumamo chunk is found or created at the start of the + region with `mumamo-get-chunk-at'. +- Then this chunk is fontified according to the major mode for + that chunk. +- If the chunk did not encompass the whole region then this + procedure is repeated with the rest of the region. + +If some mumamo chunk in the region between START and END has been +marked for removal \(for example by `mumamo-jit-lock-after-change') then +they are removed by this function. + +For some main major modes \(see `define-mumamo-multi-major-mode') the +main major modes is first used to fontify the whole region. This +is because otherwise the fontification routines for that mode may +have trouble finding the correct starting state in a chunk. + +Special care has been taken for chunks that are strings, ie +surrounded by \"...\" since they are fontified a bit special in +most major modes." + ;; Fix-me: unfontifying should be done using the correct syntax table etc. + ;; Fix-me: refontify when new chunk + ;;(msgtrc "fontify-region-1: font-lock-keywords-only =%s in buffer %s, def=%s" font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + (save-match-data + (let* ((old-point (point)) + (here start) + (main-major (mumamo-main-major-mode)) + (fontified-t ;;(or mumamo-dbg-pretend-fontified + ;; (get-text-property here 'fontified)) + t) + after-change-functions ;; Fix-me: tested adding this to avoid looping + (first-new-ovl nil) + (last-new-ovl nil) + (chunk-at-start-1 (mumamo-find-chunks start "mumamo-fontify-region-1")) + (while-n1 0) + ) + (when chunk-at-start-1 + (unless (= start (1- (overlay-end chunk-at-start-1))) + (setq chunk-at-start-1 nil))) + ;;(while (and (> 500 (setq while-n1 (1+ while-n1))) + (while (and (mumamo-while 9000 'while-n1 "fontified-t") + fontified-t + (< here end)) + ;;(msgtrc "mumamo-fontify-region-1 heree 1, here=%s, end=%s" here end) + ;;(mumamo-assert-fontified-t here end) + ;;(mumamo-assert-fontified-t start end) + ;; Check where new chunks should be, adjust old chunks as + ;; necessary. Refontify inside end-start and outside of + ;; start-end mark for refontification when major-mode has + ;; changed or there was no old chunk. + ;; + ;; Fix-me: Join chunks! + (let* ((chunk (mumamo-find-chunks here "mumamo-fontify-region-1 2")) + (chunk-min (when chunk (overlay-start chunk))) + (chunk-max (when chunk (overlay-end chunk))) + (chunk-min-1 (when chunk (if (> chunk-min (point-min)) (1- chunk-min) (point-min)))) + (chunk-max-1 (when chunk (if (< chunk-max (point-max)) (1+ chunk-max) (point-max)))) + (chunk-min-face (when chunk (get-text-property chunk-min-1 'face))) + (chunk-max-face (when chunk (get-text-property chunk-max-1 'face))) + (chunk-major (when chunk (mumamo-chunk-major-mode chunk))) + max ; (min chunk-max end)) + ) + (assert chunk) + + (setq chunk-min (when chunk (overlay-start chunk))) + (setq chunk-max (when chunk (overlay-end chunk))) + (setq chunk-min-1 + (when chunk + (if (> chunk-min (point-min)) (1- chunk-min) (point-min)))) ;chunk-min + (setq chunk-max-1 + (when chunk + (if (< chunk-max (point-max)) (1+ chunk-max) (point-max)))) ;chunk-max + (setq chunk-min-face + (when chunk (get-text-property chunk-min-1 'face))) + (setq chunk-max-face + (when chunk (get-text-property chunk-max-1 'face))) + (setq chunk-major (when chunk (mumamo-chunk-major-mode chunk))) + + (if (and first-new-ovl (overlay-buffer first-new-ovl)) + (setq last-new-ovl chunk) + (setq last-new-ovl chunk) + (setq first-new-ovl chunk)) + ;;(mumamo-assert-fontified-t chunk-min chunk-max) + + (setq max (min chunk-max end)) + + (assert chunk) (assert (overlay-buffer chunk)) (assert chunk-min) + (assert chunk-max) (assert chunk-major) + ;; Fix-me: The next assertion sometimes fails. Could it be + ;; that this loop is continuing even after a change in the + ;; buffer? How do I stop that? When?: + ;;(assert (or (= here start) (= here chunk-min)) nil "h=%s, s=%s, cm=%s-%s, e=%s, chunk-major=%s" here start chunk-min chunk-max end chunk-major) + ;;(assert (not (mumamo-fun-eq prev-major chunk-major))) + ;;(when prev-chunk + ;; (assert (= (overlay-end prev-chunk) (overlay-start chunk)))) + + ;; Fontify + ;;(msgtrc "\nmumamo-fontify-region-1 before chunk=%s" chunk) + (mumamo-update-obscure chunk here) + (let* ((syntax-min-max (mumamo-chunk-syntax-min-max chunk nil)) + (syntax-min (car syntax-min-max)) + (syntax-max (cdr syntax-min-max)) + (chunk-min (overlay-start chunk)) + (chunk-max (overlay-end chunk)) + (border-min-max (mumamo-chunk-syntax-min-max chunk t)) + (border-min (car border-min-max)) + (border-max (cdr border-min-max)) + ) + ;;(msgtrc "fontify-region-1:syntax-min-max=%S, chunk=%S" syntax-min-max chunk) + ;;(msgtrc "chunk mumamo-border-face: %s" chunk) + (mumamo-msgfntfy "mumamo-fontify-region-1, here=%s chunk-min=%s syn-mn/mx=%s/%s" here chunk-min syntax-min syntax-max) + (when (<= here syntax-min) + (mumamo-flush-chunk-syntax chunk syntax-min syntax-max)) + (when (and (<= here syntax-min) + (< chunk-min border-min)) + ;;(msgtrc "face-in: %s-%s" chunk-min border-min) + (put-text-property chunk-min border-min 'face 'mumamo-border-face-in) + ) + (when (and (<= chunk-max max) + ;;(< (1+ border-max) chunk-max)) + (< border-max chunk-max)) + ;;(put-text-property (1+ border-max) chunk-max + (put-text-property border-max chunk-max + 'face 'mumamo-border-face-out)) + (mumamo-fontify-region-with here max verbose chunk-major + syntax-min syntax-max)) + + ;;(setq prev-major chunk-major) + ;;(setq prev-chunk chunk) + (setq here (if (= max here) (1+ max) max)) + ;;(setq fontified-t (or mumamo-dbg-pretend-fontified (get-text-property (1- here) 'fontified))) + ) + ;;(msgtrc "ft here end=%s %s %s" fontified-t here end) + ) + (goto-char old-point) + ;;(msgtrc "b first-new-ovl=%s last-new-ovl=%s" first-new-ovl last-new-ovl) + (unless fontified-t + ;; Fix-me: I am not sure what to do here. Probably just + ;; refontify the rest between start and end. But does not + ;; this lead to unnecessary refontification? + ;;(msgtrc "not sure, here=%s, end=%s" here end) + (unless (= here (point-max)) + (mumamo-mark-for-refontification here end))) + )) + ;;(msgtrc "EXIT mumamo-fontify-region-1") + ) + + +(defvar mumamo-known-buffer-local-fontifications + '( + font-lock-mode-hook + ;; + css-color-mode + hi-lock-mode + hi-lock-file-patterns + hi-lock-interactive-patterns + wrap-to-fill-column-mode + )) + +(defconst mumamo-irrelevant-buffer-local-vars + '( + ;; This list was fetched with + ;; emacs-Q, fundamental-mode + after-change-functions + ;;auto-composition-function + ;;auto-composition-mode + ;;auto-composition-mode-major-mode + buffer-auto-save-file-format + buffer-auto-save-file-name + buffer-backed-up + buffer-display-count + buffer-display-time + buffer-file-format + buffer-file-name + buffer-file-truename + buffer-invisibility-spec + buffer-read-only + buffer-saved-size + buffer-undo-list + change-major-mode-hook + ;;char-property-alias-alist + cursor-type + default-directory + delay-mode-hooks + enable-multibyte-characters + ;;font-lock-mode + ;;font-lock-mode-major-mode + ;;major-mode + mark-active + mark-ring + mode-name + point-before-scroll + ;; Handled by font lock etc + font-lock-defaults + font-lock-fontified + font-lock-keywords + ;;font-lock-keywords-only + font-lock-keywords-case-fold-search + font-lock-mode + ;;font-lock-mode-major-mode + font-lock-set-defaults + font-lock-syntax-table + font-lock-beginning-of-syntax-function + fontification-functions + jit-lock-context-unfontify-pos + jit-lock-mode + ;; Mumamo + font-lock-fontify-buffer-function + jit-lock-contextually + jit-lock-functions + ;; More symbols from visual inspection + before-change-functions + delayed-mode-hooks + isearch-mode + line-move-ignore-invisible + local-abbrev-table + ;;syntax-ppss-last + ;;syntax-ppss-cache + + ;; Cua + cua--explicit-region-start + ;; Viper + viper--intercept-key-maps + viper--key-maps + viper-ALPHA-char-class + viper-current-state + viper-emacs-global-user-minor-mode + viper-emacs-intercept-minor-mode + viper-emacs-kbd-minor-mode + viper-emacs-local-user-minor-mode + viper-emacs-state-modifier-minor-mode + viper-insert-basic-minor-mode + viper-insert-diehard-minor-mode + viper-insert-global-user-minor-mode + viper-insert-intercept-minor-mode + viper-insert-kbd-minor-mode + viper-insert-local-user-minor-mode + viper-insert-minibuffer-minor-mode + viper-insert-point + viper-insert-state-modifier-minor-mode + viper-intermediate-command + viper-last-posn-while-in-insert-state + viper-minibuffer-current-face + viper-mode-string + viper-non-word-characters + viper-replace-minor-mode + viper-replace-overlay + viper-undo-functions + viper-undo-needs-adjustment + viper-vi-basic-minor-mode + viper-vi-diehard-minor-mode + viper-vi-global-user-minor-mode + viper-vi-intercept-minor-mode + viper-vi-kbd-minor-mode + viper-vi-local-user-minor-mode + viper-vi-minibuffer-minor-mode + viper-vi-state-modifier-minor-mode + ;; hs minor mode + hs-adjust-block-beginning + hs-block-start-mdata-select + hs-block-start-regexp + hs-c-start-regexp + hs-forward-sexp-func + hs-minor-mode + ;; Imenu + imenu-case-fold-search + imenu-generic-expression + ;; Fix-me: add more here + )) + +(defun mumamo-get-relevant-buffer-local-vars () + "Get list of buffer local variables to save. +Like `buffer-local-variables', but remove variables that are +known to not be necessary to save for fontification, indentation +or filling \(or that can even disturb things)." + (let (var-vals) + (dolist (vv (buffer-local-variables)) + (unless (or (not (listp vv)) + (memq (car vv) mumamo-irrelevant-buffer-local-vars) + (let* ((sym (car vv)) + (val (symbol-value sym))) + (or (markerp val) + (overlayp val)))) + (let ((ent (list (car vv) (custom-quote (cdr vv))))) + (setq var-vals (cons ent var-vals))))) + ;; Sorting is for debugging/testing + (setq var-vals (sort var-vals + (lambda (a b) + (string< (symbol-name (car a)) + (symbol-name (car b)))))) + var-vals)) + +(defvar mumamo-major-modes-local-maps nil + "An alist with major mode and local map. +An entry in the list looks like + + \(MAJOR-MODE LOCAL-KEYMAP)") + +;; (defun mumamo-font-lock-keyword-hook-symbol (major) +;; "Return hook symbol for adding font-lock keywords to MAJOR." +;; (intern (concat "mumamo-" (symbol-name major) "-font-lock-keyword-hook"))) + +;; (defun mumamo-remove-font-lock-hook (major setup-fun) +;; "For mode MAJOR remove function SETUP-FUN. +;; See `mumamo-add-font-lock-hook' for more information." +;; (remove-hook (mumamo-font-lock-keyword-hook-symbol major) setup-fun)) + +(defun mumamo-refresh-multi-font-lock (major) + "Refresh font lock information for mode MAJOR in chunks. +If multi fontification functions for major mode MAJOR is already +setup up they will be refreshed. + +If MAJOR is nil then all font lock information for major modes +used in chunks will be refreshed. + +After calling font-lock-add-keywords or changing the +fontification in other ways you must call this function for the +changes to take effect. However already fontified buffers will +not be refontified. You can use `normal-mode' to refontify +them. + +Fix-me: Does not work yet." + + (setq mumamo-internal-major-modes-alist + (if (not major) + nil + (assq-delete-all major mumamo-internal-major-modes-alist)))) + +;; RMS had the following idea: +;; +;; Suppose we add a Lisp primitive to bind a set of variables under +;; the control of an alist. Would it be possible to eliminate these +;; helper functions and use that primitive instead? +;; +;;; But wouldn't it be better to test this version first? There is +;;; no hurry, this version works and someone might find that there +;;; is a better way to do this than with helper functions. +;; +;; OK with me, as long as this point doesn't get forgotten. +(defun mumamo-fetch-major-mode-setup (major keywords mode-keywords add-keywords how) + "Return a helper function to do fontification etc like in major mode MAJOR. +Fetch the variables affecting font locking, indentation and +filling by calling the major mode MAJOR in a temporary buffer. + +Make a function with one parameter BODY which is elisp code to +eval. The function should let bind the variables above, sets the +syntax table temporarily to the one used by the major mode +\(using the mode symbol name to find it) and then evaluates body. + +Name this function mumamo-eval-in-MAJOR. Put the code for this +function in the property `mumamo-defun' on this function symbol. + + +** Some notes about background etc. + +The function made here is used in `mumamo-with-major-mode-setup'. +The code in the function parameter BODY is typically involved in +fontification, indentation or filling. + +The main reasons for doing it this way is: + +- It is faster and than setting the major mode directly. +- It does not affect buffer local variables." + ;; (info "(elisp) Other Font Lock Variables") + ;; (info "(elisp) Syntactic Font Lock) + ;;(msgtrc "fetch-major 1: font-lock-keywords-only =%s" font-lock-keywords-only) + (let ((func-sym (intern (concat "mumamo-eval-in-" (symbol-name major)))) + (func-def-sym (intern (concat "mumamo-def-eval-in-" (symbol-name major)))) + ;;(add-keywords-hook (mumamo-font-lock-keyword-hook-symbol major)) + byte-compiled-fun + (fetch-func-definition `(lambda (body))) ;;`(defun ,func-sym (body))) + temp-buf-name + temp-buf) + ;; font-lock-mode can't be turned on in buffers whose names start + ;; with a char with white space syntax. Temp buffer names are + ;; such and it is not possible to change name of a temp buffer. + (setq temp-buf-name (concat "mumamo-fetch-major-mode-setup-" (symbol-name major))) + (setq temp-buf (get-buffer temp-buf-name)) + (when temp-buf (kill-buffer temp-buf)) + (setq temp-buf (get-buffer-create temp-buf-name)) + ;;(msgtrc "fetch-major-mode-setup in buffer %s, after-chunk=%s, before with-current-buffer" (current-buffer) (when (boundp 'after-chunk) after-chunk)) + (with-current-buffer temp-buf + + (mumamo-msgfntfy "mumamo-fetch-major-mode-setup %s" major) + (let ((mumamo-fetching-major t) + mumamo-multi-major-mode) + ;;(msgtrc "fetch-major-mode-setup in buffer %s, before (funcall %s)" (current-buffer) major) + (funcall major) + ) + + (mumamo-msgfntfy ">>> mumamo-fetch-major-mode-setup A font-lock-mode=%s" font-lock-mode) + (font-lock-mode 1) + (mumamo-msgfntfy "<<< mumamo-fetch-major-mode-setup B font-lock-mode=%s" font-lock-mode) + (mumamo-msgfntfy "mumamo-fetch-major-mode-setup: fetching jit-lock-after-change-extend-region-functions A=%s" jit-lock-after-change-extend-region-functions) + + ;; Note: font-lock-set-defaults must be called before adding + ;; keywords. Otherwise Emacs loops. I have no idea why. Hm, + ;; probably wrong, it is likely to be nxhtml-mumamo that is the + ;; problem. Does not loop in html-mumamo. + ;;(msgtrc "\n--------------------") + (font-lock-set-defaults) + ;; Fix-me: but hi-lock still does not work... what have I + ;; forgotten??? font-lock-keywords looks ok... + (when keywords + (if add-keywords + (progn + ;;(msgtrc "fetch:font-lock-add-keywords %S %S %S" (if mode-keywords major nil) keywords how) + (font-lock-add-keywords (if mode-keywords major nil) keywords how) + ;;(font-lock-add-keywords major keywords how) + ;;(msgtrc "fetch:font-lock-keywords=%S" font-lock-keywords) + ) + (font-lock-remove-keywords (if mode-keywords major nil) keywords) + ;;(font-lock-remove-keywords major keywords) + ) + (unless mode-keywords (font-lock-mode -1) (font-lock-mode 1)) + ;;(msgtrc "fetch-major-mode-setup:font-lock-keywords=%S" font-lock-keywords) + ) + ;;(run-hooks add-keywords-hook) + + (add-to-list 'mumamo-major-modes-local-maps + (let ((local-map (current-local-map))) + (cons major-mode (if local-map + (copy-keymap local-map) + 'no-local-map)))) + + (mumamo-msgfntfy "mumamo-fetch-major-mode-setup: fetching jit-lock-after-change-extend-region-functions B=%s" jit-lock-after-change-extend-region-functions) + (let* ((syntax-sym (intern-soft (concat (symbol-name major) "-syntax-table"))) + (fetch-func-definition-let + ;; Be XML compliant: + (list + (list 'sgml-xml-mode + ;;(when (mumamo-derived-from-mode ',major 'sgml-mode) t)) + (when (mumamo-derived-from-mode major 'sgml-mode) t)) + + ;; We need to copy the variables that we need and + ;; that are not automatically buffer local, but + ;; could be it. Arguably it is a bug if they are not + ;; buffer local though we have to adapt. + + ;; From cc-mode.el: + (list 'indent-line-function (custom-quote indent-line-function)) + (list 'indent-region-function (custom-quote indent-region-function)) + (list 'normal-auto-fill-function (custom-quote normal-auto-fill-function)) + (list 'comment-start (custom-quote comment-start)) + (list 'comment-end (custom-quote comment-end)) + (list 'comment-start-skip (custom-quote comment-start-skip)) + (list 'comment-end-skip (custom-quote comment-end-skip)) + (list 'comment-multi-line (custom-quote comment-multi-line)) + (list 'comment-line-break-function (custom-quote comment-line-break-function)) + (list 'paragraph-start (custom-quote paragraph-start)) + (list 'paragraph-separate (custom-quote paragraph-separate)) + (list 'paragraph-ignore-fill-prefix (custom-quote paragraph-ignore-fill-prefix)) + (list 'adaptive-fill-mode (custom-quote adaptive-fill-mode)) + (list 'adaptive-fill-regexp (custom-quote adaptive-fill-regexp)) + + ;;; Try doing the font lock things last, keywords really last + (list 'font-lock-multiline (custom-quote font-lock-multiline)) + (list 'font-lock-extend-after-change-region-function (custom-quote font-lock-extend-after-change-region-function)) + (list 'font-lock-extend-region-functions (custom-quote font-lock-extend-region-functions)) + (list 'font-lock-comment-start-skip (custom-quote font-lock-comment-start-skip)) + (list 'font-lock-comment-end-skip (custom-quote font-lock-comment-end-skip)) + (list 'font-lock-syntactic-keywords (custom-quote font-lock-syntactic-keywords)) + + (list 'font-lock-keywords (custom-quote font-lock-keywords)) + ;;(list 'font-lock-keywords-alist (custom-quote font-lock-keywords-alist)) + ;;(list 'font-lock-removed-keywords-alist (custom-quote font-lock-removed-keywords-alist)) + + ;; Fix-me: uncommenting this line (as it should be) + ;; sets font-lock-keywords-only to t globally...: bug 3467 + (list 'font-lock-keywords-only (custom-quote font-lock-keywords-only)) + + (list 'font-lock-keywords-case-fold-search (custom-quote font-lock-keywords-case-fold-search)) + + (list 'font-lock-set-defaults t) ; whether we have set up defaults. + + ;; Set from font-lock-defaults normally: + (list 'font-lock-defaults (custom-quote (copy-tree font-lock-defaults))) + ;; Syntactic Font Lock + (list 'font-lock-syntax-table (custom-quote font-lock-syntax-table)) ;; See nXhtml bug 400415 + (list 'font-lock-beginning-of-syntax-function (custom-quote font-lock-beginning-of-syntax-function)) + (list 'font-lock-syntactic-face-function (custom-quote font-lock-syntactic-face-function)) + + ;; Other Font Lock Variables + (list 'font-lock-mark-block-function (custom-quote font-lock-mark-block-function)) + (list 'font-lock-extra-managed-props (custom-quote font-lock-extra-managed-props)) + ;; This value is fetched from font-lock: + (list 'font-lock-fontify-buffer-function (custom-quote font-lock-fontify-buffer-function)) + (list 'font-lock-unfontify-buffer-function (custom-quote font-lock-unfontify-buffer-function)) + (list 'font-lock-fontify-region-function (custom-quote font-lock-fontify-region-function)) + (list 'font-lock-unfontify-region-function (custom-quote font-lock-unfontify-region-function)) + + ;; Jit Lock Variables + (list 'jit-lock-after-change-extend-region-functions (custom-quote jit-lock-after-change-extend-region-functions)) + + ;;(list 'syntax-table (custom-quote (copy-syntax-table (syntax-table)))) + ;;(list 'mumamo-original-syntax-begin-function (custom-quote syntax-begin-function)) + (list 'syntax-begin-function (custom-quote syntax-begin-function)) + (list 'fill-paragraph-function (custom-quote fill-paragraph-function)) + (list 'fill-forward-paragraph-function + (when (boundp 'fill-forward-paragraph-function) + (custom-quote fill-forward-paragraph-function))) + + ;; newcomment + (list 'comment-use-global-state (custom-quote (when (boundp 'comment-use-global-state) comment-use-global-state))) + + ;; parsing sexps + (list 'multibyte-syntax-as-symbol (custom-quote multibyte-syntax-as-symbol)) + (list 'parse-sexp-ignore-comments (custom-quote parse-sexp-ignore-comments)) + (list 'parse-sexp-lookup-properties (custom-quote parse-sexp-lookup-properties)) + ;; fix-me: does not the next line work? + (list 'forward-sexp-function (custom-quote forward-sexp-function)) + )) + (relevant-buffer-locals (mumamo-get-relevant-buffer-local-vars)) + ) + ;;(append '(1 2) '(3 4) '((eval body))) + (mumamo-msgfntfy "===========> before setq fetch-func-definition %s" func-sym) + ;; Avoid doublets + (dolist (fetched fetch-func-definition-let) + (let ((fvar (car fetched))) + (setq relevant-buffer-locals (assq-delete-all fvar relevant-buffer-locals)))) + (setq fetch-func-definition + (append fetch-func-definition + `((let ,(append fetch-func-definition-let + relevant-buffer-locals) + (with-syntax-table ,(if syntax-sym + syntax-sym + '(standard-syntax-table));;'syntax-table + ;; fix-me: Protect against font-lock-keywords-only to t globally...: bug 3467 + ;;(msgtrc "%s enter 1: font-lock-keywords-only def=%s, body=%S" ',major (default-value 'font-lock-keywords-only) body) + (let (;(font-lock-keywords-only font-lock-keywords-only) + ret) + ;;(msgtrc "%s enter 2: font-lock-keywords-only def=%s" ',major (default-value 'font-lock-keywords-only)) + (setq ret (eval body)) + ;;(msgtrc "%s exit 1: font-lock-keywords-only def=%s" ',major (default-value 'font-lock-keywords-only)) + ret)) + ;;(msgtrc "in %s 1: font-lock-keywords-only =%s in buffer %s, def=%s" ',func-sym font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + ) + ;;(msgtrc "in %s 2: font-lock-keywords-only =%s in buffer %s, def=%s" ',func-sym font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + ;;(message "backtrace there:\n%s" (with-output-to-string (backtrace))) + ))) + + (setq byte-compiled-fun (let ((major-syntax-table)) + (byte-compile fetch-func-definition))) + (assert (functionp byte-compiled-fun)) + (unless keywords + (eval `(defvar ,func-sym nil)) + (eval `(defvar ,func-def-sym ,fetch-func-definition)) + (set func-sym byte-compiled-fun) ;; Will be used as default + (assert (functionp (symbol-value func-sym)) t) + (funcall (symbol-value func-sym) nil) + (put func-sym 'permanent-local t) + (put func-def-sym 'permanent-local t)))) + (kill-buffer temp-buf) + ;; Use the new value in current buffer. + (when keywords + ;;(set (make-local-variable func-sym) (symbol-value func-sym)) + ;;(msgtrc "fetch: major=%s func-def-sym=%s cb=%s fetch-func-definition=%s" major func-def-sym (current-buffer) fetch-func-definition) + ;;(msgtrc "fetch: major=%s func-def-sym=%s cb=%s fetch-func-definition" major func-def-sym (current-buffer)) + (set (make-local-variable func-sym) byte-compiled-fun) + (set (make-local-variable func-def-sym) fetch-func-definition) + (put func-sym 'permanent-local t) + (put func-def-sym 'permanent-local t)) + (assert (functionp (symbol-value func-sym)) t) + ;; return a list def + fun + (cons func-sym func-def-sym))) + +;; Fix-me: maybe a hook in font-lock-add-keywords?? +(defun mumamo-ad-font-lock-keywords-helper (major keywords how add-keywords) + ;;(msgtrc "ad-font-lock-keywords-helper %s %s %s %s" major keywords how add-keywords) + (if major + (mumamo-fetch-major-mode-setup major keywords t t how) + ;; Fix-me: Can't do that, need a list of all + ;; mumamo-current-chunk-family chunk functions major + ;; modes. But this is impossible since the major modes might + ;; be determined dynamically. As a work around look in current + ;; chunks. + (let ((majors (list (mumamo-main-major-mode)))) + (dolist (entry mumamo-internal-major-modes-alist) + (let ((major (car entry)) + (fun-var-sym (caadr entry))) + (when (local-variable-p fun-var-sym) + (setq majors (cons (car entry) majors))))) + (dolist (major majors) + (setq major (mumamo-get-major-mode-substitute major 'fontification)) + ;;(msgtrc "(fetch-major-mode-setup %s %s %s %s %s)" major keywords nil t how) + (mumamo-fetch-major-mode-setup major keywords nil add-keywords how)) + ;;(font-lock-mode -1) (font-lock-mode 1) + ))) + +;; Fix-me: This has stopped working again 2009-11-04, but I do not know when it began... +(defadvice font-lock-add-keywords (around + mumamo-ad-font-lock-add-keywords + activate + compile) + (if (or (boundp 'mumamo-fetching-major) (boundp 'mumamo-add-font-lock-called) (not mumamo-multi-major-mode)) + ad-do-it + (let (mumamo-multi-major-mode + mumamo-add-font-lock-called + (major (ad-get-arg 0)) + (keywords (ad-get-arg 1)) + (how (ad-get-arg 2))) + (mumamo-ad-font-lock-keywords-helper major keywords how t)))) + +(defadvice font-lock-remove-keywords (around + mumamo-ad-font-lock-remove-keywords + activate + compile) + (if (or (boundp 'mumamo-fetching-major) (boundp 'mumamo-add-font-lock-called) (not mumamo-multi-major-mode)) + ad-do-it + (let (mumamo-multi-major-mode + mumamo-add-font-lock-called + (major (ad-get-arg 0)) + (keywords (ad-get-arg 1))) + (mumamo-ad-font-lock-keywords-helper major keywords nil nil)))) + +(defun mumamo-bad-mode () + "MuMaMo replacement for a major mode that could not be loaded." + (interactive) + (kill-all-local-variables) + (setq major-mode 'mumamo-bad-mode) + (setq mode-name + (propertize "Mumamo Bad Mode" + 'face 'font-lock-warning-face))) + +;;(mumamo-get-major-mode-setup 'css-mode) +;;(mumamo-get-major-mode-setup 'fundamental-mode) +(defun mumamo-get-major-mode-setup (use-major) + "Return function for evaluating code in major mode USE-MAJOR. +Fix-me: This doc string is wrong, old: + +Get local variable values for major mode USE-MAJOR. These +variables are used for indentation and fontification. The +variables are returned in a list with the same format as +`mumamo-fetch-major-mode-setup'. + +The list of local variable values which is returned by this +function is cached in `mumamo-internal-major-modes-alist'. This +avoids calling the major mode USE-MAJOR for each chunk during +fontification and speeds up fontification significantly." + ;; Fix-me: Problems here can cause mumamo to loop badly when this + ;; function is called over and over again. To avoid this add a + ;; temporary entry using mumamo-bad-mode while trying to fetch the + ;; correct mode. + + ;;(assq 'mumamo-bad-mode mumamo-internal-major-modes-alist) + (let ((use-major-entry (assq use-major mumamo-internal-major-modes-alist)) + bad-mode-entry + dummy-entry + fun-var-sym + fun-var-def-sym) + (unless use-major-entry + ;; Get mumamo-bad-mode entry and add a dummy entry based on + ;; this to avoid looping. + (setq bad-mode-entry + (assq 'mumamo-bad-mode mumamo-internal-major-modes-alist)) + (unless bad-mode-entry + ;; Assume it is safe to get the mumamo-bad-mode entry ;-) + (add-to-list 'mumamo-internal-major-modes-alist + (list 'mumamo-bad-mode + (mumamo-fetch-major-mode-setup 'mumamo-bad-mode nil nil nil nil))) + (setq bad-mode-entry + (assq 'mumamo-bad-mode mumamo-internal-major-modes-alist))) + (setq dummy-entry (list use-major (cadr bad-mode-entry))) + ;; Before fetching setup add the dummy entry and then + ;; immediately remove it. + (add-to-list 'mumamo-internal-major-modes-alist dummy-entry) + (setq use-major-entry (list use-major + (mumamo-fetch-major-mode-setup use-major nil nil nil nil))) + (setq mumamo-internal-major-modes-alist + (delete dummy-entry + mumamo-internal-major-modes-alist)) + (add-to-list 'mumamo-internal-major-modes-alist use-major-entry)) + (setq fun-var-sym (caadr use-major-entry)) + (setq fun-var-def-sym (cdadr use-major-entry)) + (assert (functionp (symbol-value fun-var-sym)) t) + (assert (eq 'lambda (car (symbol-value fun-var-def-sym))) t) + ;; Always make a buffer local value for keywords. + (unless (local-variable-p fun-var-sym) + (set (make-local-variable fun-var-sym) (symbol-value fun-var-sym)) + (set (make-local-variable fun-var-def-sym) (symbol-value fun-var-def-sym))) + (caadr (or (assq use-major mumamo-internal-major-modes-alist) + )))) +;; (assq use-major +;; (add-to-list 'mumamo-internal-major-modes-alist +;; (list use-major +;; (mumamo-fetch-major-mode-setup +;; use-major nil nil nil)))))))) + +(defun mumamo-remove-all-chunk-overlays () + "Remove all CHUNK overlays from the current buffer." + (save-restriction + (widen) + (mumamo-delete-new-chunks))) + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Creating and accessing chunks + +(defun mumamo-define-no-mode (mode-sym) + "Fallback major mode when no major mode for MODE-SYM is found." + (let ((mumamo-repl4 (intern (format "mumamo-4-%s" mode-sym))) + (lighter (format "No %s" mode-sym)) + (doc (format "MuMaMo replacement for %s which was not found." + mode-sym))) + (if (commandp mumamo-repl4) + mumamo-repl4 + (eval `(defun ,mumamo-repl4 () + ,doc + (interactive) + (kill-all-local-variables) + (setq major-mode ',mumamo-repl4) + (setq mode-name + (propertize ,lighter + 'face 'font-lock-warning-face))))))) +;;(mumamo-define-no-mode 'my-ownB-mode) + +;;(mumamo-major-mode-from-modespec 'javascript-mode) +(defun mumamo-major-mode-from-modespec (major-spec) + "Translate MAJOR-SPEC to a major mode. +Translate MAJOR-SPEC used in chunk definitions of multi major +modes to a major mode. + +See `mumamo-major-modes' for an explanation." + (mumamo-major-mode-from-spec major-spec mumamo-major-modes)) + +(defun mumamo-major-mode-from-spec (major-spec table) + (unless major-spec + (mumamo-backtrace "mode-from-modespec, major-spec is nil")) + (let ((modes (cdr (assq major-spec table))) + (mode 'mumamo-bad-mode)) + (setq mode + (catch 'mode + (dolist (m modes) + (when (functionp m) + (let ((def (symbol-function m))) + (when (and (listp def) + (eq 'autoload (car def))) + (mumamo-condition-case err + (load (nth 1 def)) + (error (setq m nil))))) + (when m (throw 'mode m)))) + nil)) + (unless mode + (if (functionp major-spec) + ;; As a last resort allow spec to be a major mode too: + (setq mode major-spec) + (if modes + (mumamo-warn-once '(mumamo-major-mode-from-modespec) + "Couldn't find an available major mode for specification %s,\n alternatives are:\n %s" + major-spec modes) + (mumamo-warn-once '(mumamo-major-mode-from-modespec) + "Couldn't find an available major mode for spec %s" + major-spec)) + ;;(setq mode 'fundamental-mode) + (setq mode (mumamo-define-no-mode major-spec)) + )) + (mumamo-msgfntfy " mumamo-major-mode-from-modespec %s => %s" major-spec mode) + mode)) + +(defun mumamo-get-existing-new-chunk-at (pos &optional first) + "Return last existing chunk at POS if any. +However if FIRST get first existing chunk at POS instead." + ;;(msgtrc "(mumamo-get-existing-new-chunk-at %s)" pos) + (let ((chunk-ovl) + (orig-pos pos)) + (when (= pos (point-max)) + (setq pos (1- pos))) + (when (= pos 0) (setq pos 1)) + (dolist (o (overlays-in pos (1+ pos))) + (when (and (overlay-get o 'mumamo-is-new) + ;; Because overlays-in need to have a range of length + ;; > 0 we might have got overlays that is after our + ;; orig-pos: + (<= (overlay-start o) orig-pos)) + ;; There can be two, choose the last or first depending on + ;; FIRST. + (if chunk-ovl + ;; (when (or (> (overlay-end o) (overlay-start o)) + ;; (overlay-get o 'mumamo-prev-chunk)) + (when (if first + (< (overlay-end o) (overlay-end chunk-ovl)) + (> (overlay-end o) (overlay-end chunk-ovl)) + ) + (setq chunk-ovl o)) + (setq chunk-ovl o)))) + chunk-ovl)) + +(defun mumamo-get-chunk-save-buffer-state (pos) + "Return chunk overlay at POS. Preserve state." + (let (chunk) + ;;(mumamo-save-buffer-state nil + ;;(setq chunk (mumamo-get-chunk-at pos))) + (setq chunk (mumamo-find-chunks pos "mumamo-get-chunk-save-buffer-state")) + ;;) + chunk)) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Chunk and chunk family properties + +(defun mumamo-syntax-maybe-completable (pnt) + "Return non-nil if at point PNT non-printable characters may occur. +This just considers existing chunks." + (let* ((chunk (mumamo-find-chunks pnt "mumamo-syntax-maybe-completable")) + syn-min-max) + (if (not chunk) + t + (mumamo-update-obscure chunk pnt) + (setq syn-min-max (mumamo-chunk-syntax-min-max chunk nil)) + ;;(and (> pnt (1+ (mumamo-chunk-syntax-min chunk))) + (and (> pnt (1+ (car syn-min-max))) + ;;(< pnt (1- (mumamo-chunk-syntax-max chunk))))))) + (< pnt (1- (cdr syn-min-max))))))) + +(defvar mumamo-current-chunk-family nil + "The currently used chunk family.") +(make-variable-buffer-local 'mumamo-current-chunk-family) +(put 'mumamo-current-chunk-family 'permanent-local t) + +;; (defvar mumamo-main-major-mode nil) +;; (make-variable-buffer-local 'mumamo-main-major-mode) +;; (put 'mumamo-main-major-mode 'permanent-local t) + +(defun mumamo-main-major-mode () + "Return major mode used when there are no chunks." + (let ((mm (cadr mumamo-current-chunk-family))) + (if mm mm + (msgtrc "main-major-mode => nil, mumamo-current-chunk-family=%s" mumamo-current-chunk-family)))) +;;; (let ((main (cadr mumamo-current-chunk-family))) +;;; (if main +;;; main +;;; mumamo-main-major-mode))) + +;; (defun mumamo-unset-chunk-family () +;; "Set chunk family to nil, ie undecided." +;; (interactive) +;; (setq mumamo-current-chunk-family nil)) + +;; (defun mumamo-define-chunks (chunk-family) +;; "Set the CHUNK-FAMILY used to divide the buffer." +;; (setq mumamo-current-chunk-family chunk-family)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; General chunk search routines + +;; search start forward + +;;(defun mumamo-search-fw-exc-start-str (pos max marker) +(defun mumamo-chunk-start-fw-str (pos max marker) + "General chunk function helper. +A chunk function helper like this can be used in +`mumamo-find-possible-chunk' to find the borders of a chunk. +There are several functions like this that comes with mumamo. +Their names tell what they do. Lets look at the parts of the +name of this function: + + mumamo-chunk: All this helper functions begins so + -start-: Search for the start of a chunk + -fw-: Search forward + -str: Search for a string + +Instead of '-start-' there could be '-end-', ie end. +Instead of '-fw-' there could be '-bw-', ie backward. +Instead of '-str' there could be '-re', ie regular expression. + +There could also be a '-inc' at the end of the name. If the name +ends with this then the markers should be included in the chunks, +otherwise not. + +The argument POS means where to start the search. MAX means how +far to search (when searching backwards the argument is called +'min' instead). MARKER is a string or regular expression (see +the name) to search for." + (assert (stringp marker)) + (let ((pm (point-min)) + (cb (current-buffer))) + (message "cb=%s" cb) + (goto-char (max pm (- pos (length marker))))) + (search-forward marker max t)) + +(defun mumamo-chunk-start-fw-re (pos max marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MAX and MARKER." + (assert (stringp marker)) + (goto-char (- pos (length marker))) + (re-search-forward marker max t)) + +(defun mumamo-chunk-start-fw-str-inc (pos max marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MAX and MARKER." + (assert (stringp marker)) + (goto-char pos) + (let ((start (search-forward marker max t))) + (when start (setq start (- start (length marker)))))) + +;; search start backward + +;; (defun mumamo-chunk-start-bw-str (pos min marker) +;; "General chunk function helper. +;; See `mumamo-chunk-start-fw-str' for more information and the +;; meaning of POS, MIN and MARKER." +;; ;;(assert (stringp marker)) +;; (let (start-in) +;; (goto-char pos) +;; (setq start-in (search-backward marker min t)) +;; (when start-in +;; ;; do not include the marker +;; (setq start-in (+ start-in (length marker)))) +;; start-in)) + +;; (defun mumamo-chunk-start-bw-re (pos min marker) +;; "General chunk function helper. +;; See `mumamo-chunk-start-fw-str' for more information and the +;; meaning of POS, MIN and MARKER." +;; (assert (stringp marker)) +;; (let (start-in) +;; (goto-char pos) +;; (setq start-in (re-search-backward marker min t)) +;; (when start-in +;; ;; do not include the marker +;; (setq start-in (match-end 0))) +;; start-in)) + +;; (defun mumamo-chunk-start-bw-str-inc (pos min marker) +;; "General chunk function helper. +;; See `mumamo-chunk-start-fw-str' for more information and the +;; meaning of POS, MIN and MARKER." +;; (assert (stringp marker)) +;; (goto-char (+ pos (length marker))) +;; (search-backward marker min t)) + +;; search end forward + +(defun mumamo-chunk-end-fw-str (pos max marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MAX and MARKER." + (assert (stringp marker)) + ;;(goto-char (1+ pos)) ;; 1+ cause otherwise ?> is at point + (goto-char pos) + (let (end-in) + (setq end-in (search-forward marker max t)) + (when end-in + ;; do not include the marker + (setq end-in (- end-in (length marker)))) + end-in)) + +(defun mumamo-chunk-end-fw-re (pos max marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MAX and MARKER." + (assert (stringp marker)) + (goto-char (1+ pos)) ;; 1+ cause otherwise ?> is at point + (let (end-in) + (setq end-in (re-search-forward marker max t)) + (when end-in + ;; do not include the marker + (setq end-in (match-beginning 0))) + end-in)) + +(defun mumamo-chunk-end-fw-str-inc (pos max marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MAX and MARKER." + (assert (stringp marker)) + ;;(goto-char (1+ pos)) ;; 1+ cause otherwise ?> is at point + (goto-char (1+ (- pos (length marker)))) + ;;(msgtrc "mumamo-chunk-end-fw-str-inc %s %s %s, point=%s point-max=%s" pos max marker (point) (point-max)) + (search-forward marker max t)) + +;; search end backward + +;; (defun mumamo-chunk-end-bw-str (pos min marker) +;; "General chunk function helper. +;; See `mumamo-chunk-start-fw-str' for more information and the +;; meaning of POS, MIN and MARKER." +;; (assert (stringp marker)) +;; (goto-char (+ pos (length marker))) +;; (search-backward marker min t)) + +;; (defun mumamo-chunk-end-bw-re (pos min marker) +;; "General chunk function helper. +;; See `mumamo-chunk-start-fw-str' for more information and the +;; meaning of POS, MIN and MARKER." +;; (assert (stringp marker)) +;; (goto-char (+ pos (length marker))) +;; (re-search-backward marker min t)) + +(defun mumamo-chunk-end-bw-str-inc (pos min marker) + "General chunk function helper. +See `mumamo-chunk-start-fw-str' for more information and the +meaning of POS, MIN and MARKER." + (assert (stringp marker)) + (goto-char pos) + (let ((end (search-backward marker min t))) + (when end (setq end (+ end (length marker)))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; General chunk routines + +;; (defvar mumamo-known-chunk-start nil "Internal use only!.") + +(defconst mumamo-string-syntax-table + (let ((tbl (copy-syntax-table))) + (modify-syntax-entry ?\" "\"" tbl) + (modify-syntax-entry ?\' "\"" tbl) + tbl) + "Just for \"..\" and '...'.") + +;; "..." '...' "..'.." '.."..' +(defun mumamo-guess-in-string (pos) + "If POS is in a string then return string start position. +Otherwise return nil." + (when (and (>= pos (point-min))) + (let ((here (point)) + (inhibit-field-text-motion t) + line-beg + parsed + str-char + str-pos) + (goto-char pos) + (setq line-beg (line-beginning-position)) + (setq parsed (with-syntax-table mumamo-string-syntax-table + (parse-partial-sexp line-beg pos))) + (setq str-char (nth 3 parsed)) + (when str-char + (skip-chars-backward (string ?^ str-char)) + (setq str-pos (point))) + (goto-char here) + str-pos))) + +;;; The main generic chunk routine + +;; Fix-me: new routine that really search forward only. Rewrite +;; `mumamo-quick-static-chunk' first with this. +(defun mumamo-possible-chunk-forward (pos + max + chunk-start-fun + chunk-end-fun + &optional borders-fun) + "Search forward from POS to MAX for possible chunk. +Return as a list with values + + \(START END CHUNK-MAJOR BORDERS PARSEABLE-BY CHUNK-END-FUN BORDERS-FUN) + +START and END are start and end of the possible chunk. +CHUNK-MAJOR is the major mode specifier for this chunk. \(Note +that this specifier is translated to a major mode through +`mumamo-major-modes'.) + +START-BORDER and END-BORDER may be nil. Otherwise they should be +the position where the border ends respectively start at the +corresponding end of the chunk. + +BORDERS is the return value of the optional BORDERS-FUN which +takes three parameters, START, END and EXCEPTION-MODE in the +return values above. BORDERS may be nil and otherwise has this +format: + + \(START-BORDER END-BORDER CHUNK-MAJOR CHUNK-END-FUN) + +PARSEABLE-BY is a list of major modes with parsers that can parse +the chunk. + +CHUNK-START-FUN and CHUNK-END-FUN should be functions that +searches forward from point for start and end of chunk. They +both take two parameters, POS and MAX above. If no possible +chunk is found both these functions should return nil, otherwise +see below. + +CHUNK-START-FUN should return a list of the form below if a +possible chunk is found: + + (START CHUNK-MAJOR PARSEABLE-BY) + +CHUNK-END-FUN should return the end of the chunk. + +" + ;;(msgtrc "possible-chunk-forward %s %s" pos max) + (let ((here (point)) + start-rec + start + end + chunk-major + parseable-by + borders + ret + ) + (goto-char pos) + ;; Fix-me: check valid. Should this perhaps be done in the + ;; function calling this instead? + ;;(mumamo-end-in-code syntax-min syntax-max curr-major) + (setq start-rec (funcall chunk-start-fun (point) max)) + (when start-rec + (setq start (nth 0 start-rec)) + (setq chunk-major (nth 1 start-rec)) + (setq parseable-by (nth 2 start-rec)) + (goto-char start) + ;; Fix-me: check valid + ;;(setq end (funcall chunk-end-fun (point) max)) + (when borders-fun + (let ((start-border (when start (unless (and (= 1 start) + (not chunk-major)) + start))) + (end-border (when end (unless (and (= (point-max) end) + (not chunk-major)) + end)))) + (setq borders (funcall borders-fun start-border end-border chunk-major)))) + (setq ret (list start end chunk-major borders parseable-by chunk-end-fun borders-fun))) + (goto-char here) + ret)) + +;; Fix-me: This routine has some difficulties. One of the more +;; problematic things is that chunk borders may depend on the +;; surrounding chunks syntax. Patterns that possibly could be chunk +;; borders might instead be parts of comments or strings in cases +;; where they should not be valid borders there. +(defun mumamo-find-possible-chunk (pos + min max + bw-exc-start-fun ;; obsolete + bw-exc-end-fun + fw-exc-start-fun + fw-exc-end-fun + &optional find-borders-fun) + (mumamo-find-possible-chunk-new pos + ;;min + max + bw-exc-start-fun + ;;bw-exc-end-fun + fw-exc-start-fun + fw-exc-end-fun + find-borders-fun)) + +(defun mumamo-find-possible-chunk-new (pos + ;;min + max + bw-exc-start-fun + ;;bw-exc-end-fun + fw-exc-start-fun + fw-exc-end-fun + &optional find-borders-fun) + ;; This should return no end value! + "Return list describing a possible chunk that starts after POS. +No notice is taken about existing chunks and no chunks are +created. The description returned is for the smallest possible +chunk which is delimited by the function parameters. + +POS must be less than MAX. + +The function BW-EXC-START-FUN takes two parameters, POS and +MIN. It should search backward from POS, bound by MIN, for +exception start and return a cons or a list: + + \(FOUND-POS . EXCEPTION-MODE) + \(FOUND-POS EXCEPTION-MODE PARSEABLE-BY) + +Here FOUND-POS is the start of the chunk. EXCEPTION-MODE is the +major mode specifier for this chunk. \(Note that this specifier +is translated to a major mode through `mumamo-major-modes'.) + +PARSEABLE-BY is a list of parsers that can handle the chunk +beside the one that may be used by the chunks major mode. +Currently only the XML parser in `nxml-mode' is recognized. In +this list it should be the symbol `nxml-mode'. + +The functions FW-EXC-START-FUN and FW-EXC-END-FUN should search +for exception start or end, forward resp backward. Those two +takes two parameters, start position POS and max position MAX, +and should return just the start respectively the end of the +chunk. + +For all three functions the position returned should be nil if +search fails. + + +Return as a list with values + + \(START END EXCEPTION-MODE BORDERS PARSEABLE-BY FR-EXC-FUN FIND-BORDERS-FUN) + +**Fix-me: FIND-BORDERS-FUN must be split for chunks-in-chunks! + +The bounds START and END are where the exception starts or stop. +Either of them may be nil, in which case this is equivalent to +`point-min' respectively `point-max'. + +If EXCEPTION-MODE is non-nil that is the submode for this +range. Otherwise the main major mode should be used for this +chunk. + +BORDERS is the return value of the optional FIND-BORDERS-FUN +which takes three parameters, START, END and EXCEPTION-MODE in +the return values above. BORDERS may be nil and otherwise has +this format: + + \(START-BORDER END-BORDER EXCEPTION-MODE FW-EXC-FUN) + +START-BORDER and END-BORDER may be nil. Otherwise they should be +the position where the border ends respectively start at the +corresponding end of the chunk. + +PARSEABLE-BY is a list of major modes with parsers that can parse +the chunk. + +FW-EXC-FUN is the function that finds the end of the chunk. This +is either FW-EXC-START-FUN or FW-EXC-END-FUN. + +---- * Note: This routine is used by to create new members for +chunk families. If you want to add a new chunk family you could +most often do that by writing functions for this routine. Please +see the many examples in mumamo-fun.el for how this can be done. +See also `mumamo-quick-static-chunk'." + ;;(msgtrc "====") + ;;(msgtrc "find-poss-new %s %s %s %s %s %s" pos max bw-exc-start-fun fw-exc-start-fun fw-exc-end-fun find-borders-fun) + + ;;(mumamo-condition-case err + (progn + (assert (and (<= pos max)) nil + "mumamo-chunk: pos=%s, max=%s, bt=%S" + pos max (with-output-to-string (backtrace))) + ;; "in" refers to "in exception" and "out" is then in main + ;; major mode. + (let (start-in-cons + exc-mode + fw-exc-mode + fw-exc-fun + parseable-by + start-in start-out + end-in end-out + start end + ;;end-of-exception + wants-end-type + found-valid-end + (main-major (mumamo-main-major-mode)) + borders + border-beg + border-end) + ;;;; find start of range + ;; + ;; start normal + ;; + ;;(setq start-out (funcall bw-exc-end-fun pos min)) + ;; Do not check end here! + ;;(setq start-out (funcall fw-exc-end-fun pos max)) + ;;(msgtrc "find-poss-new.start-out=%s" start-out) + ;; start exception + (setq start-in (funcall fw-exc-start-fun pos max)) + ;;(msgtrc "find-poss-new.start-in=%s" start-in) + (when (listp start-in) + (setq fw-exc-mode (nth 1 start-in)) + (setq start-in (car start-in))) + ;; compare + (when (and start-in start-out) + (if (> start-in start-out) + (setq start-in nil) + (setq start-out nil))) + (cond + (start-in + (setq start-in-cons (funcall bw-exc-start-fun start-in pos)) + ;;(msgtrc "find-poss-new.start-in=%s start-in-cons=%s" start-in start-in-cons) + (when start-in-cons + (assert (= start-in (car start-in-cons))) + (setq exc-mode (cdr start-in-cons))) + (setq start start-in)) + (start-out + (setq start start-out)) + ) + (when (and exc-mode + (listp exc-mode)) + (setq parseable-by (cadr exc-mode)) + (setq exc-mode (car exc-mode))) + ;; borders + (when find-borders-fun + (let ((start-border (when start (unless (and (= 1 start) + (not exc-mode)) + start))) + (end-border (when end (unless (and (= (point-max) end) + (not exc-mode)) + end)))) + (setq borders (funcall find-borders-fun start-border end-border exc-mode)))) + ;; check + (setq border-beg (nth 0 borders)) + (setq border-end (nth 1 borders)) + ;;(when start (assert (<= start pos))) + ;;(assert (or (not start) (= start pos))) + (when border-beg + (assert (<= start border-beg))) + ;; Fix-me: This is just totally wrong in some pieces and a + ;; desperate try after seeing the problems with wp-app.php + ;; around line 1120. Maybe this can be used when cutting chunks + ;; from top to bottom however. + (when nil ;end + (let ((here (point)) + end-line-beg + end-in-string + start-in-string + (start-border (or (nth 0 borders) start)) + (end-border (or (nth 1 borders) end))) + ;; Check if in string + ;; Fix-me: add comments about why and examples + tests + ;; Fix-me: must loop to find good borders .... + (when end + ;; Fix-me: more careful positions for guess + (setq end-in-string + (mumamo-guess-in-string + ;;(+ end 2) + (1+ end-border) + )) + (when end-in-string + (when start + (setq start-in-string + (mumamo-guess-in-string + ;;(- start 2) + (1- start-border) + ))) + (if (not start-in-string) + (setq end nil) + (if exc-mode + (if (and start-in-string end-in-string) + ;; If both are in a string and on the same line then + ;; guess this is actually borders, otherwise not. + (unless (= start-in-string end-in-string) + (setq start nil) + (setq end nil)) + (when start-in-string (setq start nil)) + (when end-in-string (setq end nil))) + ;; Fix-me: ??? + (when start-in-string (setq start nil)) + )) + (unless (or start end) + (setq exc-mode nil) + (setq borders nil) + (setq parseable-by nil)))))) + + (when (or start end exc-mode borders parseable-by) + (setq fw-exc-fun (if exc-mode + ;; Fix-me: this is currently correct, + ;; but will change if exc mode in exc + ;; mode is allowed. + fw-exc-end-fun + ;; Fix-me: these should be collected later + ;;fw-exc-start-fun + nil + )) + (mumamo-msgfntfy "--- mumamo-find-possible-chunk-new %s" (list start end exc-mode borders parseable-by fw-exc-fun)) + ;;(message "--- mumamo-find-possible-chunk-new %s" (list start end exc-mode borders parseable-by fw-exc-fun)) + (when fw-exc-mode + (unless (eq fw-exc-mode exc-mode) + ;;(message "fw-exc-mode=%s NEQ exc-mode=%s" fw-exc-mode exc-mode) + )) + ;;(msgtrc "find-poss-new returns %s" (list start end exc-mode borders parseable-by fw-exc-fun find-borders-fun)) + (when fw-exc-fun + (list start end exc-mode borders parseable-by fw-exc-fun find-borders-fun))))) + ;;(error (mumamo-display-error 'mumamo-chunk "%s" (error-message-string err))) + + ;;) + ) + +;; (defun temp-overlays-here () +;; (interactive) +;; (let* ((here (point)) +;; (ovl-at (overlays-at here)) +;; (ovl-in (overlays-in here (1+ here))) +;; (ovl-in0 (overlays-in here here)) +;; ) +;; (with-output-to-temp-buffer (help-buffer) +;; (help-setup-xref (list #'temp-overlays-at) (interactive-p)) +;; (with-current-buffer (help-buffer) +;; (insert (format "overlays-at %s:\n%S\n\n" here ovl-at)) +;; (insert (format "overlays-in %s-%s:\n%S\n\n" here (1+ here) ovl-in)) +;; (insert (format "overlays-in %s-%s:\n%S\n\n" here here ovl-in0)) +;; )))) +;; (defun temp-cursor-pos () +;; (interactive) +;; (what-cursor-position t)) +;; ;;(global-set-key [f9] 'temp-cursor-pos) +;; (defun temp-test-new-create-chunk () +;; (interactive) +;; (mumamo-delete-new-chunks) +;; ;;(setq x1 nil) +;; (let (x1 +;; (first t)) +;; (while (or first x1) +;; (setq first nil) +;; (setq x1 (mumamo-new-create-chunk (mumamo-find-next-chunk-values x1 nil nil nil))))) +;; ) + +;; (defun temp-create-last-chunk () +;; (interactive) +;; (mumamo-new-create-chunk (mumamo-find-next-chunk-values mumamo-last-chunk nil nil nil))) + +(defun mumamo-delete-new-chunks () + (setq mumamo-last-chunk nil) + (save-restriction + (widen) + (let ((ovls (overlays-in (point-min) (point-max)))) + (dolist (ovl ovls) + (when (overlay-get ovl 'mumamo-is-new) + ;;(msgtrc "delete-overlay %s delete-new-chunks" ovl) + (delete-overlay ovl)))))) + +(defun mumamo-new-create-chunk (new-chunk-values) + "Create and return a chunk from NEW-CHUNK-VALUES. +When doing this store the functions for creating the next chunk +after this in the properties below of the now created chunk: + +- 'mumamo-next-major: is nil or the next chunk's major mode. +- 'mumamo-next-end-fun: function that searches for end of AFTER-CHUNK +- 'mumamo-next-border-fun: functions that finds borders" + ;;((1 696 nxhtml-mode nil nil nil nil) (696 nil php-mode nil nil nil nil)) + ;;(current (list curr-min curr-max curr-major curr-border-min curr-border-max curr-parseable curr-fw-exc-fun)) + ;;(msgtrc "######new-create.chunk.new-chunk-values=%s" new-chunk-values) + (when new-chunk-values + (let* ((this-values (nth 0 new-chunk-values)) + (next-values (nth 1 new-chunk-values)) + (next-major (nth 0 next-values)) + (next-end-fun (nth 1 next-values)) + (next-border-fun (nth 2 next-values)) + (next-depth-diff (nth 3 next-values)) + (next-indent (nth 4 next-values)) + (this-beg (nth 0 this-values)) + (this-end (nth 1 this-values)) + (this-maj (nth 2 this-values)) + (this-bmin (nth 3 this-values)) + (this-bmax (nth 4 this-values)) + (this-pable (nth 5 this-values)) + (this-after-chunk (nth 7 this-values)) + ;;(this-is-closed (nth 8 this-values)) + (this-insertion-type-beg (nth 8 this-values)) + (this-insertion-type-end (nth 9 this-values)) + ;;(this-is-closed (and this-end (< 1 this-end))) + (this-after-chunk-depth (when this-after-chunk + (overlay-get this-after-chunk 'mumamo-depth))) + (depth-diff (if this-after-chunk + (overlay-get this-after-chunk 'mumamo-next-depth-diff) + 1)) + (depth (if this-after-chunk-depth + (+ this-after-chunk-depth depth-diff) + 0)) + ;;(fw-funs (nth 6 this-values)) + ;;(borders-fun (nth 7 this-values)) + ;;(this-is-closed (when (or this-end (mumamo-fun-eq this-maj (mumamo-main-major-mode))) t)) + (use-this-end (if this-end this-end (1+ (buffer-size)))) ;(save-restriction (widen) (point-max)))) + (this-chunk (when (and (<= this-beg use-this-end) + ;; Avoid creating two empty overlays + ;; at the this-end - but what if we are + ;; not creating, just changing the + ;; last overlay ... + ;; + ;; (not (and (= this-beg use-this-end) + ;; (= use-this-end (1+ (buffer-size))) + ;; this-after-chunk + ;; (= 0 (- (overlay-end this-after-chunk) (overlay-start this-after-chunk))) + ;; )) + ) + (when (= this-beg 1) + (if (= use-this-end 1) + (assert (mumamo-fun-eq (mumamo-main-major-mode) this-maj) t) + (if this-after-chunk ;; not first + (assert (not (mumamo-fun-eq (mumamo-main-major-mode) this-maj)) t) + (assert (mumamo-fun-eq (mumamo-main-major-mode) this-maj) t)))) + ;;(message "Create chunk %s - %s" this-beg use-this-end) + ;;(make-overlay this-beg use-this-end nil nil (not this-is-closed)) + (make-overlay this-beg use-this-end nil this-insertion-type-beg this-insertion-type-end) + )) + ;; Fix-me: move to mumamo-find-next-chunk-values + (this-border-fun (when (and this-chunk this-after-chunk) + ;;(overlay-get this-after-chunk 'mumamo-next-border-fun) + (mumamo-chunk-car this-after-chunk 'mumamo-next-border-fun) + )) + (this-borders (when this-border-fun + ;;(msgtrc "(funcall %s %s %s %s)" this-border-fun this-beg this-end this-maj) + (funcall this-border-fun this-beg this-end this-maj))) + ;; Fix-me, check: there is no first border when moving out. + (this-borders-min (when (= 1 depth-diff) + (nth 0 this-borders))) + ;; Fix-me, check: there is no bottom border when we move + ;; further "in" since borders are now always inside + ;; sub-chunks (if I remember correctly...). + ;;(this-borders-max (when (and this-is-closed + (this-borders-max (when (and (not this-insertion-type-end) + (/= 1 next-depth-diff)) + (nth 1 this-borders))) + ) + ;;(msgtrc "created %s, major=%s" this-chunk this-maj) + (when (> depth 4) (error "Chunk depth > 4")) + (setq this-bmin nil) + (setq this-bmax nil) + (when this-borders-min (setq this-bmin (- this-borders-min this-beg))) + (when this-borders-max (setq this-bmax (- this-end this-borders-max))) + ;;(when this-after-chunk (message "this-after-chunk.this-end=%s, this-beg=%s, this-end=%s" (overlay-end this-after-chunk) this-beg this-end)) + ;;(message "fw-funs=%s" fw-funs) + (when this-chunk + (overlay-put this-chunk 'mumamo-is-new t) + (overlay-put this-chunk 'face (mumamo-background-color depth)) + (overlay-put this-chunk 'mumamo-depth depth) + ;; Values for next chunk + (overlay-put this-chunk 'mumamo-next-depth-diff next-depth-diff) + (assert (symbolp next-major) t) + (overlay-put this-chunk 'mumamo-next-major next-major) + ;; Values for this chunk + ;;(overlay-put this-chunk 'mumamo-is-closed this-is-closed) + (overlay-put this-chunk 'mumamo-insertion-type-end this-insertion-type-end) + (overlay-put this-chunk 'mumamo-syntax-min-d this-bmin) + (overlay-put this-chunk 'mumamo-syntax-max-d this-bmax) + (overlay-put this-chunk 'mumamo-prev-chunk this-after-chunk) + (overlay-put this-chunk 'mumamo-next-indent next-indent) + (when this-after-chunk (overlay-put this-after-chunk 'mumamo-next-chunk this-chunk)) + + ;;(msgtrc "\n<<<<<<<<<<<<<<<<< next-depth-diff/depth-diff=%s/%s, this-maj=%s, this-after-chunk=%s" next-depth-diff depth-diff this-maj this-after-chunk) + ;;(overlay-put this-chunk 'mumamo-next-end-fun next-end-fun) + (cond + ((= 1 next-depth-diff) + (mumamo-chunk-push this-chunk 'mumamo-next-border-fun next-border-fun) + (mumamo-chunk-push this-chunk 'mumamo-next-end-fun next-end-fun)) + ((= -1 next-depth-diff) + (mumamo-chunk-pop this-chunk 'mumamo-next-border-fun) + (mumamo-chunk-pop this-chunk 'mumamo-next-end-fun)) + ((= 0 next-depth-diff) + nil) + (t (error "next-depth-diff=%s" next-depth-diff))) + ;;(msgtrc "mumamo-next-end-fun=%S" (overlay-get this-chunk 'mumamo-next-end-fun)) + + ;; Fix-me: replace 'mumamo-major-mode with multi major mode to make it more flexible. + (cond + ((= 1 depth-diff) + (mumamo-chunk-push this-chunk 'mumamo-major-mode this-maj)) + ((= -1 depth-diff) + (mumamo-chunk-pop this-chunk 'mumamo-major-mode) + ) + (t (error "depth-diff=%s" depth-diff))) + + (overlay-put this-chunk 'mumamo-parseable-by this-pable) + (overlay-put this-chunk 'created (current-time-string)) + (mumamo-update-chunk-margin-display this-chunk) + (setq mumamo-last-chunk this-chunk) ;; Use this chunk!!!! + ;; Get syntax-begin-function for syntax-ppss: + (let* ((syntax-begin-function + (mumamo-with-major-mode-fontification this-maj + ;; Do like in syntax.el: + '(if syntax-begin-function + (progn + syntax-begin-function) + (when (and (not syntax-begin-function) + ;; fix-me: How to handle boundp here? + (boundp 'font-lock-beginning-of-syntax-function) + font-lock-beginning-of-syntax-function) + font-lock-beginning-of-syntax-function))))) + (mumamo-msgfntfy "Got syntax-begin-function, modified=%s" (buffer-modified-p)) + (overlay-put this-chunk 'syntax-begin-function syntax-begin-function)) + ) + ;;(msgtrc "Created %s, this=%s, next=%s" this-chunk this-values next-values) + this-chunk + ) + )) + +(defun mumamo-update-chunk-margin-display (chunk) + "Set before-string of CHUNK as spec by `mumamo-margin-use'." + ;; Fix-me: This is not displayed. Emacs bug? + ;;(overlay-put this-chunk 'before-string `((margin left-margin) ,(format "%d %s" depth maj))) + (if (not mumamo-margin-info-mode) + (overlay-put chunk 'before-string nil) + (let* ((depth (overlay-get chunk 'mumamo-depth)) + (maj (mumamo-chunk-car chunk 'mumamo-major-mode)) + (strn (propertize (format "%d" depth) + 'face (list :inherit (or (mumamo-background-color depth) + 'default) + :foreground "#505050" + :underline t + :slant 'normal + :weight 'normal + ))) + (maj-name (substring (symbol-name maj) 0 -5)) + (strm (propertize maj-name 'face + (list :foreground "#a0a0a0" :underline nil + :background (frame-parameter nil 'background-color) + :weight 'normal + :slant 'normal))) + str + (margin (mumamo-margin-used))) + (when (> (length strm) 5) (setq strm (substring strm 0 5))) + (setq str (concat strn + strm + (propertize " " 'face 'default) + )) + (overlay-put chunk 'before-string + (propertize " " 'display + `((margin ,margin) ,str)))))) + +(defun mumamo-update-chunks-margin-display (buffer) + "Apply `update-chunk-margin-display' to all chunks in BUFFER." + (with-current-buffer buffer + (save-restriction + (widen) + (let ((chunk (mumamo-find-chunks 1 "margin-disp")) + (while-n0 0)) + (while (and (mumamo-while 1500 'while-n0 "chunk") + chunk) + (mumamo-update-chunk-margin-display chunk) + (setq chunk (overlay-get chunk 'mumamo-next-chunk))))))) + +(defvar mumamo-margin-used nil) +(make-variable-buffer-local 'mumamo-margin-used) +(put 'mumamo-margin-used 'permanent-local t) + +(defun mumamo-margin-used () + (setq mumamo-margin-used + (if (and (boundp 'linum-mode) linum-mode) 'right-margin (nth 0 mumamo-margin-use)))) + +;; (defun mumamo-set-window-margins-used (win) +;; "Set window margin according to `mumamo-margin-use'." +;; ;; Fix-me: old-margin does not work, break it up +;; (let* ((old-margin-used mumamo-margin-used) +;; (margin-used (mumamo-margin-used)) +;; (width (nth 1 mumamo-margin-use)) +;; (both-widths (window-margins win)) +;; (old-left (eq old-margin-used 'left-margin)) +;; (left (eq margin 'left-margin))) +;; ;; Change only the margin we used! +;; (if (not mumamo-margin-info-mode) +;; (progn +;; (set-window-margins win +;; (if left nil (car both-widths)) +;; (if (not left) nil (cdr both-widths))) +;; ) +;; ;;(msgtrc "set-window-margins-used margin-info-mode=t") +;; (case margin-used +;; ('left-margin (set-window-margins win width (when old-left (cdr both-widths)))) +;; ('right-margin (set-window-margins win (car both-widths) width)))))) + +(defun mumamo-update-buffer-margin-use (buffer) + ;;(msgtrc "update-buffer-margin-use %s" buffer) + (when (fboundp 'mumamo-update-chunks-margin-display) + (with-current-buffer buffer + (when mumamo-multi-major-mode + (let* ((old-margin-used mumamo-margin-used) + (margin-used (mumamo-margin-used)) + (old-is-left (eq old-margin-used 'left-margin)) + (is-left (eq margin-used 'left-margin)) + (width (nth 1 mumamo-margin-use)) + (need-update nil)) + (if (not mumamo-margin-info-mode) + (when old-margin-used + (setq need-update t) + (setq old-margin-used nil) + (if old-is-left + (setq left-margin-width 0) + (setq right-margin-width 0))) + (unless (and (eq old-margin-used margin-used) + (= width (if old-is-left left-margin-width right-margin-width))) + (setq need-update t) + (if is-left + (setq left-margin-width width) + (setq right-margin-width width)) + (unless (eq old-margin-used margin-used) + (if old-is-left + (setq left-margin-width 0) + (setq right-margin-width 0))))) + (when need-update + (mumamo-update-chunks-margin-display buffer) + (dolist (win (get-buffer-window-list buffer)) + (set-window-buffer win buffer))) + ) + ;; Note: window update must be before buffer update because it + ;; uses old-margin from the call to function margin-used. + ;; (dolist (win (get-buffer-window-list buffer)) + ;; (mumamo-set-window-margins-used win)) + ;; (mumamo-update-chunks-margin-display buffer) + )))) + +(defun mumamo-new-chunk-value-min (values) + (let ((this-values (nth 0 values))) + (nth 0 this-values))) + +(defun mumamo-new-chunk-value-max (values) + (let ((this-values (nth 0 values))) + (nth 1 this-values))) + +(defun mumamo-new-chunk-equal-chunk-values (chunk values) + ;;(msgtrc "eq? chunk=%S, values=%S" chunk values) + (let* (;; Chunk + (chunk-is-new (overlay-get chunk 'mumamo-is-new)) + ;;(chunk-is-closed (overlay-get chunk 'mumamo-is-closed)) + (chunk-insertion-type-end (overlay-get chunk 'mumamo-insertion-type-end)) + (chunk-next-major (overlay-get chunk 'mumamo-next-major)) + (chunk-next-end-fun (mumamo-chunk-car chunk 'mumamo-next-end-fun)) + (chunk-next-border-fun (mumamo-chunk-car chunk 'mumamo-next-border-fun)) + (chunk-next-chunk-diff (overlay-get chunk 'mumamo-next-depth-diff)) + (chunk-beg (overlay-start chunk)) + (chunk-end (overlay-end chunk)) + (chunk-bmin (overlay-get chunk 'mumamo-syntax-min-d)) + (chunk-bmax (overlay-get chunk 'mumamo-syntax-max-d)) + (chunk-prev-chunk (overlay-get chunk 'mumamo-prev-chunk)) + (chunk-major-mode (mumamo-chunk-car chunk 'mumamo-major-mode)) + (chunk-pable (overlay-get chunk 'mumamo-parseable-by)) + (chunk-depth-diff (if chunk-prev-chunk + (overlay-get chunk-prev-chunk 'mumamo-next-depth-diff) + 0)) + ;; Values + (this-values (nth 0 values)) + (next-values (nth 1 values)) + (values-next-major (nth 0 next-values)) + (values-next-end-fun (nth 1 next-values)) + (values-next-border-fun (nth 2 next-values)) + (values-next-depth-diff (nth 3 next-values)) + (values-beg (nth 0 this-values)) + (values-end (nth 1 this-values)) + (values-major-mode (nth 2 this-values)) + (values-bmin (nth 3 this-values)) + (values-bmax (nth 4 this-values)) + (values-pable (nth 5 this-values)) + (values-prev-chunk (nth 7 this-values)) + (values-insertion-type-beg (nth 8 this-values)) + (values-insertion-type-end (nth 9 this-values)) + ;;(values-is-closed (when values-end t)) + ) + ;;(msgtrc "values=%S" values) + (and t ;chunk-is-new + (eq chunk-next-major values-next-major) + + ;; Can't check chunk-next-end-fun or chunk-next-border-fun + ;; here since they are fetched from prev chunk: + ;;(progn (message "eq-c-v: here b: %s /= %s" chunk-next-end-fun values-next-end-fun) t) + ;;(eq chunk-next-end-fun values-next-end-fun) + ;;(progn (message "eq-c-v: here c, %s /= %s" chunk-next-border-fun values-next-border-fun) t) + ;;(eq chunk-next-border-fun values-next-border-fun) + + (= chunk-next-chunk-diff values-next-depth-diff) + (= chunk-beg values-beg) + ;;(progn (message "eq-c-v: here b") t) + ;; (and (equal chunk-is-closed values-is-closed) + ;; (or (not chunk-is-closed) + (and (equal chunk-insertion-type-end values-insertion-type-end) + (or ;;chunk-insertion-type-end + (= chunk-end values-end))) + ;;(progn (message "eq-c-v: here c, %s /= %s" chunk-major-mode values-major-mode) t) + (or (= -1 chunk-depth-diff) + (eq chunk-major-mode values-major-mode)) + ;;(progn (message "eq-c-v: here d") t) + (equal chunk-pable values-pable) + ;;(progn (message "eq-c-v: here e") t) + (eq chunk-prev-chunk values-prev-chunk) + ;;(progn (message "eq-c-v: here f") t) + ;;(eq chunk-is-closed values-is-closed) + (eq chunk-insertion-type-end values-insertion-type-end) + ;; fix-me: bmin bmax + ;;(and chunk-bmin values-bmin (= chunk-bmin values-bmin)) + ;;(and chunk-bmax values-bmax (= chunk-bmax values-bmax)) + ) + )) + +(defvar mumamo-sub-chunk-families nil + "Chunk dividing routines for sub chunks. +A major mode in a sub chunk can inherit chunk dividing routines +from multi major modes. This is the way chunks in chunks is +implemented. + +This variable is an association list with entries of the form + + \(CHUNK-MAJOR CHUNK-FAMILY) + +where CHUNK-MAJOR is the major mode in a chunk and CHUNK-FAMILY +is a chunk family \(ie the third argument to +`define-mumamo-multi-major-mode'. + +You can use the function `mumamo-inherit-sub-chunk-family' to add +to this list.") + +(defvar mumamo-multi-local-sub-chunk-families nil + "Multi major mode local chunk dividing rourines for sub chunks. +Like `mumamo-sub-chunk-families' specific additions for multi +major modes. The entries have the form + + \((CHUNK-MAJOR . MULTI-MAJOR) CHUNK-FAMILY) + +Use the function `mumamo-inherit-sub-chunk-family-locally' to add +to this list.") + +;;(mumamo-get-sub-chunk-funs 'html-mode) +(defun mumamo-get-sub-chunk-funs (major) + "Get chunk family sub chunk with major mode MAJOR." + (let ((rec (or + (assoc (cons major mumamo-multi-major-mode) mumamo-multi-local-sub-chunk-families) + (assoc major mumamo-sub-chunk-families)))) + (caddr (cadr rec)))) + +(defun mumamo-inherit-sub-chunk-family-locally (multi-major multi-using) + "Add chunk dividing routines from MULTI-MAJOR locally. +The dividing routines from multi major mode MULTI-MAJOR can then +be used in sub chunks in buffers using multi major mode +MULTI-USING." + (let* ((chunk-family (get multi-major 'mumamo-chunk-family)) + (major (nth 1 chunk-family))) + (let ((major-mode major)) + (when (derived-mode-p 'nxml-mode) + (error "Major mode %s major can't be used in sub chunks" major))) + (add-to-list 'mumamo-multi-local-sub-chunk-families + (list (cons major multi-using) chunk-family)))) + +(defun mumamo-inherit-sub-chunk-family (multi-major) + "Inherit chunk dividing routines from multi major modes. +Add chunk family from multi major mode MULTI-MAJOR to +`mumamo-sub-chunk-families'. + +Sub chunks with major mode the same as MULTI-MAJOR mode will use +this chunk familyu to find subchunks." + (let* ((chunk-family (get multi-major 'mumamo-chunk-family)) + (major (nth 1 chunk-family))) + (let ((major-mode major)) + (when (derived-mode-p 'nxml-mode) + (error "Major mode %s major can't be used in sub chunks" major))) + (add-to-list 'mumamo-sub-chunk-families (list major chunk-family)))) + +(defun mumamo-find-next-chunk-values (after-chunk from after-change-max chunk-at-after-change) + "Search forward for start of next chunk. +Return a list with chunk values for next chunk after AFTER-CHUNK +and some values for the chunk after it. + +For the first chunk AFTER-CHUNK is nil. Otherwise the values in stored in AFTER-CHUNK +is used to find the new chunk, its border etc. + + +See also `mumamo-new-create-chunk' for more information." + ;;(msgtrc "(find-next-chunk-values %s %s %s %s)" after-chunk from after-change-max chunk-at-after-change) + ;;(mumamo-backtrace "find-next") + (when after-chunk + (unless (eq (overlay-buffer after-chunk) + (current-buffer)) + (error "mumamo-find-next-chunk-values: after-chunk=%S, cb=%S" after-chunk (current-buffer)))) + (let* ((here (point)) + (max (point-max)) + ;;(after-chunk-is-closed (when after-chunk-valid (overlay-get after-chunk 'mumamo-is-closed))) + (after-chunk-insertion-type-end (when after-chunk (overlay-get after-chunk 'mumamo-insertion-type-end))) + ;; Note that "curr-*" values are fetched from "mumamo-next-*" values in after-chunk + (curr-min (if after-chunk (overlay-end after-chunk) 1)) + (curr-end-fun (when after-chunk + (mumamo-chunk-car after-chunk 'mumamo-next-end-fun))) + (curr-border-fun (when curr-end-fun (mumamo-chunk-car after-chunk 'mumamo-next-border-fun))) + (curr-syntax-min-max (when curr-border-fun (funcall curr-border-fun + (overlay-end after-chunk) + nil nil))) + (curr-syntax-min (or (car curr-syntax-min-max) + (when after-chunk (overlay-end after-chunk)) + 1)) + (search-from (or nil ;from + curr-syntax-min)) + ;;(dummy (msgtrc "search-from=%s" search-from)) + (main-chunk-funs (let ((chunk-info (cdr mumamo-current-chunk-family))) + (cadr chunk-info))) + (curr-major (if after-chunk + (or + ;; 'mumamo-next-major is used when we are going into a sub chunk. + (overlay-get after-chunk 'mumamo-next-major) + ;; We are going out of a sub chunk. + (mumamo-chunk-cadr after-chunk 'mumamo-major-mode)) + (mumamo-main-major-mode))) + ;;(dummy (msgtrc "curr-major=%s" curr-major)) + (curr-chunk-funs + (if (or (not after-chunk) + (= 0 (+ (overlay-get after-chunk 'mumamo-depth) + (overlay-get after-chunk 'mumamo-next-depth-diff)))) + main-chunk-funs + (mumamo-get-sub-chunk-funs curr-major))) + curr-max + next-max + curr-max-found + next-min + curr-border-min + curr-border-max + curr-parseable + next-fw-exc-fun + next-indent + next-major + curr-end-fun-end + next-border-fun + ;; The insertion types for the new chunk + (curr-insertion-type-beg (when after-chunk after-chunk-insertion-type-end)) + curr-insertion-type-end + next-depth-diff + r-point + ) + (unless (and after-chunk-insertion-type-end + (= (1+ (buffer-size)) ;; ie point-max + (overlay-end after-chunk))) + (when (>= max search-from) + (when curr-end-fun + ;; If after-change-max is non-nil here then this function has + ;; been called after changes that are all in one chunk. We + ;; need to check if the chunk right border have been changed, + ;; but we do not have to look much longer than the max point + ;; of the change. + ;;(message "set after-change-max nil") (setq after-change-max nil) + (let* ((use-max (if nil ;;after-change-max + (+ after-change-max 100) + max)) + (chunk-end (and chunk-at-after-change + (overlay-end chunk-at-after-change))) + ;;(use-min (max (- search-from 2) (point-min))) + (use-min curr-syntax-min) + (possible-end-fun-end t) + (end-search-pos use-min)) + ;; The code below takes care of the case when to subsequent + ;; chunks have the same ending delimiter. (Maybe a while + ;; loop is bit overkill here.) + (while (and possible-end-fun-end + (not curr-end-fun-end) + (< end-search-pos use-max)) + (setq curr-end-fun-end (funcall curr-end-fun end-search-pos use-max)) + (if (not curr-end-fun-end) + (setq possible-end-fun-end nil) + (cond ((and t ;after-chunk-is-closed + (< curr-end-fun-end (overlay-end after-chunk))) + (setq curr-end-fun-end nil) + (setq end-search-pos (1+ end-search-pos))) + ;; See if the end is in code + ((let* ((syn2-min-max (when curr-border-fun + (funcall curr-border-fun + (overlay-end after-chunk) + curr-end-fun-end + nil))) + (syn2-max (or (cadr syn2-min-max) + curr-end-fun-end))) + (not (mumamo-end-in-code use-min syn2-max curr-major))) + (setq end-search-pos (1+ curr-end-fun-end)) + (setq curr-end-fun-end nil) + )))) + (unless curr-end-fun-end + ;; Use old end if valid + (and after-change-max + chunk-end + (= -1 (overlay-get chunk-at-after-change 'mumamo-next-depth-diff)) + (< after-change-max chunk-end) + chunk-end)) + ;; Fix-me: Check if old chunk is valid. It is not valid if + ;; depth-diff = -1 and curr-end-fun-end is not the same as + ;; before. + + ;; Fix-me: this test should also be made for other chunks + ;; searches, but this catches most problems I think. + ;; (or (not curr-end-fun-end) + ;; ;; Fix-me: The bug in wiki-090804-js.html indicates that + ;; ;; we should not subtract 1 here. The subchunk there + ;; ;; ends with and this can't be in column 1 + ;; ;; when the line before ends with a // style js comment + ;; ;; unless we don't subtract 1. + ;; ;; + ;; ;; However wiki-strange-hili-080629.html does not work + ;; ;; then because then the final " in style="..." is + ;; ;; included in the scan done in mumamo-end-in-code. + ;; ;; + ;; ;; The solution is to check for the syntax borders here. + ;; (let* ((syn2-min-max (when curr-border-fun + ;; (funcall curr-border-fun + ;; (overlay-end after-chunk) + ;; curr-end-fun-end + ;; nil))) + ;; (syntax-max (or (cadr syn2-min-max) + ;; curr-end-fun-end))) + ;; ;;(mumamo-end-in-code syntax-min (- curr-end-fun-end 1) curr-major) + ;; ;; + ;; ;; fix-me: This should be really in the individual + ;; ;; routines that finds possible chunks. Mabye this is + ;; ;; possible to fix now when just looking forward for + ;; ;; chunks? + ;; (mumamo-end-in-code curr-syntax-min syntax-max curr-major) + ;; ) + ;; (setq curr-end-fun-end nil)) + ;; Use old result if valid + ;; (and nil ;(not curr-end-fun-end) + ;; chunk-at-after-change + ;; (= -1 (overlay-get chunk-at-after-change 'mumamo-next-depth-diff)) + ;; (setq curr-end-fun-end (overlay-end chunk-at-after-change))) + ;;(msgtrc "find-next-chunk-values:curr-end-fun-end after end-in-code=%s" curr-end-fun-end) + )) + ;;(msgtrc "find-next-chunk-values:here d, curr-min=%s, after-chunk=%s" curr-min after-chunk) + (when (listp curr-chunk-funs) + ;;(msgtrc "find-next-chunk-values:curr-chunk-funs=%s" curr-chunk-funs) + (setq r-point (point)) + (dolist (fn curr-chunk-funs) + ;;(msgtrc "find-next-chunk-values:before (r (funcall fn search-from search-from max)), fn=%s search-from=%s, max=%s" fn search-from max) + (assert (= r-point (point)) t) + (let* ((r (funcall fn search-from search-from max)) + (rmin (nth 0 r)) + (rmax (nth 1 r)) + (rmajor-sub (nth 2 r)) + (rborder (nth 3 r)) + (rparseable (nth 4 r)) + (rfw-exc-fun (nth 5 r)) + (rborder-fun (nth 6 r)) + (rindent (nth 7 r)) + (rborder-min (when rborder (nth 0 rborder))) + (rborder-max (when rborder (nth 1 rborder))) + ;;(rmin-found rmin) + ) + ;;(msgtrc "find-next-chunk-values:fn=%s, r=%s" fn r) + (goto-char r-point) + (when r + (when rmax (message "mumamo warning: Bad r=%s, nth 1 should be nil" r)) + (unless (or rmin rmax) + (error "Bad r=%s, fn=%s" r fn)) + (unless rfw-exc-fun + (error "No fw-exc-fun returned from fn=%s, r=%s" fn r)) + (unless rmajor-sub + (error "No major mode for sub chunk, fn=%s, r=%s" fn r))) + (when r + (mumamo-msgfntfy " fn=%s, r=%s" fn r) + (unless rmin (setq rmin (point-max))) + ;;(unless rmax (setq rmax (point-min))) + ;; Do not allow zero length chunks + (unless rmax (setq rmax (point-max))) + (unless (and (> rmin 1) + rmax + (= rmin rmax)) + ;; comparision have to be done differently if we are in an + ;; exception part or not. since we are doing this from top to + ;; bottom the rules are: + ;; + ;; - exception parts always outrules non-exception part. when + ;; in exception part the min start point should be used. + ;; - when in non-exception part the max start point and the + ;; min end point should be used. + ;; + ;; check if first run: + + ;; Fix-me: there is some bug here when borders are not + ;; included and are not 0 width. + (if (not next-min) + (progn + (setq next-min rmin) + (setq curr-border-min rborder-min) + (setq next-max rmax) + (setq curr-border-max rborder-max) + ;;(setq curr-max-found rmin-found) + (setq curr-parseable rparseable) + (setq next-fw-exc-fun rfw-exc-fun) + (setq next-border-fun rborder-fun) + (setq next-indent rindent) + (setq next-major rmajor-sub)) + (if rmajor-sub + (if next-major + (when (or (not next-min) + (< rmin next-min)) + (setq next-min rmin) + (setq curr-border-min rborder-min) + (when rmax (setq max rmax)) + (setq curr-border-max rborder-max) + ;;(when rmin-found (setq curr-max-found t)) + (setq curr-parseable rparseable) + (setq next-fw-exc-fun rfw-exc-fun) + (setq next-border-fun rborder-fun) + (setq next-indent rindent) + (setq next-major rmajor-sub)) + (setq next-min rmin) + (setq curr-border-min rborder-min) + (when rmax (setq max rmax)) + (setq curr-border-max rborder-max) + ;;(when rmin-found (setq curr-max-found t)) + (setq curr-parseable rparseable) + (setq next-fw-exc-fun rfw-exc-fun) + (setq next-border-fun rborder-fun) + (setq next-indent rindent) + (setq next-major rmajor-sub)) + (unless next-major + (when (> next-min rmin) + (setq next-min rmin) + (setq curr-border-min rborder-min)) + (when (and rmax max + (> rmax max)) + ;;(setq max-found rmin-found) + ;;(when rmin-found (setq curr-max-found t)) + (when rmax (setq max rmax)) + (setq curr-border-max rborder-max)) + )))) + (mumamo-msgfntfy "next-min/max=%s/%s border=%s/%s search-from=%s" next-min max curr-border-min curr-border-max search-from) + ;; check! + (when (and next-min max) + ;;(assert (>= next-min search-from) t) + (assert (<= search-from max) t) + (when curr-border-min + (assert (<= next-min curr-border-min) t) + (assert (<= curr-border-min max) t)) + (when curr-border-max + (assert (<= next-min curr-border-max) t) + (assert (<= curr-border-max max) t)))) + ))) + (goto-char here) + (setq curr-max-found (or curr-max-found curr-end-fun-end)) + (when t ;curr-max-found + (setq curr-max (if max max (point-max))) + (setq curr-max (min (if next-min next-min curr-max) + (if curr-end-fun-end curr-end-fun-end curr-max)))) + ;;(setq curr-max nil) + (setq next-depth-diff (cond + ( (and curr-max curr-end-fun-end + (= curr-max curr-end-fun-end)) + -1) + ( (= curr-max (1+ (buffer-size))) + 0) + ( t 1))) + (when (= -1 next-depth-diff) ;; We will pop it from 'mumamo-major-mode + (setq next-major nil)) + (when curr-max + (unless (>= curr-max curr-min) + (error "curr-max is not >= curr-min"))) + ;;(setq curr-is-closed (and curr-max (< 1 curr-max))) + (when (and curr-max (= 1 curr-max)) + (assert (mumamo-fun-eq curr-major (mumamo-main-major-mode)) t) + ) + (assert (symbolp next-major) t) + ;; Fix-me: see for example rr-min8.php + (when (or ;;(not after-chunk) + (= curr-max (1+ (buffer-size))) + (cond + ((= next-depth-diff 1) + next-border-fun) + ((= next-depth-diff -1) + next-border-fun) + ((= next-depth-diff 0) + t) + (t (error "next-depth-diff=%s" next-depth-diff)))) + (setq curr-insertion-type-end t)) + (let ((current (list curr-min curr-max curr-major curr-border-min curr-border-max curr-parseable + curr-chunk-funs after-chunk + ;;curr-is-closed + curr-insertion-type-beg + curr-insertion-type-end + )) + (next (list next-major next-fw-exc-fun next-border-fun next-depth-diff next-indent))) + ;;(msgtrc "find-next-chunk-values=> current=%s, next=%s" current next) + (list current next)))))) + +;; Fix-me: This should check if the new chunk should be +;; parsed or not +;; (defsubst mumamo-chunk-nxml-parseable (chunk) +;; (mumamo-fun-eq (mumamo-main-major-mode) +;; (mumamo-chunk-major-mode xml-chunk))) + +(defun mumamo-valid-nxml-point (pos) + "Return non-nil if position POS is in an XML chunk." + (memq 'nxml-mode (get-text-property pos 'mumamo-parseable-by))) + +(defun mumamo-valid-nxml-chunk (chunk) + "Return t if chunk CHUNK should be valid XML." + (when chunk + (let ((major-mode (mumamo-chunk-major-mode chunk)) + (region (overlay-get chunk 'mumamo-region)) + (parseable-by (overlay-get chunk 'mumamo-parseable-by))) + ;;(message "mumamo-valid-nxml-chunk: major-mode=%s, parseble-by=%s" major-mode parseable-by) + (or region + (derived-mode-p 'nxml-mode) + (memq 'nxml-mode parseable-by))))) + +;; A good test case for the use of this is the troublesome code in the +;; first line of xml-as-string.php in nxml/nxhtml/bug-tests. Currently +;; this test code is however splitted and it looks like the code below +;; can't handle the line above if the line looks like below. The ?> is +;; still thought to be a border. Does this mean that ' is not treated +;; as a string separator? +;; +;; '; ?> +;; +;; However there are the reverse cases also, in lines like +;; +;; href="url($url); ?>" +;; . Could this be solved by RMS suggestion with a + ;; function/defmacro that binds variables to their global values? + (mumamo-msgfntfy "point-min,max=%s,%s syntax-start,end=%s,%s, major=%s" (point-min) (point-max) syntax-start syntax-end major) + ;;(msgtrc "end-in-code:here a after-chunk=%s" (when (boundp 'after-chunk) after-chunk)) + (assert (and syntax-start syntax-end) t) + (let ((doesnt-here (point)) + doesnt-ret) + (save-restriction + (widen) + ;;(msgtrc "end-in-code:here a2 after-chunk=%s" (when (boundp 'after-chunk) after-chunk)) + (mumamo-with-major-mode-fontification major + `(let (ppss) + ;; fix-me: Use main major mode, and `syntax-ppss'. Change the + ;; defadvice of this to make that possible. + ;;(msgtrc "end-in-code:here b after-chunk=%s" (when (boundp 'after-chunk) after-chunk)) + (setq ppss (parse-partial-sexp ,syntax-start (+ ,syntax-end 0))) + ;;(msgtrc "end-in-code %s %s %s:ppss=%S" ,syntax-start ,syntax-end ',major ppss) + ;;(msgtrc "end-in-code:here c after-chunk=%s" (when (boundp 'after-chunk) after-chunk)) + ;; If inside a string or comment then the end marker is + ;; invalid: + ;;(msgtrc "mumamo-end-in-code:ppss=%s" ppss) + (if (or (nth 3 ppss) + (nth 4 ppss)) + (progn + ;;(msgtrc "invalid end, syntax-end =%s" syntax-end) + (setq doesnt-ret nil) + (if (nth 4 ppss) ;; in comment, check if single line comment + (let ((here (point)) + eol-pos) + ;;(msgtrc "end-in-code, was in comment, ppss=%S" ppss) + (goto-char ,syntax-end) + (setq eol-pos (line-end-position)) + (goto-char here) + (setq ppss (parse-partial-sexp ,syntax-start (+ eol-pos 1))) + ;;(msgtrc "end-in-code, in comment, new ppss %s %s=%S" ,syntax-start (+ eol-pos 1) ppss) + (unless (nth 4 ppss) + (setq doesnt-ret t))))) + (setq doesnt-ret t) + ;;(msgtrc "valid end, syntax-end =%s" syntax-end) + )))) + (goto-char doesnt-here) + ;;(msgtrc "end-in-code:ret=%s" doesnt-ret) + doesnt-ret)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Easy chunk defining + +(defun mumamo-quick-chunk-forward (pos + min max + begin-mark end-mark inc mode + mark-is-border) + ;;(msgtrc "quick-chunk-forward %s %s %s" pos min max) + (let ((search-fw-exc-start + `(lambda (pos max) + (let ((exc-start + (if ,inc + (mumamo-chunk-start-fw-str-inc pos max ,begin-mark) + (mumamo-chunk-start-fw-str pos max ,begin-mark)))) + (when exc-start + (list exc-start mode nil))))) + (search-fw-exc-end + `(lambda (pos max) + ;;(msgtrc "search-fw-exc-end %s %s, inc=%s, end-mark=%s" pos max ,inc ,end-mark) + (save-match-data + (let ((ret (if ,inc + (mumamo-chunk-end-fw-str-inc pos max ,end-mark) + (mumamo-chunk-end-fw-str pos max ,end-mark)))) + ;;(msgtrc "search-fw-exc-end ret=%s" ret) + ret)))) + (find-borders + (when mark-is-border + `(lambda (start end exc-mode) + (let ((start-border) + (end-border)) + (if (and ,inc);; exc-mode) + (progn + (when start + (setq start-border + (+ start (length ,begin-mark)))) + (when end + (setq end-border + (- end (length ,end-mark))))) + (if (and (not ,inc) (not exc-mode)) + (progn + (when start + (setq start-border + (+ start (length ,end-mark)))) + (when end + (setq end-border + (- end (length ,begin-mark))))))) + (when (or start-border end-border) + (mumamo-msgfntfy "quick.start-border/end=%s/%s, start/end=%s/%s exc-mode=%s" start-border end-border start end exc-mode) + (list start-border end-border))))))) + (mumamo-possible-chunk-forward pos max + search-fw-exc-start + search-fw-exc-end + find-borders))) + +(defun mumamo-quick-static-chunk (pos + min max + begin-mark end-mark inc mode + mark-is-border) + (if t + (mumamo-quick-chunk-forward pos min max begin-mark end-mark inc mode mark-is-border) + ;; (let ((old (mumamo-quick-static-chunk-old pos min max begin-mark end-mark inc mode mark-is-border)) + ;; (new (mumamo-quick-chunk-forward pos min max begin-mark end-mark inc mode mark-is-border))) + ;; (unless (equal old new) (msgtrc "equal=%s\n\told=%S\n\tnew=%S" (equal old new) old new)) + ;; (if nil old new)) + )) + +;; (defun mumamo-quick-static-chunk-old (pos +;; min max +;; begin-mark end-mark inc mode +;; mark-is-border) +;; "Quick way to make a chunk function with static dividers. +;; Here is an example of how to use it: + +;; (defun mumamo-chunk-embperl-<- (pos min max) +;; \"Find [- ... -], return range and perl-mode.\" +;; (mumamo-quick-static-chunk pos min max \"[-\" \"-]\" nil 'perl-mode)) + +;; As you can see POS, MIN and MAX comes from argument of the +;; function you define. + +;; BEGIN-MARK should be a string that begins the chunk. +;; END-MARK should be a string that ends the chunk. + +;; If INC is non-nil then the dividers are included in the chunk. +;; Otherwise they are instead made parts of the surrounding chunks. + +;; MODE should be the major mode for the chunk. + +;; If MARK-IS-BORDER is non-nil then the marks are just borders and +;; not supposed to have the same syntax as the inner part of the + +;; Fix-me: This can only be useful if the marks are included in the +;; chunk, ie INC is non-nil. Should not these two arguments be +;; mixed then? +;; " +;; (mumamo-msgfntfy "quick.pos=%s min,max=%s,%s begin-mark/end=%s/%s mark-is-border=%s" pos min max begin-mark end-mark mark-is-border) +;; (let ((search-bw-exc-start +;; `(lambda (pos min) +;; (let ((exc-start +;; (if ,inc +;; (mumamo-chunk-start-bw-str-inc pos min begin-mark) +;; (mumamo-chunk-start-bw-str pos min begin-mark)))) +;; (when (and exc-start +;; (<= exc-start pos)) +;; (cons exc-start mode))))) +;; (search-bw-exc-end +;; `(lambda (pos min) +;; (if ,inc +;; (mumamo-chunk-end-bw-str-inc pos min ,end-mark) +;; (mumamo-chunk-end-bw-str pos min ,end-mark)))) +;; (search-fw-exc-start +;; `(lambda (pos max) +;; (if ,inc +;; (mumamo-chunk-start-fw-str-inc pos max ,begin-mark) +;; (mumamo-chunk-start-fw-str pos max ,begin-mark)))) +;; (search-fw-exc-end +;; `(lambda (pos max) +;; (save-match-data +;; (if ,inc +;; (mumamo-chunk-end-fw-str-inc pos max ,end-mark) +;; (mumamo-chunk-end-fw-str pos max ,end-mark))))) +;; (find-borders +;; (when mark-is-border +;; `(lambda (start end exc-mode) +;; (let ((start-border) +;; (end-border)) +;; (if (and ,inc exc-mode) +;; (progn +;; (when start +;; (setq start-border +;; (+ start (length ,begin-mark)))) +;; (when end +;; (setq end-border +;; (- end (length ,end-mark))))) +;; (if (and (not ,inc) (not exc-mode)) +;; (progn +;; (when start +;; (setq start-border +;; (+ start (length ,end-mark)))) +;; (when end +;; (setq end-border +;; (- end (length ,begin-mark))))))) +;; (when (or start-border end-border) +;; (mumamo-msgfntfy "quick.start-border/end=%s/%s, start/end=%s/%s exc-mode=%s" start-border end-border start end exc-mode) +;; (list start-border end-border))))))) +;; (mumamo-find-possible-chunk pos min max +;; search-bw-exc-start +;; search-bw-exc-end +;; search-fw-exc-start +;; search-fw-exc-end +;; find-borders))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Changing the major mode that the user sees + +(defvar mumamo-unread-command-events-timer nil) +(make-variable-buffer-local 'mumamo-unread-command-events-timer) + +(defun mumamo-unread-command-events (command-keys new-major old-last-command) + "Sync new keymaps after changing major mode in a timer. +Also tell new major mode. + +COMMAND-KEYS is the keys entered after last command and the call +to `mumamo-idle-set-major-mode' \(which is done in an idle +timer). Those keys are added to `unread-command-events' so they +can be used in the new keymaps. They should be in the format +returned by + + \(listify-key-sequence (this-command-keys-vector)) + +NEW-MAJOR mode is the new major mode. + +OLD-LAST-COMMAND is the value of `last-command' after switching +major mode. \(This is cleared by the function `top-level' so +this function will not see it since it is run in a timer.)" + (mumamo-condition-case err + (progn + ;; last-command seems to be cleared by top-level so set it + ;; back here. + (unless last-command + (setq last-command old-last-command)) + (when (< 0 (length command-keys)) + ;;(setq last-command-char nil) ;; For `viper-command-argument' + (setq unread-command-events (append command-keys nil))) + (message "Switched to %s" new-major)) + (error + (let ((mumamo-display-error-lwarn t)) + (mumamo-display-error 'mumamo-unread-command-events "err=%s" err))))) + +(defvar mumamo-idle-set-major-mode-timer nil) +(make-variable-buffer-local 'mumamo-idle-set-major-mode-timer) +(put 'mumamo-idle-set-major-mode-timer 'permanent-local t) + +(defun mumamotemp-pre-command () + "Temporary command for debugging." + (message "mumamotemp-pre 1: modified=%s %s" (buffer-modified-p) (current-buffer))) +(defun mumamotemp-post-command () + "Temporary command for debugging." + (message "mumamotemp-post 1: modified=%s %s" (buffer-modified-p) (current-buffer))) +(put 'mumamotemp-pre-command 'permanent-local-hook t) +(put 'mumamotemp-post-command 'permanent-local-hook t) +(defun mumamotemp-start () + "Temporary command for debugging." + (add-hook 'post-command-hook 'mumamotemp-post-command nil t) + (add-hook 'pre-command-hook 'mumamotemp-pre-command nil t)) + +(defsubst mumamo-cancel-idle-set-major-mode () + (when (timerp mumamo-idle-set-major-mode-timer) + (cancel-timer mumamo-idle-set-major-mode-timer)) + (setq mumamo-idle-set-major-mode-timer nil)) + +(defun mumamo-request-idle-set-major-mode () + "Setup to change major mode from chunk when Emacs is idle." + (mumamo-cancel-idle-set-major-mode) + (setq mumamo-idle-set-major-mode-timer + (run-with-idle-timer + mumamo-set-major-mode-delay + nil + 'mumamo-idle-set-major-mode (current-buffer) (selected-window)))) + +(defvar mumamo-done-first-set-major nil) +(make-variable-buffer-local 'mumamo-done-first-set-major) +(put 'mumamo-done-first-set-major 'permanent-local t) + +;; Fix-me: Add a property to the symbol instead (like in CUA). +(defvar mumamo-safe-commands-in-wrong-major + '(self-insert-command + fill-paragraph ;; It changes major mode + forward-char + viper-forward-char + backward-char + viper-backward-char + next-line + viper-next-line + previous-line + viper-previous-line + scroll-down + cua-scroll-down + scroll-up + cua-scroll-up + move-beginning-of-line + move-end-of-line + nonincremental-search-forward + nonincremental-search-backward + mumamo-backward-chunk + mumamo-forward-chunk + ;; Fix-me: add more + ) + ) + +(defun mumamo-fetch-local-map (major) + "Fetch local keymap for major mode MAJOR. +Do that by turning on the major mode in a new buffer. Add the +keymap to `mumamo-major-modes-local-maps'. + +Return the fetched local map." + (let (temp-buf-name + temp-buf + local-map) + (setq temp-buf-name (concat "mumamo-fetch-major-mode-local-" + (symbol-name major))) + (setq temp-buf (get-buffer temp-buf-name)) + (when temp-buf (kill-buffer temp-buf)) + (setq temp-buf (get-buffer-create temp-buf-name)) + (with-current-buffer temp-buf + (let ((mumamo-fetching-major t)) + (funcall major)) + (setq local-map (current-local-map)) + (when local-map (setq local-map (copy-keymap (current-local-map)))) + (add-to-list 'mumamo-major-modes-local-maps + (cons major-mode local-map))) + (kill-buffer temp-buf) + local-map)) + +(defvar mumamo-post-command-chunk nil) +(make-variable-buffer-local 'mumamo-post-command-chunk) + +(defun mumamo-post-command-get-chunk (pos) + "Get chunk at POS fast." + (let ((have-regions (and (boundp 'mumamo-regions) + mumamo-regions))) + (when have-regions (setq mumamo-post-command-chunk nil)) + (if (and mumamo-post-command-chunk + (overlayp mumamo-post-command-chunk) + ;;(progn (message "here a=%s" mumamo-post-command-chunk) t) + (overlay-buffer mumamo-post-command-chunk) + ;;(progn (message "here b=%s" mumamo-post-command-chunk) t) + (< pos (overlay-end mumamo-post-command-chunk)) + ;;(progn (message "here c=%s" mumamo-post-command-chunk) t) + (>= pos (overlay-start mumamo-post-command-chunk)) + ;;(progn (message "here d=%s" mumamo-post-command-chunk) t) + (mumamo-chunk-major-mode mumamo-post-command-chunk) + ;;(progn (msgtrc "here e=%s" mumamo-post-command-chunk) t) + ) + mumamo-post-command-chunk + ;;(msgtrc "--------------- new post-command-chunk") + (setq mumamo-post-command-chunk + (or (unless have-regions (mumamo-get-existing-new-chunk-at (point) nil)) + (mumamo-find-chunks (point) "post-command-get-chunk")))))) + +;; (setq mumamo-set-major-mode-delay 10) +(defun mumamo-set-major-post-command () + "Change major mode if necessary after a command. +If the major mode for chunk at `window-point' differ from current +major mode then change major mode to that for the chunk. If +however `mumamo-set-major-mode-delay' is greater than 0 just +request a change of major mode when Emacs is idle that long. + +See the variable above for an explanation why a delay might be +needed \(and is the default)." + ;;(msgtrc "set-major-post-command here") + (let* ((in-pre-hook (memq 'mumamo-set-major-pre-command pre-command-hook)) + (ovl (unless in-pre-hook (mumamo-post-command-get-chunk (point)))) + (major (when ovl (mumamo-chunk-major-mode ovl))) + (set-it-now (not (or in-pre-hook (mumamo-fun-eq major major-mode))))) + ;;(msgtrc "set-major-post-command ovl=%s, in-pre-hook=%s" ovl in-pre-hook) + (if (not set-it-now) + (unless (mumamo-fun-eq major major-mode) + (when mumamo-idle-set-major-mode-timer + (mumamo-request-idle-set-major-mode))) + (if mumamo-done-first-set-major + (if (<= 0 mumamo-set-major-mode-delay) + ;; Window point has been moved to a new chunk with a new + ;; major mode. Major mode will not be changed directly, + ;; but in an idle timer or in pre-command-hook. To avoid + ;; that the user get the wrong key bindings for the new + ;; chunk fetch the local map directly and apply that. + (let* ((map-rec (assoc major mumamo-major-modes-local-maps)) + (map (cdr map-rec))) + (unless map + (setq map (mumamo-fetch-local-map major))) + (unless (eq map 'no-local-map) + (use-local-map map)) + (add-hook 'pre-command-hook 'mumamo-set-major-pre-command nil t) + (mumamo-request-idle-set-major-mode)) + (mumamo-set-major major ovl) + (message "Switched to %s" major-mode)) + (mumamo-set-major major ovl))))) + +(defun mumamo-set-major-pre-command () + "Change major mode if necessary before a command. +When the key sequence that invoked the command is in current +local map and major mode is not the major mode for the current +mumamo chunk then set major mode to that for the chunk." + (mumamo-condition-case err + ;; First see if we can avoid changing major mode + (if (memq this-command mumamo-safe-commands-in-wrong-major) + (mumamo-request-idle-set-major-mode) + ;;(message "pre point=%s" (point)) + (let* ((ovl (mumamo-find-chunks (point) "mumamo-set-major-pre-command")) + (major (mumamo-chunk-major-mode ovl))) + ;;(message "pre point=%s" (point)) + (if (not major) + (lwarn '(mumamo-set-major-pre-command) :error "major=%s" major) + (when (or (not (mumamo-fun-eq major-mode major)) + (not (mumamo-set-major-check-keymap))) + (setq major-mode nil) + (mumamo-set-major major ovl) + ;; Unread the last command key sequence + (setq unread-command-events + (append (listify-key-sequence (this-command-keys-vector)) + unread-command-events)) + ;; Some commands, like `viper-command-argument' need to + ;; know the last command, so tell them. + (setq this-command (lambda () + (interactive) + (setq this-command last-command))))))) + (error + (mumamo-display-error 'mumamo-set-major-pre-command + "cb:%s, %s" (current-buffer) (error-message-string err))))) + +(defun mumamo-idle-set-major-mode (buffer window) + "Set major mode from mumamo chunk when Emacs is idle. +Do this only if current buffer is BUFFER and then do it in window +WINDOW. + +See the variable `mumamo-set-major-mode-delay' for an +explanation." + (save-match-data ;; runs in idle timer + (mumamo-msgfntfy "mumamo-idle-set-major-mode b=%s, window=%s" buffer window) + (with-selected-window window + ;; According to Stefan Monnier we need to set the buffer too. + (with-current-buffer (window-buffer window) + (when (eq buffer (current-buffer)) + (mumamo-condition-case err + ;;(let* ((ovl (mumamo-get-chunk-at (point))) + ;;(message "idle point=%s" (point)) + (let* ((ovl (mumamo-find-chunks (point) "mumamo-idle-set-major-mode")) + (major (mumamo-chunk-major-mode ovl)) + (modified (buffer-modified-p))) + ;;(message "idle point=%s" (point)) + (unless (mumamo-fun-eq major major-mode) + ;;(message "mumamo-set-major at A") + (mumamo-set-major major ovl) + ;; Fix-me: This is a bug workaround. Possibly in Emacs. + (when (and (buffer-modified-p) + (not modified)) + (set-buffer-modified-p nil)) + ;; sync keymap + (when (timerp mumamo-unread-command-events-timer) + (cancel-timer mumamo-unread-command-events-timer)) + (when unread-command-events + ;; Save unread keys before calling `top-level' which + ;; will clear them. + (setq mumamo-unread-command-events-timer + (run-with-idle-timer + 0 nil + 'mumamo-unread-command-events + unread-command-events + major last-command)) + (top-level) + ))) + (error + (mumamo-display-error 'mumamo-idle-set-major-mode + "cb=%s, err=%s" (current-buffer) err)))))))) + +(defun mumamo-post-command-1 (&optional no-debug) + "See `mumamo-post-command'. +Turn on `debug-on-error' unless NO-DEBUG is nil." + (unless no-debug (setq debug-on-error t)) + (setq mumamo-find-chunks-level 0) + (mumamo-msgfntfy "mumamo-post-command-1 ENTER: font-lock-mode=%s" font-lock-mode) + (if font-lock-mode + (mumamo-set-major-post-command) + ;;(mumamo-on-font-lock-off) + ) + ;;(msgtrc "mumamo-post-command-1 EXIT: font-lock-keywords-only =%s" (default-value 'font-lock-keywords-only)) + ) + + + + +(defvar mumamo-bug-3467-w14 41) +(defvar mumamo-bug-3467-w15 51) +;;(mumamo-check-has-bug3467 t) +;;(kill-local-variable 'mumamo-bug-3467-w14) +(defun mumamo-check-has-bug3467 (verbose) + (let ((has-bug nil)) + (with-temp-buffer + (let ((mumamo-bug-3467-w14 42) + (mumamo-bug-3467-w15 52)) + (when verbose (message "mumamo-bug-3467-w14 maybe let: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w14 (default-value 'mumamo-bug-3467-w14))) + (when verbose (message "mumamo-bug-3467-w15 maybe let: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w15 (default-value 'mumamo-bug-3467-w15))) + (set (make-local-variable 'mumamo-bug-3467-w14) 43) + (set-default 'mumamo-bug-3467-w14 44) + (set-default 'mumamo-bug-3467-w15 54) + (when verbose (message "mumamo-bug-3467-w14 maybe let: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w14 (default-value 'mumamo-bug-3467-w14))) + (when verbose (message "mumamo-bug-3467-w15 maybe let: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w15 (default-value 'mumamo-bug-3467-w15)))) + (when verbose (message "mumamo-bug-3467-w14 top level: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w14 (default-value 'mumamo-bug-3467-w14))) + (when (/= mumamo-bug-3467-w14 43) (setq has-bug t)) + (when (/= (default-value 'mumamo-bug-3467-w14) 41) (setq has-bug t)) + (when verbose (message "mumamo-bug-3467-w15 top level: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w15 (default-value 'mumamo-bug-3467-w15))) + ) + (when verbose (message "mumamo-bug-3467-w14 top level: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w14 (default-value 'mumamo-bug-3467-w14))) + (when verbose (message "mumamo-bug-3467-w15 top level: in buffer %s=%S, global=%S" (current-buffer) mumamo-bug-3467-w15 (default-value 'mumamo-bug-3467-w15))) + (or has-bug + (local-variable-p 'mumamo-bug-3467-w14) + (/= (default-value 'mumamo-bug-3467-w14) 41) + ) + )) + +(defvar mumamo-has-bug3467 (mumamo-check-has-bug3467 nil)) + +(defun mumamo-emacs-start-bug3467-timer-if-needed () + "Work around for Emacs bug 3467. The only one I have found." + (when mumamo-has-bug3467 + (run-with-idle-timer 0 nil 'mumamo-emacs-bug3467-workaround))) + +(defun mumamo-emacs-bug3467-workaround () + "Work around for Emacs bug 3467. The only one I have found." + (set-default 'font-lock-keywords-only nil)) + + + + +(defun mumamo-post-command () + "Run this in `post-command-hook'. +Change major mode if necessary." + ;;(msgtrc "mumamo-post-command") + (when mumamo-multi-major-mode + (mumamo-condition-case err + (mumamo-post-command-1 t) + (error + (mumamo-msgfntfy "mumamo-post-command %S" err) + ;; Warnings are to disturbing when run in post-command-hook, + ;; but this message is important so show it with an highlight. + (message + (propertize + "%s\n- Please try M-: (mumamo-post-command-1) to see what happened." + 'face 'highlight) + (error-message-string err)))))) + +(defun mumamo-change-major-function () + "Function added to `change-major-mode-hook'. +Remove mumamo when changing to a new major mode if the change is +not done because point was to a new chunk." + (unless mumamo-set-major-running + (mumamo-turn-off-actions))) + +(defun mumamo-derived-from-mode (major from-mode) + "Return t if major mode MAJOR is derived from FROM-MODE." + (let ((major-mode major)) + (derived-mode-p from-mode))) + +;; This is the new version of add-hook. For its origin see +;; http://lists.gnu.org/archive/html/emacs-devel/2007-12/msg00169.html +;; +;;(unless (> emacs-major-version 22) +(defvar mumamo-test-add-hook nil + "Internal use.") +(unless (and t + (let ((has-it nil)) + ;;(add-hook 'mumamo-test-add-hook 'mumamo-jit-lock-after-change nil t) + (add-hook 'mumamo-test-add-hook 'mumamo-after-change nil t) + (setq has-it (eq 'permanent-local-hook + (get 'mumamo-test-add-hook 'permanent-local))) + has-it)) + (defun add-hook (hook function &optional append local) + "Add to the value of HOOK the function FUNCTION. +FUNCTION is not added if already present. +FUNCTION is added (if necessary) at the beginning of the hook list +unless the optional argument APPEND is non-nil, in which case +FUNCTION is added at the end. + +The optional fourth argument, LOCAL, if non-nil, says to modify +the hook's buffer-local value rather than its default value. +This makes the hook buffer-local if needed, and it makes t a member +of the buffer-local value. That acts as a flag to run the hook +functions in the default value as well as in the local value. + +HOOK should be a symbol, and FUNCTION may be any valid function. If +HOOK is void, it is first set to nil. If HOOK's value is a single +function, it is changed to a list of functions." + (or (boundp hook) (set hook nil)) + (or (default-boundp hook) (set-default hook nil)) + (if local (unless (local-variable-if-set-p hook) + (set (make-local-variable hook) (list t))) + ;; Detect the case where make-local-variable was used on a hook + ;; and do what we used to do. + (unless (and (consp (symbol-value hook)) (memq t (symbol-value hook))) + (setq local t))) + (let ((hook-value (if local (symbol-value hook) (default-value hook)))) + ;; If the hook value is a single function, turn it into a list. + (when (or (not (listp hook-value)) (eq (car hook-value) 'lambda)) + (setq hook-value (list hook-value))) + ;; Do the actual addition if necessary + (unless (member function hook-value) + (setq hook-value + (if append + (append hook-value (list function)) + (cons function hook-value)))) + ;; Set the actual variable + (if local + (progn + ;; If HOOK isn't a permanent local, + ;; but FUNCTION wants to survive a change of modes, + ;; mark HOOK as partially permanent. + (and (symbolp function) + (get function 'permanent-local-hook) + (not (get hook 'permanent-local)) + (put hook 'permanent-local 'permanent-local-hook)) + (set hook hook-value)) + (set-default hook hook-value)))) + ) + + +(defvar mumamo-survive-hooks + '( + ;; activate-mark-hook after-change-functions after-save-hook + ;; before-save-functions auto-save-hook before-revert-hook + ;; buffer-access-fontify-functions calendar-load-hook + ;; command-line-functions compilation-finish-function + ;; deactivate-mark-hook find-file-hook + ;; find-file-not-found-functions first-change-hook + ;; kbd-macro-termination-hook kill-buffer-hook + ;; kill-buffer-query-functions menu-bar-update-hook + ;; post-command-hook pre-abbrev-expand-hook pre-command-hook + ;; write-contents-functions write-file-functions + ;; write-region-annotate-functions + ;; c-special-indent-hook + )) + +;; +;; Emulation modes +;; +;; These variables should have 'permanant-local t set in their +;; packages IMO, but now they do not have that. +(eval-after-load 'viper-cmd + (progn + (put 'viper-after-change-functions 'permanent-local t) + (put 'viper-before-change-functions 'permanent-local t) + )) +(eval-after-load 'viper + (progn + (put 'viper-post-command-hooks 'permanent-local t) + (put 'viper-pre-command-hooks 'permanent-local t) + ;;minor-mode-map-alist + ;; viper-mode-string -- is already buffer local, globally void + (put 'viper-mode-string 'permanent-local t) + )) +;;viper-tut--part +(eval-after-load 'viper-init + (progn + (put 'viper-d-com 'permanent-local t) + (put 'viper-last-insertion 'permanent-local t) + (put 'viper-command-ring 'permanent-local t) + (put 'viper-vi-intercept-minor-mode 'permanent-local t) + (put 'viper-vi-basic-minor-mode 'permanent-local t) + (put 'viper-vi-local-user-minor-mode 'permanent-local t) + (put 'viper-vi-global-user-minor-mode 'permanent-local t) + (put 'viper-vi-state-modifier-minor-mode 'permanent-local t) + (put 'viper-vi-diehard-minor-mode 'permanent-local t) + (put 'viper-vi-kbd-minor-mode 'permanent-local t) + (put 'viper-insert-intercept-minor-mode 'permanent-local t) + (put 'viper-insert-basic-minor-mode 'permanent-local t) + (put 'viper-insert-local-user-minor-mode 'permanent-local t) + (put 'viper-insert-global-user-minor-mode 'permanent-local t) + (put 'viper-insert-state-modifier-minor-mode 'permanent-local t) + (put 'viper-insert-diehard-minor-mode 'permanent-local t) + (put 'viper-insert-kbd-minor-mode 'permanent-local t) + (put 'viper-replace-minor-mode 'permanent-local t) + (put 'viper-emacs-intercept-minor-mode 'permanent-local t) + (put 'viper-emacs-local-user-minor-mode 'permanent-local t) + (put 'viper-emacs-global-user-minor-mode 'permanent-local t) + (put 'viper-emacs-kbd-minor-mode 'permanent-local t) + (put 'viper-emacs-state-modifier-minor-mode 'permanent-local t) + (put 'viper-vi-minibuffer-minor-mode 'permanent-local t) + (put 'viper-insert-minibuffer-minor-mode 'permanent-local t) + (put 'viper-automatic-iso-accents 'permanent-local t) + (put 'viper-special-input-method 'permanent-local t) + (put 'viper-intermediate-command 'permanent-local t) + ;; already local: viper-undo-needs-adjustment + (put 'viper-began-as-replace 'permanent-local t) + ;; already local: viper-replace-overlay + ;; already local: viper-last-posn-in-replace-region + ;; already local: viper-last-posn-while-in-insert-state + ;; already local: viper-sitting-in-replace + (put 'viper-replace-chars-to-delete 'permanent-local t) + (put 'viper-replace-region-chars-deleted 'permanent-local t) + (put 'viper-current-state 'permanent-local t) + (put 'viper-cted 'permanent-local t) + (put 'viper-current-indent 'permanent-local t) + (put 'viper-preserve-indent 'permanent-local t) + (put 'viper-auto-indent 'permanent-local t) + (put 'viper-electric-mode 'permanent-local t) + ;; already local: viper-insert-point + ;; already local: viper-pre-command-point + (put 'viper-com-point 'permanent-local t) + (put 'viper-ex-style-motion 'permanent-local t) + (put 'viper-ex-style-editing 'permanent-local t) + (put 'viper-ESC-moves-cursor-back 'permanent-local t) + (put 'viper-delete-backwards-in-replace 'permanent-local t) + ;; already local: viper-related-files-and-buffers-ring + (put 'viper-local-search-start-marker 'permanent-local t) + (put 'viper-search-overlay 'permanent-local t) + (put 'viper-last-jump 'permanent-local t) + (put 'viper-last-jump-ignore 'permanent-local t) + (put 'viper-minibuffer-current-face 'permanent-local t) + ;; already local: viper-minibuffer-overlay + (put 'viper-command-ring 'permanent-local t) + (put 'viper-last-insertion 'permanent-local t) + )) +(eval-after-load 'viper-keym + (progn + ;; already local: viper-vi-local-user-map + ;; already local: viper-insert-local-user-map + ;; already local: viper-emacs-local-user-map + (put 'viper--key-maps 'permanent-local t) + (put 'viper--intercept-key-maps 'permanent-local t) + ;; already local: viper-need-new-vi-local-map + ;; already local: viper-need-new-insert-local-map + ;; already local: viper-need-new-emacs-local-map + )) +(eval-after-load 'viper-mous + (progn + (put 'viper-mouse-click-search-noerror 'permanent-local t) + (put 'viper-mouse-click-search-limit 'permanent-local t) + )) +(eval-after-load 'viper-util + (progn + (put 'viper-syntax-preference 'permanent-local t) + (put 'viper-non-word-characters 'permanent-local t) + (put 'viper-ALPHA-char-class 'permanent-local t) + )) + +(eval-after-load 'cua-base + (progn + (put 'cua-inhibit-cua-keys 'permanent-local t) + (put 'cua--explicit-region-start 'permanent-local t) + (put 'cua--status-string 'permanent-local t) + )) +;; This is for the defvar in ido.el: +(eval-after-load 'ido + (progn + (put 'cua-inhibit-cua-keys 'permanent-local t) + )) +(eval-after-load 'cua-rect + (progn + (put 'cua--rectangle 'permanent-local t) + (put 'cua--rectangle-overlays 'permanent-local t) + )) +(eval-after-load 'edt + (progn + (put 'edt-select-mode 'permanent-local t) + )) +(eval-after-load 'tpu-edt + (progn + (put 'tpu-newline-and-indent-p 'permanent-local t) + (put 'tpu-newline-and-indent-string 'permanent-local t) + (put 'tpu-saved-delete-func 'permanent-local t) + (put 'tpu-buffer-local-map 'permanent-local t) + (put 'tpu-mark-flag 'permanent-local t) + )) +(eval-after-load 'vi + (progn + (put 'vi-add-to-mode-line 'permanent-local t) + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-scroll-amount + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-shift-width + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-ins-point + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-ins-length + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-ins-repetition + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-ins-overwrt-p + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-ins-prefix-code + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-last-change-command + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-last-shell-command + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-last-find-char + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-mark-alist + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-insert-state + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-mode-old-local-map + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-mode-old-mode-name + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-mode-old-major-mode + ;;Warning (mumamo-per-buffer-local-vars): Not a local variable: vi-mode-old-case-fold + ;; + )) +(eval-after-load 'vi + (progn + (put 'vip-emacs-local-map 'permanent-local t) + (put 'vip-insert-local-map 'permanent-local t) + (put 'vip-insert-point 'permanent-local t) + (put 'vip-com-point 'permanent-local t) + (put 'vip-current-mode 'permanent-local t) + (put 'vip-emacs-mode-line-buffer-identification 'permanent-local t) + (put 'vip-current-major-mode 'permanent-local t) + )) + +(eval-after-load 'hi-lock + (progn + (put 'hi-lock-mode 'permanent-local t) + )) + +;; +;; Minor modes that are not major mode specific +;; + +(put 'visual-line-mode 'permanent-local t) + +(eval-after-load 'flymake + (progn + ;; hook functions: + (put 'flymake-after-change-function 'permanent-local-hook t) + (put 'flymake-after-save-hook 'permanent-local-hook t) + (put 'flymake-kill-buffer-hook 'permanent-local-hook t) + ;; hooks: +;;; (put 'after-change-functions 'permanent-local 'permanent-local-hook) +;;; (put 'after-save-hook 'permanent-local 'permanent-local-hook) +;;; (put 'kill-buffer-hook 'permanent-local 'permanent-local-hook) + ;; vars: + (put 'flymake-mode 'permanent-local t) + (put 'flymake-is-running 'permanent-local t) + (put 'flymake-timer 'permanent-local t) + (put 'flymake-last-change-time 'permanent-local t) + (put 'flymake-check-start-time 'permanent-local t) + (put 'flymake-check-was-interrupted 'permanent-local t) + (put 'flymake-err-info 'permanent-local t) + (put 'flymake-new-err-info 'permanent-local t) + (put 'flymake-output-residual 'permanent-local t) + (put 'flymake-mode-line 'permanent-local t) + (put 'flymake-mode-line-e-w 'permanent-local t) + (put 'flymake-mode-line-status 'permanent-local t) + (put 'flymake-temp-source-file-name 'permanent-local t) + (put 'flymake-master-file-name 'permanent-local t) + (put 'flymake-temp-master-file-name 'permanent-local t) + (put 'flymake-base-dir 'permanent-local t))) + +;; (eval-after-load 'imenu +;; (progn +;; ;; Fix-me: imenu is only useful for main major mode. The menu +;; ;; disappears in sub chunks because it is tighed to +;; ;; local-map. Don't know what to do about that. I do not +;; ;; understand the reason for binding it to local-map, but I +;; ;; suspect the intent is to have different menu items for +;; ;; different modes. Could not that be achieved by deleting the +;; ;; menu and creating it again when changing major mode? (That must +;; ;; be implemented in imenu.el of course.) +;; ;; +;; ;; hook functions: +;; ;;; (put 'imenu-update-menubar 'permanent-local-hook t) +;; ;; hooks: +;; (put 'menu-bar-update-hook 'permanent-local 'permanent-local-hook) +;; ;; vars: +;; (put 'imenu-generic-expression 'permanent-local t) +;; (put 'imenu-create-index-function 'permanent-local t) +;; (put 'imenu-prev-index-position-function 'permanent-local t) +;; (put 'imenu-extract-index-name-function 'permanent-local t) +;; (put 'imenu-name-lookup-function 'permanent-local t) +;; (put 'imenu-default-goto-function 'permanent-local t) +;; (put 'imenu--index-alist 'permanent-local t) +;; (put 'imenu--last-menubar-index-alist 'permanent-local t) +;; (put 'imenu-syntax-alist 'permanent-local t) +;; (put 'imenu-case-fold-search 'permanent-local t) +;; (put 'imenu-menubar-modified-tick 'permanent-local t) +;; )) + +(eval-after-load 'longlines + (progn + ;; Fix-me: take care of longlines-mode-off + (put 'longlines-mode 'permanent-local t) + (put 'longlines-wrap-beg 'permanent-local t) + (put 'longlines-wrap-end 'permanent-local t) + (put 'longlines-wrap-point 'permanent-local t) + (put 'longlines-showing 'permanent-local t) + (put 'longlines-decoded 'permanent-local t) + ;; + (put 'longlines-after-change-function 'permanent-local-hook t) + (put 'longlines-after-revert-hook 'permanent-local-hook t) + (put 'longlines-before-revert-hook 'permanent-local-hook t) + (put 'longlines-decode-buffer 'permanent-local-hook t) + (put 'longlines-decode-region 'permanent-local-hook t) + (put 'longlines-mode-off 'permanent-local-hook t) + (put 'longlines-post-command-function 'permanent-local-hook t) + (put 'longlines-window-change-function 'permanent-local-hook t) + ;;(put 'mail-indent-citation 'permanent-local-hook t) + )) + + +;; Fix-me: Rails, many problematic things: + +;;; Fix-me: No idea about these, where are they used?? Add them to +;;; mumamo-per-buffer-local-vars?: +;; predictive-main-dict +;; predictive-prog-mode-main-dict +;; predictive-use-auto-learn-cache +;; predictive-dict-autosave-on-kill-buffer +(eval-after-load 'inf-ruby + (progn + (put 'inferior-ruby-first-prompt-pattern 'permanent-local t) + (put 'inferior-ruby-prompt-pattern 'permanent-local t) + )) + +;;; These are for the output buffer (no problems): +;; font-lock-keywords-only +;; font-lock-defaults -- always buffer local +;; scroll-margin +;; scroll-preserve-screen-position + +(eval-after-load 'rails-script + (progn + (put 'rails-script:run-after-stop-hook 'permanent-local t) + (put 'rails-script:show-buffer-hook 'permanent-local t) + (put 'rails-script:output-mode-ret-value 'permanent-local t) + )) + +;;; No problems I believe (it is in output buffer): +;; compilation-error-regexp-alist-alist +;; compilation-error-regexp-alist + +;;; Fix-me: This is in the minor mode, what to do? Looks like it +;;; should have 'permanent-local t - in this case. I have added it to +;;; mumamo-per-buffer-local-vars for now. +;; tags-file-name + +(eval-after-load 'rails + (progn + (put 'rails-primary-switch-func 'permanent-local t) + (put 'rails-secondary-switch-func 'permanent-local t) + )) + +;; (defun test-js-perm () +;; (put 'js--quick-match-re 'permanent-local t) +;; (put 'js--quick-match-re-func 'permanent-local t) +;; (put 'js--cache-end 'permanent-local t) +;; (put 'js--last-parse-pos 'permanent-local t) +;; (put 'js--state-at-last-parse-pos 'permanent-local t) +;; (put 'js--tmp-location 'permanent-local t)) +;; (test-js-perm) + +(defvar mumamo-per-buffer-local-vars + '( + buffer-file-name + left-margin-width + right-margin-width + ;; Fix-me: This is to prevent font-lock-mode turning off/on, but + ;; is it necessary? + ;;font-lock-mode-major-mode + tags-file-name + nxhtml-menu-mode + ;; Fix-me: adding rng timers here stops Emacs from looping after + ;; indenting in ind-0-error.php, but I have no clue why. Hm. This + ;; problem is gone, but I forgot why. + rng-c-current-token ;;rng-cmpct.el:132:(make-variable-buffer-local 'rng-c-current-token) + rng-c-escape-positions ;;rng-cmpct.el:341:(make-variable-buffer-local 'rng-c-escape-positions) + rng-c-file-name ;;rng-cmpct.el:344:(make-variable-buffer-local 'rng-c-file-name) + rng-current-schema-file-name ;;rng-loc.el:37:(make-variable-buffer-local 'rng-current-schema-file-name) + rng-current-schema ;;rng-pttrn.el:71:(make-variable-buffer-local 'rng-current-schema) + ;;rng-validate-timer is permanent-local t + ;;rng-validate-timer ;;rng-valid.el:141:(make-variable-buffer-local 'rng-validate-timer) + ;;rng-validate-quick-timer is permanent-local t + ;;rng-validate-quick-timer ;;rng-valid.el:146:(make-variable-buffer-local 'rng-validate-quick-timer) + rng-error-count ;;rng-valid.el:153:(make-variable-buffer-local 'rng-error-count) + rng-message-overlay ;;rng-valid.el:158:(make-variable-buffer-local 'rng-message-overlay) + rng-message-overlay-inhibit-point ;;rng-valid.el:165:(make-variable-buffer-local 'rng-message-overlay-inhibit-point) + rng-message-overlay-current ;;rng-valid.el:169:(make-variable-buffer-local 'rng-message-overlay-current) + rng-validate-up-to-date-end ;;rng-valid.el:188:(make-variable-buffer-local 'rng-validate-up-to-date-end) + rng-conditional-up-to-date-start ;;rng-valid.el:199:(make-variable-buffer-local 'rng-conditional-up-to-date-start) + rng-conditional-up-to-date-end ;;rng-valid.el:205:(make-variable-buffer-local 'rng-conditional-up-to-date-end) + rng-validate-mode ;;rng-valid.el:212:(make-variable-buffer-local 'rng-validate-mode) + rng-dtd ;;rng-valid.el:215:(make-variable-buffer-local 'rng-dtd) + + nxml-syntax-highlight-flag ;; For pre-Emacs nxml + ;;nxml-ns-state - not buffer local currently + nxml-prolog-regions ;;snxml-mode.el:362:(make-variable-buffer-local 'nxml-prolog-regions) + nxml-last-fontify-end ;;dnxml-mode.el:367:(make-variable-buffer-local 'nxml-last-fontify-end) + nxml-degraded ;;dnxml-mode.el:373:(make-variable-buffer-local 'nxml-degraded) + nxml-char-ref-extra-display ;;ynxml-mode.el:397:(make-variable-buffer-local 'nxml-char-ref-extra-display) + nxml-prolog-end ;;dnxml-rap.el:92:(make-variable-buffer-local 'nxml-prolog-end) + nxml-scan-end ;;dnxml-rap.el:107:(make-variable-buffer-local 'nxml-scan-end) + + ;;buffer-invisibility-spec + ;;header-line-format + + ;; Fix-me: These must be handled with 'permanent-local since they may be changed: + line-move-visual ;;simple.el:4537: (kill-local-variable 'line-move-visual) + word-wrap ;;simple.el:4538: (kill-local-variable 'word-wrap) + truncate-lines ;;simple.el:4539: (kill-local-variable 'truncate-lines) + truncate-partial-width-windows ;;simple.el:4540: (kill-local-variable 'truncate-partial-width-windows) + fringe-indicator-alist ;;simple.el:4541: (kill-local-variable 'fringe-indicator-alist) + visual-line--saved-state ;;simple.el:4544: (kill-local-variable 'visual-line--saved-state))) + vis-mode-saved-buffer-invisibility-spec ;;simple.el:6237: (kill-local-variable 'vis-mode-saved-buffer-invisibility-spec)) + + ) + "Per buffer local variables. +See also `mumamo-per-main-major-local-vars'.") + +;; Fix-me: use this, but how exactly? I think the var values must be +;; picked up at every change from main major mode. And restored after +;; changing to the new major mode - but maybe a bit differently if +;; this is the main major mode. +(defvar mumamo-per-main-major-local-vars + '( + buffer-invisibility-spec + header-line-format + ) + "Per main major local variables. +Like `mumamo-per-buffer-local-vars', but this is fetched from the +main major mode.") + +;; (when nil +;; (make-variable-buffer-local 'mumamo-survive-minor-modes) +;; (put 'mumamo-survive-minor-modes 'permanent-local t) +;; (defvar mumamo-survive-minor-modes nil +;; "Hold local minor mode variables specific major modes. +;; Those values are saved when leaving a chunk with a certain +;; major mode and restored when entering a chunk with the same +;; major mode again. + +;; The value of this variable is an associative list where the key +;; is a list with + +;; \(MAJOR-MODE MINOR-MODE) + +;; and the value is a stored value for the minor mode.") +;; ) + +(defun mumamo-make-variable-buffer-permanent (var) + "Make buffer local value of VAR survive when moving point to a new chunk. +When point is moved between chunks in a multi major mode the +major mode will be changed. This will by default kill all local +variables unless they have a non-nil `permanent-local' property +\(see info node `(elisp)Creating Buffer-Local'). + +If you do not want to put a `permanent-local' property on a +variable you can instead use this function to make variable VAR +survive chunk switches in all mumamo multi major mode buffers." + ;; If you want it to survive chunk switches only in the current + ;; buffer then use `mumamo-make-local-permanent' instead." + (pushnew var (default-value 'mumamo-per-buffer-local-vars))) + +;; ;; Fix-me: use local value +;; ;; Fix-me: delelete local value when exiting mumamo +;; (defun mumamo-make-local-permanent (var) +;; "Make buffer local value of VAR survive when moving point to a new chunk. +;; This is for the current buffer only. +;; In most cases you almost certainly want to use +;; `mumamo-make-variable-buffer-permanent' instead." +;; (pushnew var mumamo-per-buffer-local-vars)) + +(defvar mumamo-per-buffer-local-vars-done-by-me nil + "Variables set by mumamo already. +Used to avoid unnecessary warnings if setting major mode fails.") + +;; (mumamo-hook-p 'viper-pre-command-hooks) +;; (mumamo-hook-p 'viper-before-change-functions) +;; (mumamo-hook-p 'c-special-indent-hook) +(defun mumamo-hook-p (sym) + "Try to detect if SYM is a hook variable. +Just check the name." + (let ((name (symbol-name sym))) + (or (string= "-hook" (substring name -5)) + (string= "-hooks" (substring name -6)) + (string= "-functions" (substring name -10))))) + +(defvar mumamo-major-mode nil) +(make-variable-buffer-local 'mumamo-major-mode) +(put 'mumamo-major-mode 'permanent-local t) + +(defvar mumamo-change-major-mode-no-nos + '((font-lock-change-mode t) + (longlines-mode-off t) + global-font-lock-mode-cmhh + (nxml-cleanup t) + (turn-off-hideshow t)) + "Avoid running these in `change-major-mode-hook'.") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Remove things from hooks temporarily + +;; Fix-me: This is a bit disorganized, could not decide which level I +;; wanted this on. + +(defvar mumamo-after-change-major-mode-no-nos + '(;;nxhtml-global-minor-mode-enable-in-buffers + global-font-lock-mode-enable-in-buffers) + "Avoid running these in `after-change-major-mode-hook'.") + +(defvar mumamo-removed-from-hook nil) + +(defun mumamo-remove-from-hook (hook remove) + "From hook HOOK remove functions in list REMOVE. +Save HOOK and the list of functions removed to +`mumamo-removed-from-hook'." + (let (did-remove + removed) + (dolist (rem remove) + ;;(message "rem.rem=%s" rem) + (setq did-remove nil) + (if (listp rem) + (when (memq (car rem) (symbol-value hook)) + (setq did-remove t) + (remove-hook hook (car rem) t)) + (when (memq rem (symbol-value hook)) + (setq did-remove t) + (remove-hook hook rem))) + (when did-remove + (setq removed (cons rem removed)))) + (setq mumamo-removed-from-hook + (cons (cons hook removed) + mumamo-removed-from-hook)))) + +(defun mumamo-addback-to-hooks () + "Add back what was removed by `mumamo-remove-from-hook'." + ;;(message "mumamo-removed-from-hook=%s" mumamo-removed-from-hook) + (dolist (rem-rec mumamo-removed-from-hook) + (mumamo-addback-to-hook (car rem-rec) (cdr rem-rec)))) + +(defun mumamo-addback-to-hook (hook removed) + "Add to hook HOOK the list of functions in REMOVED." + ;;(message "addback: hook=%s, removed=%s" hook removed) + (dolist (rem removed) + ;;(message "add.rem=%s" rem) + (if (listp rem) + (add-hook hook (car rem) nil t) + (add-hook hook rem)))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; Compare mumamo-irrelevant-buffer-local-vars +(defvar mumamo-buffer-locals-dont-set + '( + adaptive-fill-mode + adaptive-fill-first-line-regexp + adaptive-fill-regexp + add-log-current-defun-header-regexp + auto-composition-function + auto-composition-mode + auto-composition-mode-major-mode + auto-fill-chars + + beginning-of-defun-function + buffer-auto-save-file-format + buffer-auto-save-file-name + buffer-backed-up + buffer-display-count + buffer-display-time + buffer-file-coding-system + buffer-file-format + buffer-file-name + buffer-file-truename + buffer-invisibility-spec + buffer-read-only + buffer-saved-size + buffer-undo-list + + c++-template-syntax-table + c-<-op-cont-regexp + c-<>-multichar-token-regexp + c->-op-cont-regexp + c-after-suffixed-type-decl-key + c-after-suffixed-type-maybe-decl-key + c-anchored-cpp-prefix + c-assignment-op-regexp + c-at-vsemi-p-fn + c-backslash-column + c-backslash-max-column + ;;c-basic-offset + c-before-font-lock-function + c-block-comment-prefix + c-block-comment-start-regexp + c-block-prefix-charset + c-block-stmt-1-key + c-block-stmt-2-key + c-brace-list-key + c-cast-parens + c-class-key + c-cleanup-list + c-colon-type-list-re + c-comment-only-line-offset + c-comment-prefix-regexp + c-comment-start-regexp + c-current-comment-prefix + c-decl-block-key + c-decl-hangon-key + c-decl-prefix-or-start-re + c-decl-prefix-re + c-decl-start-re + c-doc-comment-start-regexp + c-doc-comment-style + c-found-types + c-get-state-before-change-function + c-hanging-braces-alist + c-hanging-colons-alist + c-hanging-semi&comma-criteria + c-identifier-key + c-identifier-start + c-identifier-syntax-modifications + c-identifier-syntax-table + ;;c-indent-comment-alist + ;;c-indent-comments-syntactically-p + ;;c-indentation-style + c-keywords-obarray + c-keywords-regexp + c-known-type-key + c-label-kwds-regexp + c-label-minimum-indentation + c-label-prefix-re + c-line-comment-starter + c-literal-start-regexp + c-multiline-string-start-char + c-nonlabel-token-key + c-nonsymbol-chars + c-nonsymbol-token-regexp + c-not-decl-init-keywords + ;;c-offsets-alist + c-old-BOM + c-old-EOM + c-opt-<>-arglist-start + c-opt-<>-arglist-start-in-paren + c-opt-<>-sexp-key + c-opt-asm-stmt-key + c-opt-bitfield-key + c-opt-block-decls-with-vars-key + c-opt-block-stmt-key + c-opt-cpp-macro-define-id + c-opt-cpp-macro-define-start + c-opt-cpp-prefix + c-opt-cpp-start + c-opt-extra-label-key + c-opt-friend-key + c-opt-identifier-concat-key + c-opt-inexpr-brace-list-key + c-opt-method-key + c-opt-op-identifier-prefix + c-opt-postfix-decl-spec-key + c-opt-type-component-key + c-opt-type-concat-key + c-opt-type-modifier-key + c-opt-type-suffix-key + c-other-decl-block-key + c-other-decl-block-key-in-symbols-alist + c-overloadable-operators-regexp + c-paragraph-separate + c-paragraph-start + c-paren-stmt-key + c-prefix-spec-kwds-re + c-primary-expr-regexp + c-primitive-type-key + c-recognize-<>-arglists + c-recognize-colon-labels + c-recognize-knr-p + c-recognize-paren-inexpr-blocks + c-recognize-paren-inits + c-recognize-typeless-decls + c-regular-keywords-regexp + c-simple-stmt-key + c-special-brace-lists + c-special-indent-hook + c-specifier-key + c-stmt-delim-chars + c-stmt-delim-chars-with-comma + c-string-escaped-newlines + c-symbol-key + c-symbol-start + c-syntactic-eol + c-syntactic-ws-end + c-syntactic-ws-start + c-type-decl-end-used + c-type-decl-prefix-key + c-type-decl-suffix-key + c-type-prefix-key + c-vsemi-status-unknown-p-fn + + case-fold-search + comment-end + comment-end-skip + comment-indent-function + comment-line-break-function + comment-multi-line + comment-start + comment-start-skip + cursor-type + + default-directory + defun-prompt-regexp + delay-mode-hooks + + enable-multibyte-characters + end-of-defun-function + + fill-paragraph-function + font-lock-beginning-of-syntax-function + font-lock-defaults + font-lock-extend-after-change-region-function + font-lock-extend-region-functions + font-lock-fontified + font-lock-fontify-buffer-function + font-lock-fontify-region-function + font-lock-keywords + ;;font-lock-keywords-only + font-lock-keywords-case-fold-search + font-lock-mode + font-lock-mode-hook + font-lock-mode-major-mode + font-lock-multiline + font-lock-set-defaults + font-lock-syntactic-keywords + font-lock-syntactically-fontified + font-lock-syntax-table + font-lock-unfontify-buffer-function + font-lock-unfontify-region-function + fontification-functions + forward-sexp-function + + indent-line-function + indent-region-function + imenu--index-alist + imenu--last-menubar-index-alist + imenu-create-index-function + imenu-menubar-modified-tick + isearch-mode + + jit-lock-after-change-extend-region-functions + jit-lock-context-unfontify-pos + jit-lock-contextually + jit-lock-functions + jit-lock-mode + + line-move-ignore-invisible + local-abbrev-table + + major-mode + mark-active + ;;mark-ring + mode-line-process + mode-name + + normal-auto-fill-function + ;;nxhtml-menu-mode-major-mode + + open-paren-in-column-0-is-defun-start + outline-level + outline-regexp + + paragraph-ignore-fill-prefix + paragraph-separate + paragraph-start + parse-sexp-ignore-comments + parse-sexp-lookup-properties + php-mode-pear-hook + point-before-scroll + + ;; More symbols from visual inspection + ;;before-change-functions + ;;delayed-mode-hooks + ;;imenu-case-fold-search + ;;imenu-generic-expression + rngalt-completing-read-tag + rngalt-completing-read-attribute-name + rngalt-completing-read-attribute-value + rngalt-complete-first-try + rngalt-complete-last-try + rngalt-complete-tag-hooks + + syntax-begin-function + ) + "Buffer local variables that is not saved/set per chunk. +This is supposed to contain mostly buffer local variables +specific to major modes and that are not meant to be customized +by the user. +") + +(when (< emacs-major-version 23) + (defadvice c-after-change (around + mumamo-ad-c-after-change + activate + compile + ) + ;;(msgtrc "c-after-change: major-mode=%s c-nonsymbol-token-regexp=%s" major-mode c-nonsymbol-token-regexp) + (when (or (not mumamo-multi-major-mode) + (derived-mode-p 'c-mode)) + ad-do-it)) + ) + +(defun mumamo-save-per-major-local-vars (major) + "Save some per major local variables for major mode MAJOR. +This should be called before switching to a new chunks major +mode." + ;;(message "mumamo-save-per-major-local-vars %s %s" major (current-buffer)) + (let ((locals (buffer-local-variables))) + (setq locals (mapcar (lambda (local) + (unless + (or (memq (car local) mumamo-buffer-locals-dont-set) + (memq (car local) mumamo-per-buffer-local-vars) + (memq (car local) mumamo-per-main-major-local-vars) + (get (car local) 'permanent-local)) + local)) + locals)) + (setq locals (delq nil locals)) + (setq locals (sort locals (lambda (sym-a sym-b) + (string< (symbol-name (car sym-a)) + (symbol-name (car sym-b)))))) + (setq mumamo-buffer-locals-per-major + (assq-delete-all major mumamo-buffer-locals-per-major)) + (setq mumamo-buffer-locals-per-major + (cons (cons major-mode locals) + mumamo-buffer-locals-per-major)))) + +;; (benchmark 1000 '(mumamo-save-per-major-local-vars major-mode)) +;; (benchmark 1000 '(mumamo-restore-per-major-local-vars major-mode)) +(defvar mumamo-restore-per-major-local-vars-in-hook-major nil) +(defun mumamo-restore-per-major-local-vars-in-hook () + "Restore some per major mode local variables. +Call `mumamo-restore-per-major-local-vars'. +Use `mumamo-restore-per-major-local-vars-in-hook-major' as the +major mode. + +This should be called in the major mode setup hook." + (mumamo-restore-per-major-local-vars + mumamo-restore-per-major-local-vars-in-hook-major) + (setq mumamo-restore-per-major-local-vars-in-hook-major nil)) +(put 'mumamo-restore-per-major-local-vars-in-hook 'permanent-local-hook t) + +(defun mumamo-restore-per-major-local-vars (major) + "Restore some per major local variables for major mode MAJOR. +This should be called after switching to a new chunks major +mode." + (let ((locals (cdr (assq major mumamo-buffer-locals-per-major))) + var + perm) + (dolist (rec locals) + (setq var (car rec)) + (setq perm (get var 'permanent-local)) + (unless (or perm + (memq var mumamo-buffer-locals-dont-set)) + (set (make-local-variable var) (cdr rec)))))) + +;; (defun mumamo-testing-new () +;; (let ((locals (buffer-local-variables)) +;; var +;; perm +;; ) +;; (dolist (rec locals) +;; (setq var (car rec)) +;; (setq perm (get var 'permanent-local)) +;; (unless (or perm +;; (memq var mumamo-buffer-locals-dont-set)) +;; (setq var (cdr rec)))) +;; )) +;; ;;(benchmark 1000 '(mumamo-testing-new)) + +(defun mumamo-get-hook-value (hook remove) + "Return hook HOOK value with entries in REMOVE removed. +Remove also t. The value returned is a list of both local and +default values." + (let ((value (append (symbol-value hook) (default-value hook) nil))) + (dolist (rem remove) + (setq value (delq rem value))) + (delq t value))) + +;; FIX-ME: Clean up the different ways of surviving variables during +;; change of major mode. +(defvar mumamo-set-major-keymap-checked nil) +(make-variable-buffer-local 'mumamo-set-major-keymap-checked) + +(defvar mumamo-org-startup-done nil) +(make-variable-buffer-local 'mumamo-org-startup-done) +(put 'mumamo-org-startup-done 'permanent-local t) + + +(defun mumamo-font-lock-fontify-chunk () + "Like `font-lock-default-fontify-buffer' but for a chunk. +Buffer must be narrowed to inner part of chunk when this function +is called." + (let ((verbose (if (numberp font-lock-verbose) + (and (> font-lock-verbose 0) + (> (- (point-max) (point-min)) font-lock-verbose)) + font-lock-verbose)) + font-lock-extend-region-functions ;; accept narrowing + (font-lock-unfontify-region-function 'ignore)) + ;;(setq verbose t) + (with-temp-message + (when verbose + (format "Fontifying %s part %s-%s (%s)..." (buffer-name) (point-min) (point-max) font-lock-verbose)) + (condition-case err + (save-excursion + (save-match-data + (font-lock-fontify-region (point-min) (point-max) verbose) + (font-lock-after-fontify-buffer) + (setq font-lock-fontified t))) + (msgtrc "font-lock-fontify-chunk: %s" (error-message-string err)) + ;; We don't restore the old fontification, so it's best to unfontify. + (quit (mumamo-font-lock-unfontify-chunk)))))) + + +(defun mumamo-font-lock-unfontify-chunk () + "Like `font-lock-default-unfontify-buffer' for . +Buffer must be narrowed to chunk when this function is called." + ;; Make sure we unfontify etc. in the whole buffer. + (save-restriction + ;;(widen) + (font-lock-unfontify-region (point-min) (point-max)) + (font-lock-after-unfontify-buffer) + (setq font-lock-fontified nil))) + +(defun mumamo-set-major (major chunk) + "Set major mode to MAJOR for mumamo." + (mumamo-msgfntfy "mumamo-set-major %s, %s" major (current-buffer)) + (mumamo-cancel-idle-set-major-mode) + (remove-hook 'pre-command-hook 'mumamo-set-major-pre-command t) + ;;(mumamo-backtrace "mumamo-set-major") + (remove-hook 'text-mode-hook 'viper-mode) ;; Fix-me: maybe add it back... + (let ((start-time (get-internal-run-time)) + end-time + used-time + ;; Viper + viper-vi-state-mode-list + viper-emacs-state-mode-list + viper-insert-state-mode-list + ;; Org-Mode + (org-inhibit-startup mumamo-org-startup-done) + ;; Tell `mumamo-change-major-function': + (mumamo-set-major-running major) + ;; Fix-me: Take care of the new values added to these hooks! + ;; That looks difficult. We may after this have changes to + ;; both buffer local value and global value. The global + ;; changes are in this variable, but the buffer local values + ;; have been set once again. + (change-major-mode-hook (mumamo-get-hook-value + 'change-major-mode-hook + mumamo-change-major-mode-no-nos)) + (after-change-major-mode-hook (mumamo-get-hook-value + 'after-change-major-mode-hook + mumamo-after-change-major-mode-no-nos)) + ;; Some major modes deactivates the mark, we do not want that: + deactivate-mark + ;; Font lock + (font-lock-mode font-lock-mode) + ;; We have to save and reset the cursor type, at least when + ;; Viper is used + (old-cursor-type cursor-type) + ;; Protect last-command: fix-me: probably remove + (last-command last-command) + ;; Fix-me: remove this + (old-rng-schema-file (when (boundp 'rng-current-schema-file-name) rng-current-schema-file-name)) + ;; Local vars, per buffer and per major mode + per-buffer-local-vars-state + per-main-major-local-vars-state + ) + ;; We are not changing mode from font-lock's point of view, so do + ;; not tell font-lock (let binding these hooks is probably not a + ;; good choice since they may contain other stuff too): + (setq mumamo-removed-from-hook nil) + (mumamo-remove-from-hook 'change-major-mode-hook mumamo-change-major-mode-no-nos) + + ;;;;;;;;;;;;;;;; + ;; Save per buffer local variables + (dolist (sym (reverse mumamo-per-buffer-local-vars)) + (when (boundp sym) + (when (and (get sym 'permanent-local) + (not (memq sym mumamo-per-buffer-local-vars-done-by-me)) + (not (mumamo-hook-p sym))) + (delq sym mumamo-per-buffer-local-vars) + (lwarn 'mumamo-per-buffer-local-vars :warning + "Already 'permanent-local t: %s" sym)))) + (dolist (var mumamo-per-buffer-local-vars) + (if (local-variable-p var) + (push (cons var (symbol-value var)) + per-buffer-local-vars-state))) + + ;;;;;;;;;;;;;;;; + ;; Save per main major local variables + (when (mumamo-fun-eq major-mode (mumamo-main-major-mode)) + (dolist (var mumamo-per-main-major-local-vars) + (if (local-variable-p var) + (push (cons var (symbol-value var)) + per-main-major-local-vars-state)))) + + ;; For all hooks that probably can have buffer local values, go + ;; through the buffer local values and look for a permanent-local + ;; property on each function. Remove those functions that does not + ;; have it. Then make the buffer local value of the hook survive + ;; by putting a permanent-local property on it. + (unless (> emacs-major-version 22) + (dolist (hk mumamo-survive-hooks) + (put hk 'permanent-local t) + (when (local-variable-p hk) + (let ((hkv (copy-sequence (symbol-value hk)))) + (dolist (v hkv) + (unless (or (eq v t) + (get v 'permanent-local-hook)) + (remove-hook hk v t) + )))))) + + (run-hooks 'mumamo-change-major-mode-hook) + + (setq mumamo-major-mode major) + + ;;;;;;;;;;;;;;;; + ;; Save per major mode local variables before switching major + (mumamo-save-per-major-local-vars major-mode) + ;; Prepare to restore per major mode local variables after + ;; switching back to major-mode, but do it in the greatest + ;; ancestor's mode hook (see `run-mode-hooks'): + (let (ancestor-hook-sym + parent-hook-sym + (parent major)) + ;; We want the greatest ancestor's mode hook: + (setq parent-hook-sym (intern-soft (concat (symbol-name parent) "-hook"))) + (when parent-hook-sym (setq ancestor-hook-sym parent-hook-sym)) + (while (get parent 'derived-mode-parent) + (setq parent (get parent 'derived-mode-parent)) + (setq parent-hook-sym (intern-soft (concat (symbol-name parent) "-hook"))) + (when parent-hook-sym (setq ancestor-hook-sym parent-hook-sym))) + (when ancestor-hook-sym + ;; Put first in local hook to run it first: + (setq mumamo-restore-per-major-local-vars-in-hook-major major) + (add-hook ancestor-hook-sym + 'mumamo-restore-per-major-local-vars-in-hook + nil t)) + + ;;(msgtrc "set-major A: buffer-invisibility-spec=%S" buffer-invisibility-spec) + ;;(msgtrc "set-major A: word-wrap=%S, cb=%s" word-wrap (current-buffer)) + ;;(mumamo-backtrace "set-major") + (let ((here (point))) + (unwind-protect + (save-restriction + (let* ((minmax (mumamo-chunk-syntax-min-max chunk t)) + (min (car minmax)) + (max (cdr minmax)) + (here (point)) + ;; Fix-me: For some reason let binding did not help. Is this a bug or? + ;; + ;;(font-lock-fontify-buffer-function 'mumamo-font-lock-fontify-chunk) + (old-bf (buffer-local-value 'font-lock-fontify-buffer-function (current-buffer))) + (inhibit-redisplay t) ;; Fix-me: said to be for internal purposes only + ) + (narrow-to-region min max) + (set (make-local-variable 'font-lock-fontify-buffer-function) 'mumamo-font-lock-fontify-chunk) + ;;(message "funcall major=%s, %s" major font-lock-fontify-buffer-function) + ;;(message "before funcall: function=%s" font-lock-fontify-buffer-function) + (put 'font-lock-fontify-buffer-function 'permanent-local t) + (funcall major) ;; <----------------------------------------------- + (put 'font-lock-fontify-buffer-function 'permanent-local nil) + (when old-bf + (set (make-local-variable 'font-lock-fontify-buffer-function) old-bf)) + )) + (goto-char here))) + ;;(msgtrc "set-major B: buffer-invisibility-spec=%S" buffer-invisibility-spec) + ;;(msgtrc "set-major B: word-wrap=%S, cb=%s" word-wrap (current-buffer)) + + (setq font-lock-mode-major-mode major) ;; Tell font-lock it is ok + (set (make-local-variable 'font-lock-function) 'mumamo-font-lock-function) + (if (not ancestor-hook-sym) + (mumamo-restore-per-major-local-vars major) + (remove-hook ancestor-hook-sym + 'mumamo-restore-per-major-local-vars-in-hook + t))) + ;;(msgtrc "set-major c: buffer-invisibility-spec=%S" buffer-invisibility-spec) + + (when (mumamo-fun-eq major 'org-mode) (setq mumamo-org-startup-done t)) + + (setq mumamo-major-mode-indent-line-function (cons major-mode indent-line-function)) + (make-local-variable 'indent-line-function) + + (setq mode-name (concat (format-mode-line mode-name) + (save-match-data + (replace-regexp-in-string + "-mumamo-mode$" "" + (format "/%s" mumamo-multi-major-mode))))) + + (dolist (hk mumamo-survive-hooks) (put hk 'permanent-local nil)) + + ;; (when (and (featurep 'flymake) + ;; flymake-mode) + ;; (add-hook 'after-change-functions 'flymake-after-change-function nil t) + ;; (add-hook 'after-save-hook 'flymake-after-save-hook nil t) + ;; (add-hook 'kill-buffer-hook 'flymake-kill-buffer-hook nil t)) + + ;;;;;;;;;;;;;;;; + ;; Restore per buffer local variables + + ;; (dolist (sym mumamo-per-buffer-local-vars) + ;; (when (boundp sym) + ;; (put sym 'permanent-local nil))) + ;;(msgtrc "per-buffer-local-vars-state=%S" per-buffer-local-vars-state) + (dolist (saved per-buffer-local-vars-state) + ;;(msgtrc "restore p buffer: %s, local=%s" (car saved) (local-variable-p (car saved))) + (unless (local-variable-p (car saved)) + (set (make-local-variable (car saved)) (cdr saved)))) + + ;;;;;;;;;;;;;;;; + ;; Restore per main major local variables + (unless (mumamo-fun-eq major-mode (mumamo-main-major-mode)) + (dolist (saved per-main-major-local-vars-state) + (set (make-local-variable (car saved)) (cdr saved)))) + + (mumamo-addback-to-hooks) + + (setq cursor-type old-cursor-type) + (run-hooks 'mumamo-after-change-major-mode-hook) + + (when (derived-mode-p 'nxml-mode) + (when (and old-rng-schema-file + (not (string= old-rng-schema-file rng-current-schema-file-name))) + (let ((rng-schema-change-hook nil)) ;(list 'rng-alidate-clear))) + (condition-case err + (progn + (rng-set-schema-file-1 old-rng-schema-file) + (rng-what-schema)) + (nxml-file-parse-error + (nxml-display-file-parse-error err))) + (when rng-validate-mode + ;; Fix-me: Change rng-validate variables so that this is + ;; not necessary any more. + (rng-validate-mode 0) + (rng-validate-mode 1)) + ))) + ;; The nxml-parser should not die: + (when (mumamo-derived-from-mode (mumamo-main-major-mode) 'nxml-mode) + (add-hook 'after-change-functions 'rng-after-change-function nil t) + (add-hook 'after-change-functions 'nxml-after-change nil t) + ;; Added these for Emacs 22: + (unless nxml-prolog-end (setq nxml-prolog-end 1)) + (unless nxml-scan-end (setq nxml-scan-end (copy-marker 1)))) + +;;; (when (and global-font-lock-mode +;;; font-lock-global-modes +;;; font-lock-mode) +;;; (when global-font-lock-mode +;;; (add-hook 'change-major-mode-hook 'global-font-lock-mode-cmhh)) +;;; (add-hook 'change-major-mode-hook 'font-lock-change-mode nil t) + + (mumamo-set-fontification-functions) + + ;; If user has used M-x flyspell-mode then we need to correct it: + ;; Fix-me: This is inflexible. Need flyspell to cooperate. + (when (featurep 'flyspell) + (setq flyspell-generic-check-word-predicate 'mumamo-flyspell-verify)) + + (if mumamo-done-first-set-major + (setq mumamo-just-changed-major t) + (mumamo-msgfntfy "mumamo-set-major: ----- removing 'fontified") + ;; Set up to fontify buffer + (mumamo-save-buffer-state nil + (remove-list-of-text-properties (point-min) (point-max) '(fontified))) + (setq mumamo-done-first-set-major t)) + + ;; Timing, on a 3ghz cpu: + ;; + ;; used-time=(0 0 0), major-mode=css-mode + ;; used-time=(0 0 0), major-mode=ecmascript-mode + ;; used-time=(0 0 0), major-mode=html-mode + ;; used-time=(0 0 203000), major-mode=nxhtml-mode + ;; + ;; After some changes 2007-04-25: + ;; + ;; used-time=(0 0 15000), major-mode=nxhtml-mode + ;; + ;; which is 15 ms. That seems acceptable though I am not sure + ;; everything is correct when switching to nxhtml-mode yet. I + ;; will have to wait for bug reports ;-) + ;; + ;; The delay is clearly noticeable and disturbing IMO unless you + ;; change major mode in an idle timer. + ;; + ;;(setq end-time (get-internal-run-time)) + ;;(setq used-time (time-subtract end-time start-time)) + ) + (setq mumamo-set-major-keymap-checked nil) + ;; Fix-me: Seems like setting/checking the keymap in a timer is + ;; problematc. This is an Emacs bug. + ;;(run-with-idle-timer 1 nil 'mumamo-set-major-check-keymap) + ;;(force-mode-line-update) (message "force-mode-line-update called") + ) + +(defun mumamo-set-major-check-keymap () + "Helper to work around an Emacs bug when setting local map in a timer." + (or mumamo-set-major-keymap-checked + (setq mumamo-set-major-keymap-checked + (let ((map-sym (intern-soft (concat (symbol-name major-mode) "-map")))) + (if (not map-sym) + t ;; Don't know what to do + (equal (current-local-map) + (symbol-value map-sym))))))) + +(defvar mumamo-original-fill-paragraph-function nil) +(make-variable-buffer-local 'mumamo-original-fill-paragraph-function) + +(defun mumamo-setup-local-fontification-vars () + "Set up buffer local variables for mumamo style fontification." + (make-local-variable 'font-lock-fontify-region-function) + (setq font-lock-fontify-region-function 'mumamo-fontify-region) + + ;; Like font-lock-turn-on-thing-lock: + (make-local-variable 'font-lock-fontify-buffer-function) + (setq font-lock-fontify-buffer-function 'jit-lock-refontify) + (setq font-lock-fontify-buffer-function 'mumamo-fontify-buffer) + ;; Don't fontify eagerly (and don't abort if the buffer is large). + (set (make-local-variable 'font-lock-fontified) t) + + (make-local-variable 'font-lock-unfontify-buffer-function) + (setq font-lock-unfontify-buffer-function 'mumamo-unfontify-buffer) + + (set (make-local-variable 'indent-line-function) 'mumamo-indent-line-function) + + ;;(setq mumamo-original-fill-paragraph-function fill-paragraph-function) + ;;(set (make-local-variable 'fill-paragraph-function) 'mumamo-fill-paragraph-function) + ;;(set (make-local-variable 'fill-forward-paragraph-function 'forward-paragraph) + + (make-local-variable 'indent-region-function) + (setq indent-region-function 'mumamo-indent-region-function) + + ;;(set (make-local-variable 'syntax-begin-function) 'mumamo-beginning-of-syntax) + + ;;(put 'font-lock-function 'permanent-local t) + + ;; FIX-ME: Not sure about this one, but it looks like it must be + ;; set: + (make-local-variable 'jit-lock-contextually) + (setq jit-lock-contextually t) + ) + +(defun mumamo-font-lock-function (mode) + ;;(mumamo-backtrace "font-lock-function") + (font-lock-default-function mode)) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Turning on/off multi major modes + +(defun mumamo-set-fontification-functions () + "Let mumamo take over fontification. +This is run after changing major mode so that jit-lock will get +the major mode specific values. \(There are currently no such +values.)" + ;; Give the jit machinery a starting point: + (mumamo-jit-lock-register 'font-lock-fontify-region t) + ;; Set the functions that font-lock should use: + (mumamo-setup-local-fontification-vars) + ;; Need some hook modifications to keep things together too: + (add-hook 'change-major-mode-hook 'mumamo-change-major-function nil t) + (add-hook 'post-command-hook 'mumamo-post-command nil t) + (remove-hook 'change-major-mode-hook 'nxml-change-mode t) + (remove-hook 'change-major-mode-hook 'nxhtml-change-mode t) + ) + +(defun mumamo-initialize-state () + "Initialize some mumamo state variables." + (setq mumamo-done-first-set-major nil) + (setq mumamo-just-changed-major nil)) + +(defun mumamo-turn-on-actions (old-major-mode) + "Do what is necessary to turn on mumamo. +Turn on minor mode function `font-lock-mode'. +Set up for mumamo style fontification. +Create a mumamo chunk at point. +Run `mumamo-turn-on-hook'. + +OLD-MAJOR-MODE is used for the main major mode if the main major +mode in the chunk family is nil." + ;;(unless font-lock-mode (font-lock-mode 1)) + (mumamo-msgfntfy "mumamo-turn-on-actions") + (unless mumamo-current-chunk-family (error "Internal error: Chunk family is not set")) + (if (not mumamo-current-chunk-family) + (progn + (lwarn '(mumamo) :warning + "Could not turn on mumamo because chunk family was not set\n\tin buffer %s." + (current-buffer)) + (with-current-buffer "*Warnings*" + (insert "\tFor more information see `") + (mumamo-insert-describe-button 'define-mumamo-multi-major-mode 'describe-function) + (insert "'.\n"))) + ;; Load major mode: + (setq mumamo-org-startup-done nil) + (let ((main-major-mode (mumamo-major-mode-from-modespec (mumamo-main-major-mode)))) + (unless main-major-mode + (setcar (cdr mumamo-current-chunk-family) old-major-mode) + (setq main-major-mode (mumamo-main-major-mode))) + ;;(with-temp-buffer (funcall main-major-mode)) + (setq mumamo-major-mode main-major-mode) + (when (boundp 'nxml-syntax-highlight-flag) + (when (mumamo-derived-from-mode main-major-mode 'nxml-mode) + (set (make-local-variable 'nxml-syntax-highlight-flag) nil))) + ;; Init fontification + (mumamo-initialize-state) + (mumamo-set-fontification-functions) + (mumamo-save-buffer-state nil + (remove-list-of-text-properties (point-min) (point-max) + (list 'fontified))) + ;; For validation header etc: + (when (mumamo-derived-from-mode main-major-mode 'nxhtml-mode) + (require 'rngalt nil t) + (when (featurep 'rngalt) + (setq rngalt-major-mode (mumamo-main-major-mode)) + (rngalt-update-validation-header-overlay)) + (when (featurep 'rng-valid) + (setq rng-get-major-mode-chunk-function 'mumamo-find-chunks) + (setq rng-valid-nxml-major-mode-chunk-function 'mumamo-valid-nxml-chunk) + (setq rng-end-major-mode-chunk-function 'overlay-end)))) + ;;(mumamo-set-major-post-command) + ;;(add-hook 'change-major-mode-hook 'mumamo-change-major-function nil t) + (when (boundp 'flyspell-generic-check-word-predicate) + (setq flyspell-generic-check-word-predicate 'mumamo-flyspell-verify)) + (run-hooks 'mumamo-turn-on-hook) + ;;(mumamo-get-chunk-save-buffer-state (point)) + (let ((buffer-windows (get-buffer-window-list (current-buffer)))) + (if (not buffer-windows) + (let* ((ovl (mumamo-find-chunks (point) "mumamo-turn-on-actions")) + (major (when ovl (mumamo-chunk-major-mode ovl)))) + (when major + (mumamo-set-major major ovl))) + (dolist (win (get-buffer-window-list (current-buffer) nil t)) + (let ((wp (or (window-end win) + (window-point win) + (window-start win)))) + (mumamo-get-chunk-save-buffer-state wp) + (when (eq win (selected-window)) + (let* ((ovl (mumamo-find-chunks wp "mumamo-turn-on-actions")) + (major (when ovl (mumamo-chunk-major-mode ovl)))) + (when major + (mumamo-set-major major ovl)))))))) + ;;(msgtrc "mumamo-turn-on-action exit: font-lock-keywords-only =%s in buffer %s, def=%s" font-lock-keywords-only (current-buffer) (default-value 'font-lock-keywords-only)) + ;; This did not help for Emacs bug 3467: + ;;(set-default 'font-lock-keywords-only nil) + ;;(setq font-lock-keywords-only nil) + ) + (set (make-local-variable 'font-lock-function) 'mumamo-font-lock-function) + (mumamo-emacs-start-bug3467-timer-if-needed) + ) + +;; (defun mumamo-on-font-lock-off () +;; "The reverse of `mumamo-turn-on-actions'." +;; (let ((mumamo-main-major-mode (mumamo-main-major-mode))) +;; (mumamo-turn-off-actions) +;; ;; Turning off `font-lock-mode' also turns off `mumamo-mode'. It is +;; ;; quite tricky to not turn on `font-lock-mode' again in case we got +;; ;; here because it was turned off. We must first remove the cmhh +;; ;; function and then also run the internal font lock turn off. +;; (let* ((flm font-lock-mode) +;; (flgm global-font-lock-mode) +;; (remove-cmhh (and (not flm) flgm))) +;; ;; If remove-cmhh is non-nil then we got here because +;; ;; `font-lock-mode' was beeing turned off in the buffer, but +;; ;; `global-font-lock-mode' is still on. +;; (when remove-cmhh +;; (remove-hook 'change-major-mode-hook 'global-font-lock-mode-cmhh)) + +;; (if mumamo-main-major-mode +;; (funcall mumamo-main-major-mode) +;; (fundamental-mode)) + +;; (unless flm +;; (setq font-lock-mode nil) +;; (font-lock-mode-internal nil)) +;; (when remove-cmhh +;; (add-hook 'change-major-mode-hook 'global-font-lock-mode-cmhh))))) + +(defun mumamo-turn-off-actions () + "The reverse of `mumamo-turn-on-actions'." + (mumamo-msgfntfy "mumamo-turn-off-actions") + (when (fboundp 'nxhtml-validation-header-mode) + (nxhtml-validation-header-mode -1)) + (when (mumamo-derived-from-mode + (nth 1 mumamo-current-chunk-family) 'nxml-mode) + (when (fboundp 'nxml-change-mode) + (nxml-change-mode))) + (when (and (boundp 'rng-validate-mode) + rng-validate-mode) + (rng-validate-mode 0)) + (when (featurep 'rng-valid) + (setq rng-get-major-mode-chunk-function nil) + (setq rng-valid-nxml-major-mode-chunk-function nil) + (setq rng-end-major-mode-chunk-function nil) + ) + ;; Remove nxml for Emacs 22 + (remove-hook 'after-change-functions 'rng-after-change-function t) + (remove-hook 'after-change-functions 'nxml-after-change t) + (when (boundp 'rngalt-major-mode) + (setq rngalt-major-mode nil)) + (remove-hook 'change-major-mode-hook 'mumamo-change-major-function t) + ;;(mumamo-unfontify-chunks) + ;;(remove-hook 'after-change-functions 'mumamo-jit-lock-after-change t) + (remove-hook 'after-change-functions 'mumamo-after-change t) + (remove-hook 'post-command-hook 'mumamo-post-command t) + ;;(remove-hook 'c-special-indent-hook 'mumamo-c-special-indent t) + (mumamo-margin-info-mode -1) + (when (fboundp 'mumamo-clear-all-regions) (mumamo-clear-all-regions)) + (save-restriction + (widen) + (mumamo-save-buffer-state nil + (set-text-properties (point-min) (point-max) nil))) + (setq mumamo-current-chunk-family nil) + (setq mumamo-major-mode nil) + (setq mumamo-multi-major-mode nil) ;; for minor-mode-map-alist + (setq mumamo-multi-major-mode nil) + (mumamo-remove-all-chunk-overlays) + (when (fboundp 'rng-cancel-timers) (rng-cancel-timers)) + ) + +(defvar mumamo-turn-on-hook nil + "Normal hook run after turning on `mumamo-mode'.") +(put 'mumamo-turn-on-hook 'permanent-local t) + +(defvar mumamo-change-major-mode-hook nil + "Normal hook run before internal change of major mode.") +(put 'mumamo-change-major-mode-hook 'permanent-local t) + +(defvar mumamo-after-change-major-mode-hook nil + "Normal hook run after internal change of major mode.") +(put 'mumamo-after-change-major-mode-hook 'permanent-local t) + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Defining multi major modes + +(defvar mumamo-defined-multi-major-modes nil + "List of functions defined for turning on mumamo. +Those functions should be called instead of calling a major mode +function when you want to use multiple major modes in a buffer. +They may be added to for example `auto-mode-alist' to +automatically have the major mode support turned on when opening +a file. + +Each of these functions defines how to mix certain major modes in +a buffer. + +All functions defined by `define-mumamo-multi-major-mode' are +added to this list. See this function for a general description +of how the functions work. + +If you want to quickly define a new mix of major modes you can +use `mumamo-quick-static-chunk'.") + +;;;###autoload +(defun mumamo-list-defined-multi-major-modes (show-doc show-chunks match) + "List currently defined multi major modes. +If SHOW-DOC is non-nil show the doc strings added when defining +them. \(This is not the full doc string. To show the full doc +string you can click on the multi major mode in the list.) + +If SHOW-CHUNKS is non-nil show the names of the chunk dividing +functions each multi major mode uses. + +If MATCH then show only multi major modes whos names matches." + (interactive (list (y-or-n-p "Include short doc string? ") + (y-or-n-p "Include chunk function names? ") + (read-string "List only multi major mode matching regexp (emtpy for all): "))) + (with-output-to-temp-buffer (help-buffer) + (help-setup-xref (list #'mumamo-list-defined-multi-major-modes) (interactive-p)) + (with-current-buffer (help-buffer) + (insert "The currently defined multi major modes in your Emacs are:\n\n") + (let ((mmms (reverse mumamo-defined-multi-major-modes)) + (here (point))) + (setq mmms (sort mmms (lambda (a b) + (string< (symbol-name (cdr a)) + (symbol-name (cdr b)))))) + (when (string= match "") (setq match nil)) + (while mmms + (let* ((mmm (car mmms)) + (sym (cdr mmm)) + (desc (car mmm)) + (auto (get sym 'autoload)) + (auto-desc (when auto (nth 1 auto))) + (family (get sym 'mumamo-chunk-family)) + (chunks (nth 2 family))) + (when (or (not match) + (string-match-p match (symbol-name sym))) + (insert " `" (symbol-name sym) "'" + " (" desc ")\n" + (if (and show-doc auto-desc) + (concat " " auto-desc "\n") + "") + (if show-chunks + (format " Chunks:%s\n" + (let ((str "") + (nn 0)) + (mapc (lambda (c) + (if (< nn 2) + (setq str (concat str " ")) + (setq nn 0) + (setq str (concat str "\n "))) + (setq nn (1+ nn)) + (setq str (concat str (format "%-30s" (format "`%s'" c)))) + ) + chunks) + str)) + "") + (if (or show-doc show-chunks) "\n\n" "") + )) + (setq mmms (cdr mmms)))) + )))) + +(defun mumamo-describe-chunks (chunks) + "Return text describing CHUNKS." + (let* ((desc + (concat "* Main major mode: `" (symbol-name (nth 1 chunks)) "'\n" + "\n* Functions for dividing into submodes:\n"))) + (dolist (divider (nth 2 chunks)) + (setq desc + (concat + desc + "\n`" (symbol-name divider) + "'\n " + (let ((doc (if (functionp divider) + (documentation divider t) + "(Function not compiled when building doc)"))) + (if (not doc) + "(Not documented)" + (substring doc 0 (string-match "\n" doc))))))) + (setq desc + (concat + desc + "\n\n(Note that the functions for dividing into chunks returns\n" + "a major mode specifier which may be translated into a major mode\n" + "by `mumamo-main-major-mode'.)\n")) + desc)) + +(defun mumamo-add-multi-keymap (toggle keymap) + "Add TOGGLE and KEYMAP to `minor-mode-map-alist'. +This is used to add a keymap to multi major modes since the local +keymap is occupied by the major modes. + +It is also used to add the `mumamo-map' keymap to every buffer +with a multi major mode." + ;; Copied from add-minor-mode + ;; Add the map to the minor-mode-map-alist. + (when keymap + (let ((existing (assq toggle minor-mode-map-alist)) + (after t)) + (if existing + (setcdr existing keymap) + (let ((tail minor-mode-map-alist) found) + (while (and tail (not found)) + (if (eq after (caar tail)) + (setq found tail) + (setq tail (cdr tail)))) + (if found + (let ((rest (cdr found))) + (setcdr found nil) + (nconc found (list (cons toggle keymap)) rest)) + (setq minor-mode-map-alist (cons (cons toggle keymap) + minor-mode-map-alist)))))))) + +(defvar mumamo-map + (let ((map (make-sparse-keymap))) + (define-key map [(control meta prior)] 'mumamo-backward-chunk) + (define-key map [(control meta next)] 'mumamo-forward-chunk) + ;; Use mumamo-indent-line-function: + ;;(define-key map [tab] 'indent-for-tab-command) + (define-key map [(meta ?q)] 'fill-paragraph) + map) + "Keymap that is active in all mumamo buffers. +It has the some priority as minor mode maps.") +;;(make-variable-buffer-local 'mumamo-map) +(put 'mumamo-map 'permanent-local t) + +(mumamo-add-multi-keymap 'mumamo-multi-major-mode mumamo-map) + +;;;###autoload +(defun mumamo-multi-major-modep (value) + "Return t if VALUE is a multi major mode function." + (and (fboundp value) + (rassq value mumamo-defined-multi-major-modes))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Indenting, filling, moving etc + +;; FIX-ME: Indentation in perl here doc indents the ending mark which +;; corrupts the perl here doc. + +(defun mumamo-indent-line-function () + "Function to indent the current line. +This is the buffer local value of `indent-line-function' when +mumamo is used." + (let ((here (point-marker)) + fontification-functions + rng-nxml-auto-validate-flag + (before-text (<= (current-column) (current-indentation)))) + (mumamo-indent-line-function-1 nil nil nil) + ;; If the marker was in the indentation part strange things happen + ;; if we try to go back to the marker, at least in php-mode parts. + (if before-text + (back-to-indentation) + (goto-char here)))) + +(defun mumamo-indent-current-line-chunks (last-chunk-prev-line) + "Return a list of chunks to consider when indenting current line. +This list consists of four chunks at these positions: +- Beginning of line - 1 +- Beginning of line +- End of line +- End of line + 1" + ;; Fix-me: must take markers into account too when a submode + ;; includes the markers. + (setq last-chunk-prev-line nil) + ;;(msgtrc "indent-current-line-chunks: last-chunk-prev-line=%S" last-chunk-prev-line) + (save-restriction + (widen) + (let* ((lb-pos (line-beginning-position)) + (le-pos (line-end-position)) + (pos0 (if (> lb-pos (point-min)) + (1- lb-pos) + (point-min))) + (pos1 lb-pos) + (pos2 le-pos) + (pos3 (if (< le-pos (point-max)) + (+ 1 le-pos) + (point-max))) + ;; Create all chunks on this line first, then grab them + (ovl3 (mumamo-find-chunks pos3 "mumamo-indent-current-line-chunks")) + (ovl2 (if (>= pos2 (overlay-start ovl3)) + ovl3 + (mumamo-get-existing-new-chunk-at pos2))) + (ovl1 (if (>= pos1 (overlay-start ovl2)) + ovl2 + (mumamo-get-existing-new-chunk-at pos1))) + (ovl0 (if (> pos0 (overlay-start ovl1)) + ovl1 + (mumamo-get-existing-new-chunk-at pos0 t)))) + (list ovl0 ovl1 ovl2 ovl3)))) + +;; Fix-me: need to back up past comments in for example + Going out this line; First char inner or outer; line end outer; + + 3) + Going out this line; first char inner; line end outer; + + From this we deduce the following way to compute if we are + going in or out: + + - Odd above (going in): Compare prev line end's mumamo-depth + with current line end's dito. Set flag for first line in + chunk. + + - Even above (going out): Same test as for going in, but going + out happens on current line. +" + ;;(msgtrc "indent-line-function-1 blp=%s" (line-beginning-position)) + (setq prev-line-chunks nil) + ;;(setq last-parent-major-indent nil) + ;;(setq entering-submode-arg nil) + (unless prev-line-chunks + (save-excursion + (goto-char (line-beginning-position 1)) + (unless (= (point) 1) + (skip-chars-backward "\n\t ") + (goto-char (line-beginning-position 1)) + (setq prev-line-chunks (mumamo-indent-current-line-chunks nil)) + ;;(msgtrc "%d:prev-line-chunks=%S" (save-restriction (widen) (line-number-at-pos)) prev-line-chunks ) + ))) + (let* ((prev-line-chunk0 (nth 0 prev-line-chunks)) + (prev-line-chunk2 (nth 2 prev-line-chunks)) + (prev-line-chunk3 (nth 3 prev-line-chunks)) + (prev-line-major0 (mumamo-chunk-major-mode (nth 0 prev-line-chunks))) + (prev-line-major1 (mumamo-chunk-major-mode (nth 1 prev-line-chunks))) + (prev-line-major2 (mumamo-chunk-major-mode (nth 2 prev-line-chunks))) + (prev-line-major3 (mumamo-chunk-major-mode (nth 3 prev-line-chunks))) + (prev-depth2 (if prev-line-chunk2 + (overlay-get prev-line-chunk2 'mumamo-depth) + 0)) + (prev-depth3 (if prev-line-chunk3 + (overlay-get prev-line-chunk3 'mumamo-depth) + 0)) + + (this-line-chunks (mumamo-indent-current-line-chunks (nth 3 prev-line-chunks))) + ;;(dummy (msgtrc "%d:this-line-chunks=%S" (save-restriction (widen) (line-number-at-pos)) this-line-chunks)) + (this-line-chunk0 (nth 0 this-line-chunks)) + (this-line-chunk2 (nth 2 this-line-chunks)) + (this-line-chunk3 (nth 3 this-line-chunks)) + (this-line-major0 (mumamo-chunk-major-mode (nth 0 this-line-chunks))) + (this-line-major1 (mumamo-chunk-major-mode (nth 1 this-line-chunks))) + (this-line-major2 (mumamo-chunk-major-mode (nth 2 this-line-chunks))) + (this-line-major3 (mumamo-chunk-major-mode (nth 3 this-line-chunks))) + (this-depth2 (overlay-get this-line-chunk2 'mumamo-depth)) + (this-depth3 (overlay-get this-line-chunk3 'mumamo-depth)) + + ;;(dummy (msgtrc "a\t this=%S" this-line-chunks)) + this-line-indent-major + major-indent-line-function + (main-major (mumamo-main-major-mode)) + (old-indent (current-indentation)) + (next-entering-submode (if (< prev-depth3 this-depth3) 'yes 'no)) + (entering-submode + ;; Fix-me + (progn + (unless nil ;entering-submode-arg + (let* ((prev-prev-line-chunks + (save-excursion + (goto-char (line-beginning-position 0)) + (unless (bobp) + (skip-chars-backward "\n\t ") + (goto-char (line-beginning-position 1)) + (let ((chunks (mumamo-indent-current-line-chunks nil))) + ;;(msgtrc "%d:prev-prev-line-chunks=%S" (save-restriction (widen) (line-number-at-pos)) chunks) + chunks)))) + (prev-prev-line-chunk2 (nth 2 prev-prev-line-chunks)) + (prev-prev-line-chunk3 (nth 3 prev-prev-line-chunks)) + (prev-prev-depth2 (when prev-prev-line-chunk2 + (overlay-get prev-prev-line-chunk2 'mumamo-depth))) + (prev-prev-depth3 (when prev-prev-line-chunk3 + (overlay-get prev-prev-line-chunk3 'mumamo-depth)))) + ;;(msgtrc "depths 2=%s/%s/%s 3=%s/%s/%s" prev-prev-depth2 prev-depth2 this-depth2 prev-prev-depth3 prev-depth3 this-depth3) + (setq entering-submode-arg + (if prev-prev-depth2 + (if (and (eq prev-prev-line-chunk2 + (overlay-get prev-line-chunk2 'mumamo-prev-chunk)) + (< prev-prev-depth2 prev-depth2)) + 'yes + 'no) + (if (> this-depth2 0) 'yes 'no) + )) + )) + (eq 'yes entering-submode-arg) + )) ;; fix-me + ;; Fix-me + (leaving-submode (> prev-depth2 this-depth2)) + want-indent ;; The indentation we desire + got-indent + (here-on-line (point-marker)) + this-pending-undo-list + (while-n1 0) + (while-n2 0) + (while-n3 0) + ;; Is there a possible indentor chunk on this line?: + (this-line-indentor-chunk (when (> (overlay-start this-line-chunk2) + (point-at-bol)) + (overlay-get this-line-chunk2 'mumamo-prev-chunk))) + ;;(dummy (msgtrc "this-line-indentor-chunk=%S" this-line-indentor-chunk)) + ;; Check if this really is an indentor chunk: + ;; Fix-me: 'mumamo-indentor is not put on the chunk yet since + ;; it is done in mumamo-template-indent-get-chunk-shift ... - + ;; and now it is calle too often ... + (this-line-indentor-prev (when this-line-indentor-chunk + (overlay-get this-line-indentor-chunk 'mumamo-prev-chunk))) + (this-line-is-indentor (and this-line-indentor-prev + (eq (overlay-get this-line-indentor-prev 'mumamo-next-indent) + 'mumamo-template-indentor) + (progn + (goto-char (overlay-start this-line-indentor-chunk)) + (back-to-indentation) + (= (point) (overlay-start this-line-indentor-chunk))))) + ;; Fix-me: rewrite and reorder. We do not need both shift-in and shift-out + (this-template-shift (when this-line-is-indentor + (mumamo-template-indent-get-chunk-shift this-line-indentor-chunk))) + ;;(dummy (msgtrc "this-line-indentor=%s, %S" this-template-shift this-line-is-indentor)) + ;; Fix-me: skip over blank lines backward here: + (prev-template-indentor (when prev-line-chunk0 + (unless (eq this-line-chunk0 prev-line-chunk0) + (let* ((prev (overlay-get this-line-chunk0 'mumamo-prev-chunk)) + (prev-prev (overlay-get prev 'mumamo-prev-chunk))) + (when (and (eq prev-prev prev-line-chunk0) + (eq (overlay-get prev-prev 'mumamo-next-indent) + 'mumamo-template-indentor)) + prev))))) + (prev-template-shift-rec (when prev-template-indentor + (mumamo-template-indent-get-chunk-shift prev-template-indentor) + )) + (template-shift (if (and (car this-template-shift) (/= 0 (car this-template-shift))) + (car this-template-shift) + (when prev-template-shift-rec + (cdr prev-template-shift-rec)))) + (template-indent-abs (when (and template-shift + (/= 0 template-shift)) + (+ template-shift + (let ((here (point))) + (if prev-template-indentor + (goto-char (overlay-start prev-template-indentor)) + (goto-char (overlay-start this-line-indentor-chunk)) + (skip-chars-backward " \t\r\n\f")) + (prog1 + (current-indentation) + (goto-char here)))))) + ) + (when (and leaving-submode entering-submode) + (message "Do not know how to indent here (both leaving and entering sub chunks)") + ) + ;; Fix-me: indentation + ;;(error "Leaving=%s, entering=%s this0,1,2,3=%s,%s,%s,%s" leaving-submode entering-submode this-line-major0 this-line-major1 this-line-major2 this-line-major3) + (when (or leaving-submode entering-submode) + (unless last-parent-major-indent + (save-excursion + ;;(while (and (> 500 (setq while-n1 (1+ while-n1))) + (while (and (mumamo-while 500 'while-n1 "last-parent-major-indent") + (not last-parent-major-indent)) + (if (bobp) + (setq last-parent-major-indent 0) + (goto-char (line-beginning-position 0)) + (when (mumamo-fun-eq main-major + (mumamo-chunk-major-mode + (car + (mumamo-indent-current-line-chunks nil))) + ) + (skip-chars-forward " \t") + (if (eolp) + (setq last-parent-major-indent 0) + (setq last-parent-major-indent (current-column))))))))) + (mumamo-msgindent " leaving-submode=%s, entering-submode=%s" leaving-submode entering-submode) + ;;(msgtrc " leaving-submode=%s, entering-submode=%s, template-indentor=%s" leaving-submode entering-submode template-indentor) + + ;; Fix-me: use this. + ;; - clean up after chunk deletion + ;; - next line after a template-indentor, what happens? + ;;(setq template-indentor nil) ;; fix-me + (cond + ( template-indent-abs + (setq want-indent (max 0 template-indent-abs))) + ( leaving-submode + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;;;;; First line after submode + (mumamo-msgindent " leaving last-parent-major-indent=%s" last-parent-major-indent) + (if (eq (overlay-get (overlay-get this-line-chunk0 'mumamo-prev-chunk) + 'mumamo-next-indent) + 'heredoc) + (setq want-indent 0) + (setq want-indent last-parent-major-indent))) + + ( entering-submode + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;;;;; First line in submode + ;;(setq this-line-indent-major this-line-major0) + (setq this-line-indent-major (mumamo-indent-get-major-to-use this-line-major0 this-depth3)) + ;;(when (and prev-line-major0 (not (mumamo-fun-eq this-line-major0 prev-line-major0))) (setq this-line-indent-major prev-line-major0)) + (mumamo-msgindent " this-line-indent-major=%s, major-mode=%s this0=%s" this-line-indent-major major-mode this-line-major0) + (mumamo-msgindent " mumamo-submode-indent-offset=%s" mumamo-submode-indent-offset) + (unless (mumamo-fun-eq this-line-indent-major major-mode) + (mumamo-set-major this-line-indent-major this-line-chunk0)) + (setq want-indent (+ last-parent-major-indent + (if (= 0 last-parent-major-indent) + (if mumamo-submode-indent-offset-0 + mumamo-submode-indent-offset-0 + -1000) + (if mumamo-submode-indent-offset + mumamo-submode-indent-offset + -1000)))) + (unless (< 0 want-indent) (setq want-indent nil)) + (when (and want-indent (mumamo-indent-use-widen major-mode)) + ;; In this case only use want-indent if it is bigger than the + ;; indentation calling indent-line-function would give. + (condition-case nil + (atomic-change-group + (mumamo-call-indent-line (nth 0 this-line-chunks)) + (when (> want-indent (current-indentation)) + (signal 'mumamo-error-ind-0 nil)) + (setq want-indent nil)) + (mumamo-error-ind-0))) + (unless want-indent + (mumamo-call-indent-line (nth 0 this-line-chunks))) + (mumamo-msgindent " enter sub.want-indent=%s, curr=%s, last-main=%s" want-indent (current-indentation) + last-parent-major-indent) + ;;(unless (> want-indent (current-indentation)) (setq want-indent nil)) + ) + + ( t + ;; We have to change major mode, because we know nothing + ;; about the requirements of the indent-line-function: + ;; Fix-me: This may be cured by RMS suggestion to + ;; temporarily set all variables back to global values? + (setq this-line-indent-major (mumamo-indent-get-major-to-use this-line-major0 this-depth3)) + (mumamo-msgindent " this-line-indent-major=%s" this-line-indent-major) + (unless (mumamo-fun-eq this-line-indent-major major-mode) (mumamo-set-major this-line-indent-major this-line-chunk0)) + ;; Use the major mode at the beginning of since a sub chunk may + ;; start at start of line. + (if (mumamo-fun-eq this-line-major1 main-major) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;;;;; In main major mode + ;; + ;; Take care of the case when all the text is in a + ;; sub chunk. In that case use the same indentation as if + ;; the code all belongs to the surrounding major mode. + (let ((here (point)) + (use-widen (mumamo-indent-use-widen main-major))) + ;; If we can't indent indent using the main major mode + ;; because it is only blanks and we should not widen, + ;; then use the indentation on the line where it starts. + (mumamo-msgindent " In main major mode") + (forward-line 0) + (skip-chars-backward " \t\n\r\f") + (forward-line 0) + (if (or use-widen (>= (point) (overlay-start this-line-chunk0))) + (progn + (goto-char here) + (mumamo-call-indent-line this-line-chunk0)) + (setq want-indent (current-indentation)) + (goto-char here)) + (mumamo-msgindent " In main major mode B") + (setq last-parent-major-indent (current-indentation))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;;;;; In sub major mode + ;; + ;; Get the indentation the major mode alone would use: + ;;(setq got-indent (mumamo-get-major-mode-indent-column)) + ;; Since this line has another major mode than the + ;; previous line we instead want to indent relative to + ;; that line in a way decided in mumamo: + (mumamo-msgindent " In sub major mode") + (let ((chunk (mumamo-get-chunk-save-buffer-state (point))) + (font-lock-dont-widen t) + ind-zero + (here (point)) + ind-on-first-sub-line) + (save-restriction + (mumamo-update-obscure chunk here) + (let ((syn-min-max (mumamo-chunk-syntax-min-max chunk nil))) + (narrow-to-region (car syn-min-max) + (cdr syn-min-max))) + (condition-case nil + (atomic-change-group + (mumamo-call-indent-line (nth 0 this-line-chunks)) + (when (= 0 (current-indentation)) + (setq ind-zero t) + ;; It is maybe ok if indentation on first sub + ;; line is 0 so check that: + (goto-char (point-min)) + (widen) + (setq ind-on-first-sub-line (current-indentation)) + (goto-char here) + (signal 'mumamo-error-ind-0 nil))) + (mumamo-error-ind-0)) + ;; Unfortunately the indentation can sometimes get 0 + ;; here even though it is clear it should not be 0. This + ;; happens when there are only comments or empty lines + ;; above. + ;; + ;; See c:/test/erik-lilja-index.php for an example. + (when ind-zero ;(and t (= 0 (current-indentation))) + (save-excursion + (setq want-indent 0) + (unless (= 0 ind-on-first-sub-line) + ;;(while (and (> 500 (setq while-n2 (1+ while-n2))) + (while (and (mumamo-while 500 'while-n2 "want-indent") + (= 0 want-indent) + (/= (point) (point-min))) + (beginning-of-line 0) + (setq want-indent (current-indentation))) + ;; Now if want-indent is still 0 we need to look further above + (when (= 0 want-indent) + (widen) + ;;(while (and (> 500 (setq while-n3 (1+ while-n3))) + (while (and (mumamo-while 500 'while-n3 "want-indent 2") + (= 0 want-indent) + (/= (point) (point-min))) + (beginning-of-line 0) + (setq want-indent (current-indentation))) + ;; If we got to the main major mode we need to add + ;; the special submode offset: + (let* ((ovl (mumamo-get-chunk-save-buffer-state (point))) + (major (mumamo-chunk-major-mode ovl))) + (when (mumamo-fun-eq major main-major) + (setq want-indent (+ want-indent + (if (= 0 want-indent) + mumamo-submode-indent-offset-0 + mumamo-submode-indent-offset))))))))) + ))))) + (when want-indent + ;;(msgtrc "indent-line-to %s at line-beginning=%s" want-indent (line-beginning-position)) + (indent-line-to want-indent)) + ;; (when (and template-shift (/= 0 template-shift)) + ;; (let ((ind (+ (current-indentation) template-shift))) + ;; (indent-line-to ind))) + ;; (when template-indent-abs + ;; (indent-line-to template-indent-abs)) + (goto-char here-on-line) + ;;(msgtrc "exit: %s" (list this-line-chunks last-parent-major-indent)) + (list this-line-chunks last-parent-major-indent next-entering-submode))) + +;; Fix-me: use this for first line in a submode +;; Fix-me: check more carefully for widen since it may lead to bad results. +(defun mumamo-indent-use-widen (major-mode) + "Return non-nil if widen before indentation in MAJOR-MODE." + (let* ((specials (cadr (assoc major-mode mumamo-indent-widen-per-major))) + (use-widen (memq 'use-widen specials)) + (use-widen-maybe (assq 'use-widen specials))) + (or use-widen + (memq mumamo-multi-major-mode (cadr use-widen-maybe))))) +;;(mumamo-indent-use-widen 'php-mode) +;;(mumamo-indent-use-widen 'nxhtml-mode) +;;(mumamo-indent-use-widen 'html-mode) + +;; Fix-me: remove +;; (defun mumamo-indent-special-or-default (default-indent) +;; "Indent to DEFAULT-INDENT unless a special indent can be done." +;; (mumamo-with-major-mode-indentation major-mode +;; `(progn +;; (if (mumamo-indent-use-widen major-mode) +;; (save-restriction +;; (widen) +;; (mumamo-msgindent "=> special-or-default did widen, %s" major-mode) +;; (funcall indent-line-function)) +;; (indent-to-column default-indent))))) + +(defun mumamo-call-indent-line (chunk) + "Call the relevant `indent-line-function'." + ;;(msgtrc "call-indent-line %s, lbp=%s" chunk (line-beginning-position)) + (if nil + (mumamo-with-major-mode-indentation major-mode + `(save-restriction + (when (mumamo-indent-use-widen major-mode) + (mumamo-msgindent "=> indent-line did widen") + (widen)) + (funcall indent-line-function))) + (let ((maj (car mumamo-major-mode-indent-line-function)) + (fun (cdr mumamo-major-mode-indent-line-function))) + (assert (mumamo-fun-eq maj major-mode)) + (save-restriction + ;; (unless (mumamo-indent-use-widen major-mode) + ;; (let ((syn-min-max (mumamo-chunk-syntax-min-max chunk nil))) + ;; (narrow-to-region (car syn-min-max) (cdr syn-min-max)))) + (let ((mumamo-stop-widen (not (mumamo-indent-use-widen major-mode)))) + (if (not mumamo-stop-widen) + (widen) + (let ((syn-min-max (mumamo-chunk-syntax-min-max chunk nil))) + (narrow-to-region (car syn-min-max) (cdr syn-min-max)))) + ;;(msgtrc "call-indent-line fun=%s" fun) + ;;(funcall fun) + ;; Fix-me: Use mumamo-funcall-evaled to avoid (widen): + (mumamo-funcall-evaled fun) + ))))) + +(defvar mumamo-stop-widen nil) +(when nil + (let* ((fun 'describe-variable) + (lib (symbol-file fun 'defun))) + (find-function-search-for-symbol fun nil lib))) + +(defun mumamo-funcall-evaled (fun &rest args) + "Make sure FUN is evaled, then call it. +This make sure (currently) that defadvice for primitives are +called. They are not called in byte compiled code. + +See URL `http://debbugs.gnu.org/cgi/bugreport.cgi?bug=5863' since +this may change." + (when mumamo-stop-widen + (unless (get fun 'mumamo-evaled) + (let* ((lib (symbol-file fun 'defun)) + (where (find-function-search-for-symbol fun nil lib)) + (buf (car where)) + (pos (cdr where))) + (with-current-buffer buf + (let ((close (and (not (buffer-modified-p)) + (= 1 (point))))) + ;;(goto-char pos) (eval-defun nil) + (msgtrc "mumamo-funcall-evaled %s" (current-buffer)) + (eval-buffer) + (when close (kill-buffer)))) + (put fun 'mumamo-evaled t)))) + (apply 'funcall fun args)) + +;;(require 'advice) +(defun mumamo-defadvice-widen () + (defadvice widen (around + mumamo-ad-widen + activate + compile + ) + (unless (and mumamo-multi-major-mode + mumamo-stop-widen) + ad-do-it))) +(eval-after-load 'mumamo + '(mumamo-defadvice-widen)) + +;; (defadvice font-lock-fontify-buffer (around +;; mumam-ad-font-lock-fontify-buffer +;; activate +;; compile +;; ) +;; (if mumamo-multi-major-mode +;; (save-restriction +;; (let* ((chunk (mumamo-find-chunks (point) "font-lock-fontify-buffer advice")) +;; (syn-min-max (mumamo-chunk-syntax-min-max chunk nil)) +;; (syn-min (car syn-min-max)) +;; (syn-max (cdr syn-min-max)) +;; (mumamo-stop-widen t)) +;; (narrow-to-region syn-min syn-max) +;; (font-lock-fontify-region syn-min syn-max))) +;; ad-do-it)) + +(defun mumamo-indent-region-function (start end) + "Indent the region between START and END." + (save-excursion + (setq end (copy-marker end)) + (goto-char start) + (let ((old-point -1) + prev-line-chunks + last-parent-major-indent + entering-submode-arg + ;; Turn off validation during indentation + (old-rng-validate-mode (when (boundp 'rng-validate-mode) rng-validate-mode)) + (rng-nxml-auto-validate-flag nil) + (nxhtml-use-imenu nil) + fontification-functions + rng-nxml-auto-validate-flag + (nxhtml-mode-hook (mumamo-get-hook-value + 'nxhtml-mode-hook + '(html-imenu-setup))) + ;; + (while-n1 0)) + (when old-rng-validate-mode (rng-validate-mode -1)) + ;;(while (and (> 3000 (setq while-n1 (1+ while-n1))) + (while (and (mumamo-while 3000 'while-n1 "indent-region") + (< (point) end) + (/= old-point (point))) + ;;(message "mumamo-indent-region-function, point=%s" (point)) + (or (and (bolp) (eolp)) + (let ((ret (mumamo-indent-line-function-1 + prev-line-chunks + last-parent-major-indent + entering-submode-arg))) + (setq prev-line-chunks (nth 0 ret)) + (setq last-parent-major-indent (nth 1 ret)) + (setq entering-submode-arg (nth 2 ret)))) + (setq old-point (point)) + (forward-line 1)) + (when old-rng-validate-mode (rng-validate-mode 1))) + (message "Ready indenting region"))) + + +(defun mumamo-fill-forward-paragraph-function(&optional arg) + "Function to move over paragraphs used by filling code. +This is the buffer local value of +`fill-forward-paragraph-function' when mumamo is used." + ;; fix-me: Do this chunk by chunk + ;; Fix-me: use this (but only in v 23) + (let* ((ovl (mumamo-get-chunk-save-buffer-state (point))) + (major (mumamo-chunk-major-mode ovl))) + (mumamo-with-major-mode-fontification major + fill-forward-paragraph-function))) + +(defun mumamo-fill-chunk (&optional justify) + "Fill each of the paragraphs in the current chunk. +Narrow to chunk region trimmed white space at the ends. Then +call `fill-region'. + +The argument JUSTIFY is the same as in `fill-region' and a prefix +behaves the same way as there." + (interactive (progn + (barf-if-buffer-read-only) + (list (if current-prefix-arg 'full)))) + (let* ((ovl (mumamo-get-chunk-save-buffer-state (point))) + (major (mumamo-chunk-major-mode ovl))) + ;; Fix-me: There must be some bug that makes it necessary to + ;; always change mode when fill-paragraph-function is + ;; c-fill-paragraph. + + ;;(unless (mumamo-fun-eq major major-mode) (mumamo-set-major major ovl)) + (mumamo-set-major major ovl) + + (save-restriction + (mumamo-update-obscure ovl (point)) + (let* ((syn-min-max (mumamo-chunk-syntax-min-max ovl nil)) + (syn-min (car syn-min-max)) + (syn-max (cdr syn-min-max)) + use-min + (here (point-marker))) + (goto-char syn-min) + (skip-syntax-forward " ") + ;; Move back over chars that have whitespace syntax but have the p flag. + (backward-prefix-chars) + (setq use-min (point)) + (goto-char syn-max) + (skip-syntax-backward " ") + (fill-region use-min (point) justify))))) + +;; (defvar mumamo-dont-widen) +;; (defadvice widen (around +;; mumamo-ad-widen +;; activate +;; disable +;; compile +;; ) +;; "Make `widen' do nothing. +;; This is for `mumamo-fill-paragraph-function' and is necessary +;; when `c-fill-paragraph' is the real function used." +;; (unless (and (boundp 'mumamo-dont-widen) +;; mumamo-dont-widen) +;; ad-do-it)) + +(defadvice flymake-display-warning (around + mumamo-ad-flymake-display-warning + activate + compile) + "Display flymake warnings in the usual Emacs way." + (let ((msg (ad-get-arg 0))) + ;; Fix-me: Can't get backtrace here. Report it. + ;;(setq msg (format (concat msg "\n%S" (with-output-to-string (backtrace))))) + (lwarn '(flymake) :error msg))) +;;(lwarn '(flymake) :error "the warning") + +(defun mumamo-forward-chunk () + "Move forward to next chunk." + (interactive) + (let* ((chunk (mumamo-get-chunk-save-buffer-state (point))) + (end-pos (overlay-end chunk))) + (goto-char (min end-pos + (point-max))))) + +(defun mumamo-backward-chunk () + "Move backward to previous chunk." + (interactive) + (let* ((chunk (mumamo-get-chunk-save-buffer-state (point))) + (start-pos (overlay-start chunk))) + (goto-char (max (1- start-pos) + (point-min))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; Spell checking + +(defun mumamo-flyspell-verify () + "Function used for `flyspell-generic-check-word-predicate'." + (let* ((chunk (when mumamo-multi-major-mode + (mumamo-find-chunks (point) "mumamo-lyspell-verify"))) + (chunk-major (when chunk (mumamo-chunk-major-mode chunk))) + (mode-predicate (when chunk-major + (let ((predicate (get chunk-major + 'flyspell-mode-predicate))) + (if predicate + predicate + (if (mumamo-derived-from-mode chunk-major + 'text-mode) + nil + 'flyspell-generic-progmode-verify))))) + ) + (if mode-predicate + ;; Fix-me: (run-hooks 'flyspell-prog-mode-hook) + (funcall mode-predicate) + t))) + +;; (featurep 'cc-engine) +(eval-after-load 'cc-engine + (progn + ;; From Alan's mail 2009-12-03: C Mode: acceleration in brace + ;; deserts. + ;; Fix-me: Should they be here, or...? + (put 'c-state-cache 'permanent-local t) + (put 'c-state-cache-good-pos 'permanent-local t) + (put 'c-state-nonlit-pos-cache 'permanent-local t) + (put 'c-state-nonlit-pos-cache-limit 'permanent-local t) + (put 'c-state-brace-pair-desert 'permanent-local t) + (put 'c-state-point-min 'permanent-local t) + (put 'c-state-point-min-lit-type 'permanent-local t) + (put 'c-state-point-min-lit-start 'permanent-local t) + (put 'c-state-min-scan-pos 'permanent-local t) + (put 'c-state-old-cpp-beg 'permanent-local t) + (put 'c-state-old-cpp-end 'permanent-local t) + + )) + +;; Fix-me: Seems perhaps like c-state-point-min-lit-start is reset in +;; c-state-mark-point-min-literal because c-state-literal-at returns +;; nil. (Or is (car lit) nil?) + +(defvar mumamo-c-state-cache-init nil) +(make-variable-buffer-local 'mumamo-c-state-cache-init) +(put 'mumamo-c-state-cache-init 'permanent-local t) + +(defun mumamo-c-state-cache-init () + (unless mumamo-c-state-cache-init + ;;(msgtrc "c-state-cache-init running") + (setq mumamo-c-state-cache-init t) + (setq c-state-cache (or c-state-cache nil)) + (put 'c-state-cache 'permanent-local t) + (setq c-state-cache-good-pos (or c-state-cache-good-pos 1)) + (put 'c-state-cache-good-pos 'permanent-local t) + (setq c-state-nonlit-pos-cache (or c-state-nonlit-pos-cache nil)) + (put 'c-state-nonlit-pos-cache 'permanent-local t) + (setq c-state-nonlit-pos-cache-limit (or c-state-nonlit-pos-cache-limit 1)) + (put 'c-state-nonlit-pos-cache-limit 'permanent-local t) + (setq c-state-brace-pair-desert (or c-state-brace-pair-desert nil)) + (put 'c-state-brace-pair-desert 'permanent-local t) + (setq c-state-point-min (or c-state-point-min 1)) + (put 'c-state-point-min 'permanent-local t) + (setq c-state-point-min-lit-type (or c-state-point-min-lit-type nil)) + (put 'c-state-point-min-lit-type 'permanent-local t) + (setq c-state-point-min-lit-start (or c-state-point-min-lit-start nil)) + (put 'c-state-point-min-lit-start 'permanent-local t) + (setq c-state-min-scan-pos (or c-state-min-scan-pos 1)) + (put 'c-state-min-scan-pos 'permanent-local t) + (setq c-state-old-cpp-beg (or c-state-old-cpp-beg nil)) + (put 'c-state-old-cpp-beg 'permanent-local t) + (setq c-state-old-cpp-end (or c-state-old-cpp-end nil)) + (put 'c-state-old-cpp-end 'permanent-local t) + (c-state-mark-point-min-literal))) + +(defadvice c-state-cache-init (around + mumamo-ad-c-state-cache-init + activate + compile + ) + (if (not mumamo-multi-major-mode) + ad-do-it + (mumamo-c-state-cache-init))) + +;; Fix-me: Have to add per chunk local majors for this one. +(defun mumamo-c-state-literal-at (here) + ;; If position HERE is inside a literal, return (START . END), the + ;; boundaries of the literal (which may be outside the accessible bit of the + ;; buffer). Otherwise, return nil. + ;; + ;; This function is almost the same as `c-literal-limits'. It differs in + ;; that it is a lower level function, and that it rigourously follows the + ;; syntax from BOB, whereas `c-literal-limits' uses a "local" safe position. + (let* ((is-here (point)) + (s (syntax-ppss here)) + (ret (when (or (nth 3 s) (nth 4 s)) ; in a string or comment + (parse-partial-sexp (point) (point-max) + nil ; TARGETDEPTH + nil ; STOPBEFORE + s ; OLDSTATE + 'syntax-table) ; stop at end of literal + (cons (nth 8 s) (point))))) + (goto-char is-here) + ret)) + +;; (save-restriction +;; (widen) +;; (let* ((chunk (mumamo-find-chunks (point) "mumamo-c-state-literal-at")) +;; (syntax-min-max (mumamo-chunk-syntax-min-max chunk t))) +;; (narrow-to-region (car syntax-min-max) (cdr syntax-min-max))) +;; (save-excursion +;; (let ((c c-state-nonlit-pos-cache) +;; pos npos lit) +;; ;; Trim the cache to take account of buffer changes. +;; (while (and c (> (car c) c-state-nonlit-pos-cache-limit)) +;; (setq c (cdr c))) +;; (setq c-state-nonlit-pos-cache c) + +;; (while (and c (> (car c) here)) +;; (setq c (cdr c))) +;; (setq pos (or (car c) (point-min))) + +;; (while (<= (setq npos (+ pos c-state-nonlit-pos-interval)) +;; here) +;; (setq lit (c-state-pp-to-literal pos npos)) +;; (setq pos (or (cdr lit) npos)) ; end of literal containing npos. +;; (setq c-state-nonlit-pos-cache (cons pos c-state-nonlit-pos-cache))) + +;; (if (> pos c-state-nonlit-pos-cache-limit) +;; (setq c-state-nonlit-pos-cache-limit pos)) +;; (if (< pos here) +;; (setq lit (c-state-pp-to-literal pos here))) +;; lit)))) + + +(defadvice c-state-literal-at (around + mumamo-ad-c-state-state-literal-at + activate + compile + ) + (if (not mumamo-multi-major-mode) + ad-do-it + (mumamo-c-state-literal-at (ad-get-arg 0)))) + + +(defun mumamo-c-state-get-min-scan-pos () + ;; Return the lowest valid scanning pos. This will be the end of the + ;; literal enclosing point-min, or point-min itself. + (save-restriction + (save-excursion + (widen) + (mumamo-narrow-to-chunk-inner) + (or (and c-state-min-scan-pos + (>= c-state-min-scan-pos (point-min)) + c-state-min-scan-pos) + (if (not c-state-point-min-lit-start) + (goto-char (point-min)) + (goto-char c-state-point-min-lit-start) + (if (eq c-state-point-min-lit-type 'string) + (forward-sexp) + (forward-comment 1))) + (setq c-state-min-scan-pos (point)))))) + +(defadvice c-state-get-min-scan-pos (around + mumamo-ad-c-state-get-min-scan-pos-at + activate + compile + ) + (if (not mumamo-multi-major-mode) + ad-do-it + (setq ad-return-value (mumamo-c-state-get-min-scan-pos)))) + +(eval-after-load 'rng-match +;;; (defun rng-match-init-buffer () +;;; (make-local-variable 'rng-compile-table) +;;; (make-local-variable 'rng-ipattern-table) +;;; (make-local-variable 'rng-last-ipattern-index)) + (progn + (put 'rng-compile-table 'permanent-local t) + (put 'rng-ipattern-table 'permanent-local t) + (put 'rng-last-ipattern-index 'permanent-local t) + )) + +(eval-after-load 'flyspell + (progn + (put 'flyspell-mode 'permanent-local t) + + (put 'flyspell-generic-check-word-predicate 'permanent-local t) + + (put 'flyspell-casechars-cache 'permanent-local t) + (put 'flyspell-ispell-casechars-cache 'permanent-local t) + + (put 'flyspell-not-casechars-cache 'permanent-local t) + (put 'flyspell-ispell-not-casechars-cache 'permanent-local t) + + (put 'flyspell-auto-correct-pos 'permanent-local t) + (put 'flyspell-auto-correct-region 'permanent-local t) + (put 'flyspell-auto-correct-ring 'permanent-local t) + (put 'flyspell-auto-correct-word 'permanent-local t) + + (put 'flyspell-consider-dash-as-word-delimiter-flag 'permanent-local t) + + (put 'flyspell-dash-dictionary 'permanent-local t) + + (put 'flyspell-dash-local-dictionary 'permanent-local t) + + (put 'flyspell-word-cache-start 'permanent-local t) + (put 'flyspell-word-cache-end 'permanent-local t) + (put 'flyspell-word-cache-word 'permanent-local t) + (put 'flyspell-word-cache-result 'permanent-local t) + + (put 'flyspell-word-cache-start 'permanent-local t) + + + (put 'flyspell-kill-ispell-hook 'permanent-local-hook t) + (put 'flyspell-post-command-hook 'permanent-local-hook t) + (put 'flyspell-pre-command-hook 'permanent-local-hook t) + (put 'flyspell-after-change-function 'permanent-local-hook t) + (put 'flyspell-hack-local-variables-hook 'permanent-local-hook t) + (put 'flyspell-auto-correct-previous-hook 'permanent-local-hook t) + + (when mumamo-multi-major-mode + (when (featurep 'flyspell) + (setq flyspell-generic-check-word-predicate 'mumamo-flyspell-verify))) + )) + +(defun flyspell-mumamo-mode () + "Turn on function `flyspell-mode' for multi major modes." + (interactive) + (require 'flyspell) + (setq flyspell-generic-check-word-predicate 'mumamo-flyspell-verify) + (flyspell-mode 1) + ;;(run-hooks 'flyspell-prog-mode-hook) + ) + +(eval-after-load 'sgml-mode + (progn + (put 'sgml-tag-face-alist 'permanent-local t) + (put 'sgml-display-text 'permanent-local t) + (put 'sgml-tag-alist 'permanent-local t) + (put 'sgml-face-tag-alist 'permanent-local t) + (put 'sgml-tag-help 'permanent-local t) + )) + +(eval-after-load 'hl-line + (progn + (put 'hl-line-overlay 'permanent-local t) + )) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; New versions of syntax-ppss functions, temporary written as defadvice. + +(defadvice syntax-ppss-flush-cache (around + mumamo-ad-syntax-ppss-flush-cache + activate + compile + ) + "Support for mumamo. +See the defadvice for `syntax-ppss' for an explanation." + (if (not mumamo-multi-major-mode) + ad-do-it + (let ((pos (ad-get-arg 0))) + (let* ((chunk-at-pos (when (and (boundp 'mumamo-multi-major-mode) + mumamo-multi-major-mode) + (mumamo-find-chunks-1 pos "syntax-ppss-flush-cache")))) + (if chunk-at-pos + (let* ((syntax-ppss-last (overlay-get chunk-at-pos 'syntax-ppss-last)) + (syntax-ppss-cache (overlay-get chunk-at-pos 'syntax-ppss-cache))) + ;;(setq ad-return-value ad-do-it) + ad-do-it + (overlay-put chunk-at-pos 'syntax-ppss-last syntax-ppss-last) + (overlay-put chunk-at-pos 'syntax-ppss-cache syntax-ppss-cache)) + ;;(setq ad-return-value ad-do-it) + ad-do-it + ))))) + +(defvar mumamo-syntax-chunk-at-pos nil + "Internal use.") +(make-variable-buffer-local 'mumamo-syntax-chunk-at-pos) + +;; Fix-me: Is this really needed? +;; See http://lists.gnu.org/archive/html/emacs-devel/2008-04/msg00374.html +(defadvice syntax-ppss-stats (around + mumamo-ad-syntax-ppss-stats + activate + compile + ) + "Support for mumamo. +See the defadvice for `syntax-ppss' for an explanation." + (if mumamo-syntax-chunk-at-pos + (let* ((syntax-ppss-stats + (overlay-get mumamo-syntax-chunk-at-pos 'syntax-ppss-stats))) + ad-do-it + (overlay-put mumamo-syntax-chunk-at-pos 'syntax-ppss-stats syntax-ppss-stats)) + ad-do-it)) + +(defvar mumamo-syntax-ppss-major nil) + +;; FIX-ME: There is a problem with " in xhtml files, especially after +;; syntax="...". Looks like it is the " entry in +;; `sgml-font-lock-syntactic-keywords' that is jumping in! Dumping +;; things in `font-lock-apply-syntactic-highlight' seems to show that. +;; +;; (I have put in some dump code in my patched version of +;; Emacs+EmacsW32 there for that. This is commented out by default +;; and it will only work for the file nxhtml-changes.html which is big +;; enough for the problem to occur. It happens at point 1109.) +;; +;; It is this piece of code where the problem arise: +;; +;; (if (prog1 +;; (zerop (car (syntax-ppss (match-beginning 0)))) +;; (goto-char (match-end 0))) +;; .) +;; +;; +;; It comes from `sgml-font-lock-syntactic-keywords' in sgml-mode.el +;; and is supposed to protect from " that is not inside a tag. +;; However in this case for the second " in syntax="..." `syntax-ppss' +;; returns 0 as the first element in its return value. That happen +;; even though `major-mode' is correctly `html-mode'. It leads to +;; that the property 'syntax with the value (1) is added to the " +;; after the css-mode chunk in syntax="...". The problem persists +;; even if the chunk has `fundamental-mode' instead of `css-mode'. +;; +;; Bypassing the cache for `syntax-pss' by calling +;; `parse-partial-sexp' directly instead of doing ad-do-it (see +;; by-pass-chache in the code below) solves the problem for now. It +;; does not feel like the right solution however. +;; +;; One way of temporary solving the problem is perhaps to modify +;; `mumamo-chunk-attr=' to make "" borders, but I am not sure that it +;; works and it is the wrong solution. +(defadvice syntax-ppss (around + mumamo-ad-syntax-ppss + activate + compile + ) + "Support for mumamo chunks. +For each chunk store as properties of the chunk the parse state +that is normally hold in `syntax-ppss-last' and +`syntax-ppss-cache'. + +Compute the beginning parse state for a chunk this way: + +- If the chunk major mode is the same as the main major mode for + the multi major mode then parse from the beginning of the file + to the beginning of the chunk using the main major mode. While + doing that jump over chunks that do not belong to the main + major mode and cache the state at the end and beginning of the + the main major mode chunks. + +FIX-ME: implement above. Solution?: + (parse-partial-sexp syntax-min (1+ syntax-max) nil nil state-at-syntax-min) +Put this at next chunk's beginning. + +- Otherwise set the state at the beginning of the chunk to nil. + +Do here also other necessary adjustments for this." + (if (not mumamo-multi-major-mode) + ad-do-it + (let ((pos (ad-get-arg 0))) + (unless pos (setq pos (point))) + (let* ((chunk-at-pos (when (and (boundp 'mumamo-multi-major-mode) mumamo-multi-major-mode) + (mumamo-find-chunks-1 pos "syntax-ppss"))) + (dump2 (and (boundp 'dump-quote-hunt) + dump-quote-hunt + (boundp 'start) + ;;(= 1109 start) + ))) + ;;(setq dump2 t) + (setq mumamo-syntax-chunk-at-pos chunk-at-pos) + (when dump2 (msgtrc "\npos=%s point-min=%s mumamo-syntax-ppss.chunk-at-pos=%s" pos (point-min) chunk-at-pos)) + (if chunk-at-pos + (let* ((chunk-syntax-min-max (mumamo-chunk-syntax-min-max chunk-at-pos t)) + (chunk-syntax-min (car chunk-syntax-min-max)) + (chunk-major (mumamo-chunk-major-mode chunk-at-pos)) + (syntax-ppss-last (overlay-get chunk-at-pos 'syntax-ppss-last)) + (syntax-ppss-cache (overlay-get chunk-at-pos 'syntax-ppss-cache)) + (syntax-ppss-last-min (overlay-get chunk-at-pos 'syntax-ppss-last-min)) + (syntax-ppss-cache-min (list syntax-ppss-last-min)) + ;; This must be fetch the same way as in syntax-ppss: + (syntax-begin-function (overlay-get chunk-at-pos 'syntax-begin-function)) + (syntax-ppss-max-span (if chunk-syntax-min + (/ (- pos chunk-syntax-min -2) 2) + syntax-ppss-max-span)) + (syntax-ppss-stats (let ((stats (overlay-get chunk-at-pos 'syntax-ppss-stats))) + (if stats + stats + (default-value 'syntax-ppss-stats)))) + (last-min-pos (or (car syntax-ppss-last-min) + 1)) + ) + ;; If chunk has moved the cached values are invalid. + (unless (= chunk-syntax-min last-min-pos) + (setq syntax-ppss-last nil) + (setq syntax-ppss-last-min nil) + (setq syntax-ppss-cache nil) + (setq syntax-ppss-cache-min nil) + (setq syntax-ppss-stats (default-value 'syntax-ppss-stats))) + (when dump2 + (msgtrc " get syntax-ppss-last-min=%s len=%s chunk=%s" syntax-ppss-last-min (length syntax-ppss-last-min) chunk-at-pos) + (msgtrc " prop syntax-ppss-last-min=%s" (overlay-properties chunk-at-pos)) + (msgtrc " chunk-major=%s, %s, syntax-min=%s\n last-min=%s" chunk-major major-mode chunk-syntax-min syntax-ppss-last-min)) + ;;(setq dump2 nil) + (when syntax-ppss-last-min + (unless (car syntax-ppss-last-min) + ;;(msgtrc "fix-me: emacs bug workaround, setting car of syntax-ppss-last-min") + ;;(setcar syntax-ppss-last-min (1- chunk-syntax-min)) + ;;(msgtrc "fix-me: emacs bug workaround, need new syntax-ppss-last-min because car is nil") + (setq syntax-ppss-last-min nil) + )) + (unless syntax-ppss-last-min + (setq syntax-ppss-last nil) + (save-restriction + (widen) + (let* ((min-pos chunk-syntax-min) + (chunk-sub-major (mumamo-chunk-major-mode chunk-at-pos)) + (main-major (mumamo-main-major-mode)) + (is-main-mode-chunk (mumamo-fun-eq chunk-sub-major main-major))) + (when dump2 (msgtrc " min-pos=%s, is-main-mode-chunk=%s" min-pos is-main-mode-chunk)) + ;; Looks like assert can not be used here for some reason??? + ;;(assert (and min-pos) t) + (unless (and min-pos) (error "defadvice syntax-ppss: (and min-pos=%s)" min-pos)) + (setq syntax-ppss-last-min + (cons min-pos ;;(1- min-pos) + (if nil ;is-main-mode-chunk + ;; Fix-me: previous chunks as a + ;; cache? The problem is updating + ;; this. Perhaps it is possible to + ;; prune how far back to go by + ;; going to the first chunk + ;; backwards where + ;; (pars-partial-sexp min max) is + ;; "nil"? + (mumamo-with-major-mode-fontification main-major + `(parse-partial-sexp 1 ,min-pos nil nil nil nil)) + (parse-partial-sexp 1 1)))) + (setq syntax-ppss-cache-min (list syntax-ppss-last-min)) + (when dump2 (msgtrc " put syntax-ppss-last-min=%s len=%s chunk=%s" syntax-ppss-last-min (length syntax-ppss-last-min) chunk-at-pos)) + (when dump2 (msgtrc " prop syntax-ppss-last-min=%s" (overlay-properties chunk-at-pos))) + (overlay-put chunk-at-pos 'syntax-ppss-last-min syntax-ppss-last-min) + (let ((test-syntax-ppss-last-min + (overlay-get chunk-at-pos 'syntax-ppss-last-min))) + (when dump2 (msgtrc " test syntax-ppss-last-min=%s len=%s" test-syntax-ppss-last-min (length test-syntax-ppss-last-min))) + (when dump2 (msgtrc " propt syntax-ppss-last-min=%s" (overlay-properties chunk-at-pos))) + )))) + (when dump2 (msgtrc " here 0, syntax-ppss-last=%s" syntax-ppss-last)) + (unless syntax-ppss-last + (setq syntax-ppss-last syntax-ppss-last-min) + (setq syntax-ppss-cache syntax-ppss-cache-min)) + ;;(syntax-ppss pos) + (when dump2 (msgtrc " at 1, syntax-ppss-last=%s" syntax-ppss-last)) + (when dump2 (msgtrc " at 1, syntax-ppss-cache=%s" syntax-ppss-cache)) + (let (ret-val + (by-pass-cache t) + (dump2 dump2)) + (if (not by-pass-cache) + (progn + (when dump2 + (let ((old-ppss (cdr syntax-ppss-last)) + (old-pos (car syntax-ppss-last))) + ;;(assert (and old-pos pos) t) + (unless (and old-pos pos) (error "defadvice syntax-ppss: (and old-pos=%s pos=%s)" old-pos pos)) + (msgtrc "parse-partial-sexp=>%s" (parse-partial-sexp old-pos pos nil nil old-ppss)))) + (let (dump2) + (setq ret-val ad-do-it))) + (let ((old-ppss (cdr syntax-ppss-last)) + (old-pos (car syntax-ppss-last))) + (when dump2 + (msgtrc "Xparse-partial-sexp %s %s nil nil %s" old-pos pos old-ppss) + (let (dump2) + (msgtrc "ad-do-it=>%s" ad-do-it))) + (save-restriction + (widen) + ;;(assert (and old-pos pos) t) + (unless (and old-pos pos) (error "defadvice syntax-ppss 2 (and old-pos=%s pos=%s)" old-pos pos)) + (when dump2 + (msgtrc "parse-partial-sexp %s %s nil nil %s" old-pos pos old-ppss)) + (setq ret-val (parse-partial-sexp old-pos pos nil nil old-ppss))))) + (when dump2 (msgtrc " ==>ret-val=%s" ret-val)) + ;;(mumamo-backtrace "syntax-ppss") + (setq ad-return-value ret-val)) + (overlay-put chunk-at-pos 'syntax-ppss-last syntax-ppss-last) + (overlay-put chunk-at-pos 'syntax-ppss-cache syntax-ppss-cache) + (overlay-put chunk-at-pos 'syntax-ppss-stats syntax-ppss-stats) + ) + ad-do-it))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; rng-valid.el support + +;; Fix-me: The solution in this defadvice is temporary. The defadvice +;; for rng-do-some-validation should be fixed instead. +;; (ad-disable-advice 'rng-mark-error 'around 'mumamo-ad-rng-mark-error) +;; (ad-ensable-advice 'rng-mark-error 'around 'mumamo-ad-rng-mark-error) +(defadvice rng-mark-error (around + mumamo-ad-rng-mark-error + activate + compile) + "Adjust range for error to chunks." + (if (not mumamo-multi-major-mode) + ad-do-it + (let* ((beg (ad-get-arg 1)) + (end (ad-get-arg 2)) + (xml-parts nil) + (chunk (mumamo-find-chunks beg "rng-mark-error"))) + (if (not chunk) + ad-do-it + (when (and (not (overlay-get chunk 'mumamo-region)) + (mumamo-valid-nxml-chunk chunk)) + ;; rng-error + (let ((part-beg (max (overlay-start chunk) + beg)) + (part-end (min (overlay-end chunk) + end))) + (when (< part-beg part-end) + (ad-set-arg 1 part-beg) + (ad-set-arg 2 part-end) + ad-do-it))))))) + +(defadvice rng-do-some-validation-1 (around + mumamo-ad-rng-do-some-validation-1 + activate + compile) + "Adjust validation to chunks." + (if (not mumamo-multi-major-mode) + ad-do-it + (let (major-mode-chunk + (point-max (1+ (buffer-size))) ;(save-restriction (widen) (point-max))) + end-major-mode-chunk + (limit (+ rng-validate-up-to-date-end + rng-validate-chunk-size)) + (remove-start rng-validate-up-to-date-end) + (next-cache-point (+ (point) rng-state-cache-distance)) + (continue t) + (xmltok-dtd rng-dtd) + have-remaining-chars + xmltok-type + xmltok-start + xmltok-name-colon + xmltok-name-end + xmltok-replacement + xmltok-attributes + xmltok-namespace-attributes + xmltok-dependent-regions + xmltok-errors + (while-n1 0) + (while-n2 0) + (old-point -1) + ) + ;;(msgtrc "> > > > > enter rng-do-some-validation-1, continue-p-function=%s" continue-p-function) + (setq have-remaining-chars (< (point) point-max)) + (when (and continue (= (point) 1)) + (let ((regions (xmltok-forward-prolog))) + (rng-clear-overlays 1 (point)) + (while regions + (when (eq (aref (car regions) 0) 'encoding-name) + (rng-process-encoding-name (aref (car regions) 1) + (aref (car regions) 2))) + (setq regions (cdr regions)))) + (unless (equal rng-dtd xmltok-dtd) + (rng-clear-conditional-region)) + (setq rng-dtd xmltok-dtd)) + (setq while-n1 0) + (while (and (mumamo-while 2000 'while-n1 "continue") + (/= old-point (point)) + continue) + (setq old-point (point)) + ;; If mumamo (or something similar) is used then jump over parts + ;; that can not be parsed by nxml-mode. + (when (and rng-get-major-mode-chunk-function + rng-valid-nxml-major-mode-chunk-function + rng-end-major-mode-chunk-function) + (let ((here (point)) + next-non-space-pos) + (skip-chars-forward " \t\r\n") + (setq next-non-space-pos (point)) + (goto-char here) + (unless (and end-major-mode-chunk + ;; Remaining chars in this chunk? + (< next-non-space-pos end-major-mode-chunk)) + (setq end-major-mode-chunk nil) + (setq major-mode-chunk (funcall rng-get-major-mode-chunk-function next-non-space-pos "rng-do-some-validation-1 A")) + (setq while-n2 0) + (while (and (mumamo-while 500 'while-n2 "major-mode-chunk") + major-mode-chunk + (not (funcall rng-valid-nxml-major-mode-chunk-function major-mode-chunk)) + (< next-non-space-pos (point-max))) + ;;(msgtrc "next-non-space-pos=%s, cb=%s" next-non-space-pos (current-buffer)) + (let ((end-pos (funcall rng-end-major-mode-chunk-function major-mode-chunk))) + ;; fix-me: The problem here is that + ;; mumamo-find-chunks can return a 0-length chunk. + ;;(goto-char (+ end-pos 0)) + (goto-char (+ end-pos (if (= end-pos (point)) 1 0))) + (setq major-mode-chunk (funcall rng-get-major-mode-chunk-function (point) "rng-do-some-validation-1 B")) + ;;(message "---> here 3, point=%s, ep=%s, mm-chunk=%s" (point) end-pos major-mode-chunk) + ) + (setq next-non-space-pos (point)))) + ;; Stop parsing if we do not have a chunk here yet. + ;;(message "major-mode-chunk=%s" major-mode-chunk) + ;;(message "rng-valid-nxml-major-mode-chunk-function=%s" rng-valid-nxml-major-mode-chunk-function) + (setq continue (and major-mode-chunk + (funcall rng-valid-nxml-major-mode-chunk-function major-mode-chunk))) + ;;(unless continue (message "continue=nil, no major-mode-chunk")) + (when continue + ;;(message " continue=t") + (setq end-major-mode-chunk (funcall rng-end-major-mode-chunk-function major-mode-chunk))))) + + (when continue + ;; Narrow since rng-forward will continue into next chunk + ;; even if limit is at chunk end. + (if t + (progn + ;;(message "before rng-forward, point=%s" (point)) + (setq have-remaining-chars (rng-forward end-major-mode-chunk)) + ;;(message "after rng-forward, point=%s" (point)) + ) + ;; Fix-me: Validation does not work when narrowing because + ;; some state variables values seems to be lost. Probably + ;; looking at `rng-validate-prepare' will tell what to do. + (save-restriction + (when (and end-major-mode-chunk + (< (point-min) end-major-mode-chunk)) + (narrow-to-region (point-min) end-major-mode-chunk)) + (setq have-remaining-chars (rng-forward end-major-mode-chunk))) + (unless (> end-major-mode-chunk (point)) + ;;(setq have-remaining-chars t) + (goto-char end-major-mode-chunk)) + ) + ;;(message "end-major-mode-chunk=%s, rng-validate-up-to-date-end=%s" end-major-mode-chunk rng-validate-up-to-date-end) + (setq have-remaining-chars (< (point) point-max)) + ;;(unless have-remaining-chars (message "*** here have-remaining-chars=%s, p=%s/%s" have-remaining-chars (point) point-max)) + (let ((pos (point))) + (when end-major-mode-chunk + ;; Fix-me: Seems like we need a new initialization (or why + ;; do we otherwise hang without this?) + (and (> limit end-major-mode-chunk) (setq limit end-major-mode-chunk))) + (setq continue + (and have-remaining-chars + continue + (or (< pos limit) + (and continue-p-function + (funcall continue-p-function) + (setq limit (+ limit rng-validate-chunk-size)) + t)))) + ;;(unless continue (message "continue=nil, why?: %s<%s, %s" pos limit (when continue-p-function (funcall continue-p-function)))) + (cond ((and rng-conditional-up-to-date-start + ;; > because we are getting the state from (1- pos) + (> pos rng-conditional-up-to-date-start) + (< pos rng-conditional-up-to-date-end) + (rng-state-matches-current (get-text-property (1- pos) + 'rng-state))) + (when (< remove-start (1- pos)) + (rng-clear-cached-state remove-start (1- pos))) + ;; sync up with cached validation state + (setq continue nil) + ;; do this before settting rng-validate-up-to-date-end + ;; in case we get a quit + (rng-mark-xmltok-errors) + (rng-mark-xmltok-dependent-regions) + (setq rng-validate-up-to-date-end + (marker-position rng-conditional-up-to-date-end)) + (rng-clear-conditional-region) + (setq have-remaining-chars + (< rng-validate-up-to-date-end point-max)) + ;;(unless have-remaining-chars (message "have-remaining-chars=%s rng-validate-up-to-date-end=%s, point-max=%s" have-remaining-chars rng-validate-up-to-date-end point-max)) + ) + ((or (>= pos next-cache-point) + (not continue)) + (setq next-cache-point (+ pos rng-state-cache-distance)) + (rng-clear-cached-state remove-start pos) + (when have-remaining-chars + ;;(message "rng-cach-state (1- %s)" pos) + (rng-cache-state (1- pos))) + (setq remove-start pos) + (unless continue + ;; if we have just blank chars skip to the end + (when have-remaining-chars + (skip-chars-forward " \t\r\n") + (when (= (point) point-max) + (rng-clear-overlays pos (point)) + (rng-clear-cached-state pos (point)) + (setq have-remaining-chars nil) + ;;(message "have-remaining-chars => nil, cause (point) = point-max") + (setq pos (point)))) + (when (not have-remaining-chars) + (rng-process-end-document)) + (rng-mark-xmltok-errors) + (rng-mark-xmltok-dependent-regions) + (setq rng-validate-up-to-date-end pos) + (when rng-conditional-up-to-date-end + (cond ((<= rng-conditional-up-to-date-end pos) + (rng-clear-conditional-region)) + ((< rng-conditional-up-to-date-start pos) + (set-marker rng-conditional-up-to-date-start + pos)))))))))) + ;;(message "--- exit rng-do-some-validation-1, have-remaining-chars=%s" have-remaining-chars) + (setq have-remaining-chars (< (point) point-max)) + (setq ad-return-value have-remaining-chars)))) + +(defadvice rng-after-change-function (around + mumamo-ad-rng-after-change-function + activate + compile) + (when rng-validate-up-to-date-end + ad-do-it)) + +(defadvice rng-validate-while-idle (around + mumamo-ad-rng-validate-while-idle + activate + compile) + (if (not (buffer-live-p buffer)) + (rng-kill-timers) + ad-do-it)) + +(defadvice rng-validate-quick-while-idle (around + mumamo-ad-rng-validate-quick-while-idle + activate + compile) + (if (not (buffer-live-p buffer)) + (rng-kill-timers) + ad-do-it)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; xmltok.el + +;; (ad-disable-advice 'xmltok-add-error 'around 'mumamo-ad-xmltok-add-error) +;; (ad-ensable-advice 'xmltok-add-error 'around 'mumamo-ad-xmltok-add-error) +(defadvice xmltok-add-error (around + mumamo-ad-xmltok-add-error + activate + compile + ) + "Prevent rng validation errors in non-xml chunks. +This advice only prevents adding nxml/rng-valid errors in non-xml +chunks. Doing more seems like a very big job - unless Emacs gets +a narrow-to-multiple-regions function!" + (if (not mumamo-multi-major-mode) + ad-do-it + ;;(error "xmltok-add-error: %S" (with-output-to-string (backtrace))) + (when (let* ((start (or start xmltok-start)) + (end (or end (point))) + (chunk (mumamo-find-chunks (if start start end) "xmltok-add-error")) + ) + (or (not chunk) + (and (not (overlay-get chunk 'mumamo-region)) + (mumamo-valid-nxml-chunk chunk)))) + (setq xmltok-errors + (cons (xmltok-make-error message + (or start xmltok-start) + (or end (point))) + xmltok-errors))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Maybe activate advices + +;; Fix-me: This assumes there are no other advices on these functions. +(if t + (progn + ;; (ad-activate 'syntax-ppss) + ;; (ad-activate 'syntax-ppss-flush-cache) + ;; (ad-activate 'syntax-ppss-stats) + ;; (ad-activate 'rng-do-some-validation-1) + ;; (ad-activate 'rng-mark-error) + ;; (ad-activate 'xmltok-add-error) + (ad-enable-advice 'syntax-ppss 'around 'mumamo-ad-syntax-ppss) + (ad-enable-advice 'syntax-ppss-flush-cache 'around 'mumamo-ad-syntax-ppss-flush-cache) + (ad-enable-advice 'syntax-ppss-stats 'around 'mumamo-ad-syntax-ppss-stats) + (ad-enable-advice 'rng-do-some-validation-1 'around 'mumamo-ad-rng-do-some-validation-1) + (ad-enable-advice 'rng-mark-error 'around 'mumamo-ad-rng-mark-error) + (ad-enable-advice 'rng-after-change-function 'around 'mumamo-ad-rng-after-change-function) + (ad-enable-advice 'rng-validate-while-idle 'around 'mumamo-ad-rng-validate-while-idle) + (ad-enable-advice 'rng-validate-quick-while-idle 'around 'mumamo-ad-rng-validate-quick-while-idle) + (ad-enable-advice 'xmltok-add-error 'around 'mumamo-ad-xmltok-add-error) + ) + ;; (ad-deactivate 'syntax-ppss) + ;; (ad-deactivate 'syntax-ppss-flush-cache) + ;; (ad-deactivate 'syntax-ppss-stats) + ;; (ad-deactivate 'rng-do-some-validation-1) + ;; (ad-deactivate 'rng-mark-error) + ;; (ad-deactivate 'xmltok-add-error) + (ad-disable-advice 'syntax-ppss 'around 'mumamo-ad-syntax-ppss) + (ad-disable-advice 'syntax-ppss-flush-cache 'around 'mumamo-ad-syntax-ppss-flush-cache) + (ad-disable-advice 'syntax-ppss-stats 'around 'mumamo-ad-syntax-ppss-stats) + (ad-disable-advice 'rng-do-some-validation-1 'around 'mumamo-ad-rng-do-some-validation-1) + (ad-disable-advice 'rng-mark-error 'around 'mumamo-ad-rng-mark-error) + (ad-disable-advice 'rng-after-change-function 'around 'mumamo-ad-rng-after-change-function) + (ad-disable-advice 'rng-validate-while-idle 'around 'mumamo-ad-rng-validate-while-idle) + (ad-disable-advice 'rng-validate-quick-while-idle 'around 'mumamo-ad-rng-validate-quick-while-idle) + (ad-disable-advice 'xmltok-add-error 'around 'mumamo-ad-xmltok-add-error) + ) + +(font-lock-add-keywords + 'emacs-lisp-mode + '(("\\" . font-lock-keyword-face))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Simple defadvice to move into Emacs later + +(defun mumamo-ad-desktop-buffer-info (buffer) + (set-buffer buffer) + (list + ;; base name of the buffer; replaces the buffer name if managed by uniquify + (and (fboundp 'uniquify-buffer-base-name) (uniquify-buffer-base-name)) + ;; basic information + (desktop-file-name (buffer-file-name) desktop-dirname) + (buffer-name) + (if mumamo-multi-major-mode mumamo-multi-major-mode major-mode) + ;; minor modes + (let (ret) + (mapc + #'(lambda (minor-mode) + (and (boundp minor-mode) + (symbol-value minor-mode) + (let* ((special (assq minor-mode desktop-minor-mode-table)) + (value (cond (special (cadr special)) + ((functionp minor-mode) minor-mode)))) + (when value (add-to-list 'ret value))))) + (mapcar #'car minor-mode-alist)) + ret) + ;; point and mark, and read-only status + (point) + (list (mark t) mark-active) + buffer-read-only + ;; auxiliary information + (when (functionp desktop-save-buffer) + (funcall desktop-save-buffer desktop-dirname)) + ;; local variables + (let ((locals desktop-locals-to-save) + (loclist (buffer-local-variables)) + (ll)) + (while locals + (let ((here (assq (car locals) loclist))) + (if here + (setq ll (cons here ll)) + (when (member (car locals) loclist) + (setq ll (cons (car locals) ll))))) + (setq locals (cdr locals))) + ll))) + +(defadvice desktop-buffer-info (around + mumamo-ad-desktop-buffer-info + activate + compile) + (setq ad-return-value (mumamo-ad-desktop-buffer-info (ad-get-arg 0)))) + +(defun mumamo-ad-set-auto-mode-0 (mode &optional keep-mode-if-same) + "Apply MODE and return it. +If optional arg KEEP-MODE-IF-SAME is non-nil, MODE is chased of +any aliases and compared to current major mode. If they are the +same, do nothing and return nil." + (unless (and keep-mode-if-same + (eq (indirect-function mode) + (if mumamo-multi-major-mode + (indirect-function mumamo-multi-major-mode) + (indirect-function major-mode)))) + (when mode + (funcall mode) + mode))) + +(defadvice set-auto-mode-0 (around + mumamo-ad-set-auto-mode-0 + activate + compile) + (setq ad-return-value (mumamo-ad-set-auto-mode-0 (ad-get-arg 0) + (ad-get-arg 1) + ))) + + + +(defvar mumamo-sgml-get-context-last-close nil + "Last close tag start. +Only used for outermost level.") + +(defun mumamo-sgml-get-context (&optional until) + "Determine the context of the current position. +By default, parse until we find a start-tag as the first thing on a line. +If UNTIL is `empty', return even if the context is empty (i.e. +we just skipped over some element and got to a beginning of line). + +The context is a list of tag-info structures. The last one is the tag +immediately enclosing the current position. + +Point is assumed to be outside of any tag. If we discover that it's +not the case, the first tag returned is the one inside which we are." + (let ((here (point)) + (stack nil) + (ignore nil) + (context nil) + tag-info + last-close) + ;; CONTEXT keeps track of the tag-stack + ;; STACK keeps track of the end tags we've seen (and thus the start-tags + ;; we'll have to ignore) when skipping over matching open..close pairs. + ;; IGNORE is a list of tags that can be ignored because they have been + ;; closed implicitly. + ;; LAST-CLOSE is last close tag that can be useful for indentation + ;; when on outermost level. + (skip-chars-backward " \t\n") ; Make sure we're not at indentation. + (while + (and (not (eq until 'now)) + (or stack + (not (if until (eq until 'empty) context)) + (not (sgml-at-indentation-p)) + (and context + (/= (point) (sgml-tag-start (car context))) + (sgml-unclosed-tag-p (sgml-tag-name (car context))))) + (setq tag-info (ignore-errors (sgml-parse-tag-backward)))) + + ;; This tag may enclose things we thought were tags. If so, + ;; discard them. + (while (and context + (> (sgml-tag-end tag-info) + (sgml-tag-end (car context)))) + (setq context (cdr context))) + + (cond + ((> (sgml-tag-end tag-info) here) + ;; Oops!! Looks like we were not outside of any tag, after all. + (push tag-info context) + (setq until 'now)) + + ;; start-tag + ((eq (sgml-tag-type tag-info) 'open) + (when (and (null stack) + last-close) + (setq last-close 'no-use)) + (cond + ((null stack) + (if (assoc-string (sgml-tag-name tag-info) ignore t) + ;; There was an implicit end-tag. + nil + (push tag-info context) + ;; We're changing context so the tags implicitly closed inside + ;; the previous context aren't implicitly closed here any more. + ;; [ Well, actually it depends, but we don't have the info about + ;; when it doesn't and when it does. --Stef ] + (setq ignore nil))) + ((eq t (compare-strings (sgml-tag-name tag-info) nil nil + (car stack) nil nil t)) + (setq stack (cdr stack))) + (t + ;; The open and close tags don't match. + (if (not sgml-xml-mode) + (unless (sgml-unclosed-tag-p (sgml-tag-name tag-info)) + (message "Unclosed tag <%s>" (sgml-tag-name tag-info)) + (let ((tmp stack)) + ;; We could just assume that the tag is simply not closed + ;; but it's a bad assumption when tags *are* closed but + ;; not properly nested. + (while (and (cdr tmp) + (not (eq t (compare-strings + (sgml-tag-name tag-info) nil nil + (cadr tmp) nil nil t)))) + (setq tmp (cdr tmp))) + (if (cdr tmp) (setcdr tmp (cddr tmp))))) + (message "Unmatched tags <%s> and " + (sgml-tag-name tag-info) (pop stack))))) + + (if (and (null stack) (sgml-unclosed-tag-p (sgml-tag-name tag-info))) + ;; This is a top-level open of an implicitly closed tag, so any + ;; occurrence of such an open tag at the same level can be ignored + ;; because it's been implicitly closed. + (push (sgml-tag-name tag-info) ignore))) + + ;; end-tag + ((eq (sgml-tag-type tag-info) 'close) + (if (sgml-empty-tag-p (sgml-tag-name tag-info)) + (message "Spurious : empty tag" (sgml-tag-name tag-info)) + ;; Keep track of last close if context will return nil + (when (and (not last-close) + (null stack) + (> here (point-at-eol)) + (let ((here (point))) + (goto-char (sgml-tag-start tag-info)) + (skip-chars-backward " \t") + (prog1 + (bolp) + (goto-char here)))) + (setq last-close tag-info)) + + (push (sgml-tag-name tag-info) stack))) + )) + + ;; return context + (setq mumamo-sgml-get-context-last-close + (when (and last-close + (not (eq last-close 'no-use))) + (sgml-tag-start last-close))) + context)) + +(defadvice sgml-get-context (around + mumamo-ad-sgml-get-context + activate + compile) + (setq ad-return-value (mumamo-sgml-get-context (ad-get-arg 0)))) + +(defun mumamo-sgml-calculate-indent (&optional lcon) + "Calculate the column to which this line should be indented. +LCON is the lexical context, if any." + (unless lcon (setq lcon (sgml-lexical-context))) + + ;; Indent comment-start markers inside