safe-load does not break emacs initialization, should a file be
unreadable while emacs boots up.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(defvar safe-load-error-list ""
"*List of files that reported errors when loaded via safe-load")
#+END_SRC
match-paren will either jump to the "other" paren or simply insert %
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(defun match-paren (arg)
"Go to the matching parenthesis if on parenthesis otherwise insert %."
(interactive "p")
I have some stuff put away in my local dir. I don't want to load it all
at startup time, so it is using the autoload feature. For that to work
load the loaddefs, so autoload knows where to grab stuff
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(load-file (concat jj-elisp-dir "/tiny/loaddefs.el"))
(load-file (concat jj-elisp-local-dir "/loaddefs.el"))
#+END_SRC
Always ensure to have a scratch buffer around.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(save-excursion
(set-buffer (get-buffer-create "*scratch*"))
(lisp-interaction-mode)
(add-hook 'kill-buffer-query-functions 'kill-scratch-buffer))
#+END_SRC
+Handier way to add modes to auto-mode-alist
+#+BEGIN_SRC emacs-lisp tangle:yes
+(defun add-auto-mode (mode &rest patterns)
+ "Add entries to `auto-mode-alist' to use `MODE' for all given file `PATTERNS'."
+ (dolist (pattern patterns)
+ (add-to-list 'auto-mode-alist (cons pattern mode))))
+#+END_SRC
+
+
Helpers for the config
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'use-package)
(require 'bind-key)
#+END_SRC
I also disliked the repeated /add-to-list/ lines, so I now just have
one variable and go over that in a loop.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(defvar jj-elisp-subdirs '(local gnus icicle org/contrib tiny mo-git-blame cedet
cedet/eieio ecb jdee/lisp sunrise multiple-cursors
- auto-complete yasnippet magit)
+ auto-complete yasnippet magit mmm)
"List of subdirectories in jj-elisp-dir to add to load-path")
(let (dirval)
*** Info path
Help emacs to find the info files
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq Info-directory-list '("~/emacs/info"
"/usr/local/share/info/"
"/usr/local/info/"
:ID: 0a1560d9-7e55-47ab-be52-b3a8b8eea4aa
:END:
I dislike the startup message
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq inhibit-splash-screen t)
(setq inhibit-startup-message t)
#+END_SRC
Usually I want the lines to break at 72 characters.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(if (> emacs-major-version 22)
(setq fill-column 72)
(setq default-fill-column 72))
#+END_SRC
And it is nice to have a final newline in files.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq require-final-newline t)
#+END_SRC
After I typed 300 characters or took a break for more than a minute it
would be nice of emacs to save whatever I am on in one of its auto-save
backups. See [[info:emacs#Auto%20Save%20Control][info:emacs#Auto Save Control]] for more details.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq auto-save-interval 300)
(setq auto-save-timeout 60)
#+END_SRC
Set my full name and my default mail address - for whatever wants to use
it later. Also, I am using gnus.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq user-full-name "Joerg Jaspert")
(setq user-mail-address "joerg@ganneff.de")
(setq mail-user-agent (quote gnus-user-agent))
My default mail server. Well, simply a localhost, I have a forwarder that
puts mail off the right way, no need for emacs to have any further
knowledge here.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq smtpmail-default-smtp-server "localhost")
(setq smtpmail-smtp-server "localhost")
#+END_SRC
Enable automatic handling of compressed files.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(auto-compression-mode 1)
#+END_SRC
Emacs forbids a certain set of commands, as they can be very confusing
for new users. Enable them.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(put 'narrow-to-region 'disabled nil)
(put 'narrow-to-page 'disabled nil)
(put 'narrow-to-defun 'disabled nil)
*** Look / Theme
I've tried various different fonts and while I like the Terminus font
most for my shells, in Emacs Inconsolata clearly wins.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(if (> emacs-major-version 22)
(set-frame-font "Inconsolata-14")
(set-default-font "Inconsolata-14"))
I always use dark backgrounds, so tell Emacs about it. No need to
guess around.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq-default frame-background-mode 'dark)
#+END_SRC
entirely liked it. Until I found solarized, which is now not only my
emacs theme, but also for most of my other software too, especially my
shell. Consistent look is great.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(if (boundp 'custom-theme-load-path)
(progn
(defun jj-init-theme ()
#+END_SRC
Make the fringe (gutter) smaller, the argument is a width in pixels (the default is 8)
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(if (fboundp 'fringe-mode)
(fringe-mode 4))
#+END_SRC
+A bit more spacing between buffer lines
+#+BEGIN_SRC emacs-lisp tangle:yes
+(setq-default line-spacing 0.1)
+#+END_SRC
*** Cursor changes
[2013-04-21 So 20:54]
I do not want my cursor to blink.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(blink-cursor-mode -1)
#+END_SRC
*** Menu, Tool and Scrollbar
I don't want to see the menu-bar, tool-bar or scrollbar.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(when window-system
(menu-bar-mode -1)
(tool-bar-mode -1)
For them to work even then, we have to do two things.
1. We have to set the frame alist. We simple set both,
=initial-frame-alist= and =default-frame-alist= to the same value here.
- #+BEGIN_SRC emacs-lisp
+ #+BEGIN_SRC emacs-lisp tangle:yes
(setq initial-frame-alist '(
(horizontal-scroll-bars . nil)
(vertical-scroll-bars . nil)
*** Hilight current line in buffer
As it says, it does a hilight of the current line.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-hl-line-mode +1)
#+END_SRC
*** Allow recursive minibuffers
This allows (additional) minibuffer commands while in the minibuffer.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq enable-recursive-minibuffers 't)
#+END_SRC
And modeline-posn is great. It will hilight the column number in the
modeline in red as soon as you are over the defined limit.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(line-number-mode 1)
(column-number-mode 1)
(size-indication-mode 1)
to get entirely rid of some modes, the other is a function taken from
"Mastering Emacs" which replaces the modes text with an own (set of)
character(s).
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'diminish)
(diminish 'auto-fill-function)
(defvar mode-line-cleaner-alist
be org-mode - it is just so much better to use. And does sensible things
with many README files out there, and various other "crap" you get to
read in emacs.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(if (> emacs-major-version 22)
(setq major-mode 'org-mode)
(setq default-major-mode 'org-mode))
*** Shell
[2013-04-23 Tue 16:43]
Shell. zsh in my case.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq shell-file-name "zsh")
(setq shell-command-switch "-c")
(setq explicit-shell-file-name shell-file-name)
*** Emacs shell
Basic settings for emacs integrated shell
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq eshell-cmpl-cycle-completions nil
eshell-save-history-on-exit t
eshell-cmpl-dir-ignore "\\`\\(\\.\\.?\\|CVS\\|\\.svn\\|\\.git\\)/\\'")
occurence of what is at your cursor position use the following.
*C-x* will insert the current word while *M-up* and *M-down* will just
jump to the next/previous occurence of it.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(define-key isearch-mode-map (kbd "C-x") 'sacha/isearch-yank-current-word)
(global-set-key '[M-up] 'sacha/search-word-backward)
(global-set-key '[M-down] 'sacha/search-word-forward)
*** Frame configuration
I want to see the buffername and its size, not the host I am on in my
frame title.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq frame-title-format "%b (%i)")
#+END_SRC
I don't want some buffers to be killed, **scratch** for example.
In the past I had a long function that just recreated them, but the
=keep-buffers= package is easier.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'keep-buffers)
(keep-buffers-mode 1)
(push '("\\`*scratch" . erase) keep-buffers-protected-alist)
*** yes-or-no-p
Emas usually wants you to type /yes/ or /no/ fully. What a mess, I am
lazy.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(defalias 'yes-or-no-p 'y-or-n-p)
#+END_SRC
*** Language/i18n stuff
In this day and age, UTF-8 is the way to go.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(set-language-environment 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
*** Hilight matching parentheses
While I do have the nifty shortcut to jump to the other parentheses,
hilighting them makes it obvious where they are.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'paren)
(setq show-paren-style 'parenthesis)
(show-paren-mode +1)
*** Kill other buffers
While many editors allow you to close "all the other files, not the one
you are in", emacs doesn't have this... Except, now it will.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-set-key (kbd "C-c k") 'prelude-kill-other-buffers)
#+END_SRC
*** Scrolling
Default scrolling behaviour in emacs is a bit annoying, who wants to
jump half-windows?
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq scroll-margin 0)
(setq scroll-conservatively 100000)
(setq scroll-up-aggressively 0.0)
[2013-04-09 Di 23:31]
The default how emacs handles cutting/pasting with the primary selection
changed in emacs24. I am used to the old way, so get it back.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq x-select-enable-primary t)
(setq x-select-enable-clipboard t ;; copy-paste should work ...
interprogram-paste-function ;; ...with...
*** Global keyboard changes not directly related to a mode
Disable /suspend_frame/ function, I dislike it.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-unset-key [(control z)])
(global-unset-key [(control x) (control z)])
#+END_SRC
set, including newline. But to kill the entire line, one still needs a
*C-a* in front of it. So I change it, by defining a function to do just this for
me. Lazyness++.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(defun kill-entire-line ()
"Kill this entire line (including newline), regardless of where point is within the line."
(interactive)
And the same is true when I'm in org-mode, which has an own kill function...
(the keybinding happens later, after org-mode is loaded fully)
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(defun jj-org-kill-line (&optional arg)
"Kill the entire line, regardless of where point is within the line, org-mode-version"
(interactive "P")
I really hate tabs, so I don't want any indentation to try using them.
And in case a project really needs them, I can change it just for that
file/project, but luckily none of those I work in is as broken.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq-default indent-tabs-mode nil)
#+END_SRC
Make the % key jump to the matching {}[]() if on another, like vi, see [[id:b6e6cf73-9802-4a7b-bd65-fdb6f9745319][the function]]
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-set-key "\M-5" 'match-paren)
#+END_SRC
Easy way to move a line up - or down. Simpler than dealing with C-x C-t
AKA transpose lines.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-set-key [(meta shift up)] 'move-line-up)
(global-set-key [(meta shift down)] 'move-line-down)
#+END_SRC
"Pull" lines up, join them
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-set-key (kbd "M-j")
(lambda ()
(interactive)
#+END_SRC
When I press Enter I almost always want to go to the right indentation on the next line.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-set-key (kbd "RET") 'newline-and-indent)
#+END_SRC
Easier undo, and i don't need suspend-frame
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-set-key (kbd "C-z") 'undo)
#+END_SRC
Window switching, go backwards. (C-x o goes to the next window)
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-set-key (kbd "C-x O") (lambda ()
(interactive)
(other-window -1)))
#+END_SRC
Edit file as root
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-set-key (kbd "C-x C-r") 'prelude-sudo-edit)
#+END_SRC
be really useful, it also should include newlines. It doesn’t do this by
default. Rather, you have to call it with a negative argument. Sure
not, bad Emacs.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-set-key (kbd "M-SPC") 'just-one-space-with-newline)
#+END_SRC
Count which commands I use how often.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(defvar keyfreq-file
(expand-file-name "keyfreq" jj-cache-dir)
"Keyfreq cache file")
(keyfreq-autosave-mode 1)
#+END_SRC
+Duplicate current line
+#+BEGIN_SRC emacs-lisp tangle:yes
+(defun duplicate-line ()
+ "Insert a copy of the current line after the current line."
+ (interactive)
+ (save-excursion
+ (let ((line-text (buffer-substring-no-properties
+ (line-beginning-position)
+ (line-end-position))))
+ (move-end-of-line 1)
+ (newline)
+ (insert line-text))))
+
+(global-set-key (kbd "C-c p") 'duplicate-line)
+#+END_SRC
+
**** ace-jump-mode
[2013-04-28 So 11:26]
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(autoload 'ace-jump-mode "ace-jump-mode" "Emacs quick move minor mode" t)
(define-key global-map (kbd "H-SPC") 'ace-jump-mode)
;; enable a more powerful jump back function from ace jump mode
Usually you can press the *Ins*ert key, to get into overwrite mode. I
don't like that, have broken much with it and so just forbid it by
disabling that.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-unset-key [insert])
(global-unset-key [kp-insert])
#+END_SRC
to clutter up the filesystem everywhere. So I put them into one defined
place, backup-directory, which even contains my username (for systems
where =temporary-file-directory= is not inside my home).
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq backup-directory-alist `(("." . ,jj-backup-directory)))
(setq auto-save-file-name-transforms `((".*" ,jj-backup-directory t)))
#+END_SRC
Weeks start on Monday, not sunday.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq calendar-week-start-day 1)
#+END_SRC
Searches and matches should ignore case.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq-default case-fold-search t)
#+END_SRC
Which buffers to get rid off at midnight.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq clean-buffer-list-kill-buffer-names (quote ("*Help*" "*Apropos*"
"*Man " "*Buffer List*"
"*Compile-Log*"
#+END_SRC
Don't display a cursor in non-selected windows.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq-default cursor-in-non-selected-windows nil)
#+END_SRC
What should be displayed in the mode-line for files with those types
of line endings.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq eol-mnemonic-dos "(DOS)")
(setq eol-mnemonic-mac "(Mac)")
#+END_SRC
Much larger threshold for garbage collection prevents it to run too often.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq gc-cons-threshold 48000000)
#+END_SRC
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq max-lisp-eval-depth 1000)
(setq max-specpdl-size 3000)
#+END_SRC
Unfill paragraph
From https://raw.github.com/qdot/conf_emacs/master/emacs_conf.org
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(defun unfill-paragraph ()
"Takes a multi-line paragraph and makes it into a single line of text."
(interactive)
(fill-paragraph nil)))
#+END_SRC
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq-default indicate-empty-lines t)
#+END_SRC
*** Browser
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq browse-url-browser-function (quote browse-url-generic))
(setq browse-url-generic-program "/usr/bin/x-www-browser")
#+END_SRC
*** When saving a script - make it executable
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p)
#+END_SRC
*** Emacs Server
-#+BEGIN_SRC emacs-lisp
-(server-start)
+#+BEGIN_SRC emacs-lisp tangle:yes
+(require 'server)
+(unless (server-running-p)
+ (server-start))
#+END_SRC
** Customized variables
The following contains a set of variables i may reasonably want to
change on other systems - which don't affect the init file loading
process. So I *can* use the customization interface for it...
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(defgroup ganneff nil
"Modify ganneffs settings"
:group 'environment)
#+END_SRC
+** Compatibility
+[2013-05-21 Tue 23:22]
+Restore removed var alias, used by ruby-electric-brace and others
+#+BEGIN_SRC emacs-lisp tangle:yes
+(unless (boundp 'last-command-char)
+ (defvaralias 'last-command-char 'last-command-event))
+#+END_SRC
+
* Customized variables
:PROPERTIES:
:ID: 0102208d-fdf6-4928-9e40-7e341bd3aa3a
things I keep for a long while into statements somewhere else, not just
custom-set here, but we need it anyways.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq custom-file jj-custom-file)
(safe-load custom-file)
#+END_SRC
configuration.
- Some extras for ruby, used with ruby on rails for example
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(add-to-list 'auto-mode-alist '("\\.rxml$" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.rjs$" . ruby-mode))
(add-to-list 'auto-mode-alist '("\\.rake$" . ruby-mode))
#+END_SRC
- Markdown syntax
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(add-to-list 'auto-mode-alist '("\\.mdwn$" . markdown-mode))
#+END_SRC
- diff
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(add-to-list 'auto-mode-alist '("COMMIT_EDITMSG$" . diff-mode))
#+END_SRC
- perl
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(add-to-list 'auto-mode-alist '("\\.\\([pP][Llm]\\|al\\)\\'" . cperl-mode))
(add-to-list 'auto-mode-alist '("\\.pod$" . pod-mode))
(add-to-list 'auto-mode-alist '("\\.tt$" . tt-mode))
#+END_SRC
- python
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
(add-to-list 'auto-mode-alist '("\\.py$" . python-mode))
(add-to-list 'interpreter-mode-alist '("python" . python-mode))
This mode allows to have keybindings that are only alive when the
region is active. Helpful for things that only do any useful action
then, like for example the [[*multiple%20cursors][multiple cursors]] mode I load later.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'region-bindings-mode)
(region-bindings-mode-enable)
#+END_SRC
** tramp
Transparent Remote (file) Access, Multiple Protocol, remote file editing.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'tramp)
(setq tramp-default-method "ssh")
(setq tramp-persistency-file-name (expand-file-name "tramp" jj-cache-dir))
We configure only a bit of the tiny-tools to load when I should need
them. I don't need much actually, but these things are nice to have.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(autoload 'turn-on-tinyperl-mode "tinyperl" "" t)
(add-hook 'perl-mode-hook 'turn-on-tinyperl-mode)
(add-hook 'cperl-mode-hook 'turn-on-tinyperl-mode)
(autoload 'tinyeat-kill-buffer-lines-point-min "tinyeat" "" t)
#+END_SRC
*** Keyboard changes for tiny-tools
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(global-set-key "\M-;" 'tinycomment-indent-for-comment)
(global-set-key (kbd "ESC C-k") 'tinyeat-kill-line-backward)
I like dired and work a lot with it, but it tends to leave lots of
windows around.
dired-single to the rescue.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(autoload 'dired-single-buffer "dired-single" "" t)
(autoload 'dired-single-buffer-mouse "dired-single" "" t)
(autoload 'dired-single-magic-buffer "dired-single" "" t)
We want some extra key bindings loaded. In case we haven't loaded dired
yet, there won't be a keymap to add to, so add our setup function to the
load hook only. Otherwise just bind the keys.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(if (boundp 'dired-mode-map)
;; we're good to go; just add our bindings
(my-dired-init)
#+END_SRC
A few settings
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq dired-auto-revert-buffer (quote dired-directory-changed-p))
(setq dired-dwim-target t)
(setq dired-listing-switches "-alh")
#+END_SRC
wdired
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq wdired-allow-to-change-permissions t)
#+END_SRC
** filladapt
[2013-05-02 Thu 00:04]
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'filladapt)
(eval-after-load "filladapt" '(diminish 'filladapt-mode))
(setq-default filladapt-mode t)
[2013-05-03 Fri 16:09]
Replace default find-file with find-file-at-point, which tries to
guess the default file/URL from text around the point.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(ffap-bindings)
#+END_SRC
** icicles
[[http://article.gmane.org/gmane.emacs.orgmode/4574/match%3Dicicles]["In case you never heard of it, Icicles is to ‘TAB’ completion what
‘TAB’ completion is to typing things manually every time.”]]
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'icicles)
(icy-mode 1)
#+END_SRC
** uniquify
Always have unique buffernames. See [[http://www.gnu.org/software/emacs/manual/html_node/emacs/Uniquify.html][Uniquify - GNU Emacs Manual]]
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'uniquify)
(setq uniquify-buffer-name-style 'post-forward)
(setq uniquify-after-kill-buffer-p t)
A defined abbrev is a word which expands, if you insert it, into some
different text. Abbrevs are defined by the user to expand in specific
ways.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq save-abbrevs 'silently)
(setq abbrev-file-name (expand-file-name "abbrev_defs" jj-cache-dir))
(if (file-exists-p abbrev-file-name)
Obviously emacs can do syntax hilighting. For more things than you ever
heard about.
And I want to have it everywhere.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'font-lock)
(global-font-lock-mode 1)
(setq font-lock-maximum-decoration t)
#+END_SRC
** miniedit
Edit minibuffer in a full (text-mode) buffer by pressing *M-C-e*.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'miniedit)
(miniedit-install)
#+END_SRC
formats if one exists in the first 8 lines of the file.
- Time-stamp: <>
- Time-stamp: " "
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'time-stamp)
(setq time-stamp-active t)
(setq time-stamp-format "%02H:%02M:%02S (%z) - %02d.%02m.%:y from %u (%U) on %s")
** cperl
I like /cperl-mode/ a bit more than the default /perl-mode/, so set it
up here to be used.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(autoload 'cperl-mode "cperl-mode" )
(defalias 'perl-mode 'cperl-mode)
(setq cperl-hairy t)
#+END_SRC
And have cperl mode give ElDoc a useful string
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(defun my-cperl-eldoc-documentation-function ()
"Return meaningful doc string for `eldoc-mode'."
(car
#+END_SRC
** python
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(autoload 'python-mode "python-mode" "Python Mode." t)
(add-to-list 'auto-mode-alist '("\\.py\\'" . python-mode))
(add-to-list 'interpreter-mode-alist '("python" . python-mode))
If an =ipython= executable is on the path, then assume that IPython is
the preferred method python evaluation.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(when (executable-find "ipython")
(require 'ipython)
(setq org-babel-python-mode 'python-mode))
** sh
I prefer comments to be indented too
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq sh-indent-comment t)
#+END_SRC
** auto-revert
When files change outside emacs for whatever reason I want emacs to deal
with it. Not to have to revert buffers myself
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'autorevert)
(setq global-auto-revert-mode t)
(global-auto-revert-mode)
But then there are some where it would just be deadly - like org-mode,
gnus, so we have a list of modes where we don't want to see it.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'linum)
(setq linum-format "%3d ")
(setq linum-mode-inhibit-modes-list '(org-mode
#+END_SRC
** css
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(autoload 'css-mode "css-mode")
-(setq auto-mode-alist (cons '("\\.css\\'" . css-mode) auto-mode-alist))
+(add-auto-mode 'css-mode "\\.css")
+;;; CSS flymake
+(require 'flymake-css)
+(defun maybe-flymake-css-load ()
+ "Activate flymake-css as necessary, but not in derived modes."
+ (when (eq major-mode 'css-mode)
+ (flymake-css-load)))
+(add-hook 'css-mode-hook 'maybe-flymake-css-load)
+;;; Auto-complete CSS keywords
+(eval-after-load 'auto-complete
+ '(progn
+ (dolist (hook '(css-mode-hook sass-mode-hook scss-mode-hook))
+ (add-hook hook 'ac-css-mode-setup))))
+#+END_SRC
+
+** mmm-mode
+[2013-05-21 Tue 23:39]
+MMM Mode is a minor mode for Emacs that allows Multiple Major Modes to
+coexist in one buffer.
+#+BEGIN_SRC emacs-lisp tangle:yes
+(require 'mmm-auto)
+(setq mmm-global-mode 'buffers-with-submode-classes)
+(setq mmm-submode-decoration-level 2)
+(eval-after-load 'mmm-vars
+ '(progn
+ (mmm-add-group
+ 'html-css
+ '((css-cdata
+ :submode css-mode
+ :face mmm-code-submode-face
+ :front "<style[^>]*>[ \t\n]*\\(//\\)?<!\\[CDATA\\[[ \t]*\n?"
+ :back "[ \t]*\\(//\\)?]]>[ \t\n]*</style>"
+ :insert ((?j js-tag nil @ "<style type=\"text/css\">"
+ @ "\n" _ "\n" @ "</script>" @)))
+ (css
+ :submode css-mode
+ :face mmm-code-submode-face
+ :front "<style[^>]*>[ \t]*\n?"
+ :back "[ \t]*</style>"
+ :insert ((?j js-tag nil @ "<style type=\"text/css\">"
+ @ "\n" _ "\n" @ "</style>" @)))
+ (css-inline
+ :submode css-mode
+ :face mmm-code-submode-face
+ :front "style=\""
+ :back "\"")))
+ (dolist (mode (list 'html-mode 'nxml-mode))
+ (mmm-add-mode-ext-class mode "\\.r?html\\(\\.erb\\)?\\'" 'html-css))
+ (mmm-add-mode-ext-class 'html-mode "\\.php\\'" 'html-php)
+ ))
+
#+END_SRC
** html-helper
Instead of default /html-mode/ I use /html-helper-mode/.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(autoload 'html-helper-mode "html-helper-mode" "Yay HTML" t)
(setq auto-mode-alist (cons '("\\.html$" . html-helper-mode) auto-mode-alist))
(setq auto-mode-alist (cons '("\\.asp$" . html-helper-mode) auto-mode-alist))
#+END_SRC
** auctex
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq auto-mode-alist (cons '("\\.tex\\'" . latex-mode) auto-mode-alist))
(setq TeX-auto-save t)
(setq TeX-parse-self t)
#+END_SRC
** Debian related
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'dpkg-dev-el-loaddefs nil 'noerror)
(require 'debian-el-loaddefs nil 'noerror)
I use org-mode a lot and, having my config for this based on [[*Bernt%20Hansen][the config of Bernt Hansen]],
it is quite extensive. Nevertheless, it starts out small, loading it.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(require 'org)
#+END_SRC
My browsers (Conkeror, Iceweasel) can store links in org-mode. For
that we need org-protocol.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(require 'org-protocol)
#+END_SRC
My current =org-agenda-files= variable only includes a set of
directories.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-agenda-files (quote ("~/org/"
"~/org/debian"
"~/org/debconf"
the list of directories in =org-agenda-files= happens very rarely
since new files in existing directories are automatically picked up.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
;; Keep tasks with dates on the global todo lists
(setq org-agenda-todo-ignore-with-date nil)
'append)
#+END_SRC
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-agenda-persistent-filter t)
(add-hook 'org-agenda-mode-hook
'(lambda () (org-defkey org-agenda-mode-map "W" 'bh/widen))
Well, first we remove =C-c [= and =C-c ]=, as all agenda directories are
setup manually, not by org-mode. Also turn off =C-c ;=, which
comments headlines - a function never used.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(add-hook 'org-mode-hook
(lambda ()
(org-defkey org-mode-map "\C-c[" 'undefined)
#+END_SRC
And now a largish set of keybindings...
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(global-set-key "\C-cl" 'org-store-link)
(global-set-key "\C-ca" 'org-agenda)
(global-set-key "\C-cb" 'org-iswitchb)
*** Tasks, States, Todo fun
First we define the global todo keywords.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-todo-keywords
(quote ((sequence "TODO(t)" "NEXT(n)" "|" "DONE(d@/!)")
(sequence "WAITING(w@/!)" "HOLD(h@/!)" "DELEGATED(g@/!)" "|" "CANCELLED(c@/!)" "PHONE"))))
Fast todo selection allows changing from any task todo state to any
other state directly by selecting the appropriate key from the fast
todo selection key menu.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-use-fast-todo-selection t)
#+END_SRC
Changing a task state is done with =C-c C-t KEY=
where =KEY= is the appropriate fast todo state selection key as defined in =org-todo-keywords=.
The setting
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-treat-S-cursor-todo-selection-as-state-change nil)
#+END_SRC
allows changing todo states with S-left and S-right skipping all of
- Moving a task to =DONE= removes =WAITING= and =CANCELLED= tags
The tags are used to filter tasks in the agenda views conveniently.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-todo-state-tags-triggers
(quote (("CANCELLED" ("CANCELLED" . t))
("WAITING" ("WAITING" . t))
*** Capturing new tasks
Org capture replaces the old remember mode.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-directory "~/org")
(setq org-default-notes-file "~/org/refile.org")
less than a minute to capture some new task details) can leave
empty clock drawers in my tasks which aren't really useful.
The following prevents this.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(add-hook 'org-clock-out-hook 'bh/remove-empty-drawer-on-clock-out 'append)
#+END_SRC
*** Refiling
All my newly captured entries end up in =refile.org= and want to be
moved over to the right place. The following is the setup for it.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
; Targets include this file and any file contributing to the agenda - up to 9 levels deep
(setq org-refile-targets (quote ((nil :maxlevel . 9)
(org-agenda-files :maxlevel . 9))))
*** Custom agenda
Agenda view is the central place for org-mode interaction...
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
;; Do not dim blocked tasks
(setq org-agenda-dim-blocked-tasks nil)
;; Compact the block agenda view
#+END_SRC
*** Time
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
;;
;; Resume clocking task when emacs is restarted
(org-clock-persistence-insinuate)
top-level task and the clock moves to the default task.
**** Reporting
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
;; Agenda clock report parameters
(setq org-agenda-clockreport-parameter-plist
(quote (:link t :maxlevel 5 :fileskip0 t :compact t :narrow 80)))
#+END_SRC
**** Task estimates, column view
Setup column view globally with the following headlines
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
; Set default column view headings: Task Effort Clock_Summary
(setq org-columns-default-format "%80ITEM(Task) %10Effort(Effort){:} %10CLOCKSUM")
#+END_SRC
Setup the estimate for effort values.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
; global Effort estimate values
; global STYLE property values for completion
(setq org-global-properties (quote (("Effort_ALL" . "0:15 0:30 0:45 1:00 2:00 3:00 4:00 5:00 6:00 0:00")
*** Tags
Tags are mostly used for filtering inside the agenda.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
; Tags with fast selection keys
(setq org-tag-alist (quote ((:startgroup)
("@errand" . ?e)
#+END_SRC
*** Archiving
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-archive-mark-done nil)
(setq org-archive-location "%s_archive::* Archived Tasks")
#+END_SRC
*** org-babel
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-ditaa-jar-path "~/java/ditaa0_6b.jar")
(setq org-plantuml-jar-path "~/java/plantuml.jar")
(add-to-list 'org-src-lang-modes (quote ("plantuml" . fundamental)))
#+END_SRC
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
;; Don't have images visible on startup, breaks on console
(setq org-startup-with-inline-images nil)
#+END_SRC
A new exporter created by Nicolas Goaziou was introduced in org 8.0.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
;; Explicitly load required exporters
(require 'ox-html)
(require 'ox-latex)
**** Latex export
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-latex-to-pdf-process
'("xelatex -interaction nonstopmode %f"
"xelatex -interaction nonstopmode %f")) ;; for multiple passes
edit invisible text. =C-c C-r= (org-reveal) will display where the
point is if it is buried in invisible text to allow editing again.
-#+BEGIN_SRC emacs-lisp :tangle yes
+#+BEGIN_SRC emacs-lisp tangle:yes :tangle yes
(setq org-catch-invisible-edits 'error)
#+END_SRC
*** Whatever
-#+BEGIN_SRC emacs-lisp :tangle yes
+#+BEGIN_SRC emacs-lisp tangle:yes :tangle yes
;; disable the default org-mode stuck projects agenda view
(setq org-stuck-projects (quote ("" nil nil "")))
,a. item one
,b. item two
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-alphabetical-lists t)
#+END_SRC
-#+BEGIN_SRC emacs-lisp :tangle yes
+#+BEGIN_SRC emacs-lisp tangle:yes :tangle yes
(setq org-remove-highlights-with-change nil)
(setq org-list-demote-modify-bullet (quote (("+" . "-")
#+END_SRC
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
;; Enable abbrev-mode
(add-hook 'org-mode-hook (lambda () (abbrev-mode 1)))
(setq org-startup-indented t)
The following setting prevents creating blank lines before headings
but allows list items to adapt to existing blank lines around the items:
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-blank-before-new-entry (quote ((heading)
(plain-list-item . auto))))
#+END_SRC
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-reverse-note-order nil)
(setq org-default-notes-file "~/notes.org")
#+END_SRC
Enforce task blocking. Tasks can't go done when there is any subtask
still open. Unless they have a property of =NOBLOCKING: t=
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-enforce-todo-checkbox-dependencies t)
(setq org-enforce-todo-dependencies t)
#+END_SRC
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-fast-tag-selection-single-key (quote expert))
(setq org-footnote-auto-adjust t)
(setq org-hide-block-startup t)
sequence =C-c C-v h= (bound to `=org-babel-describe-bindings=') will
display a list of the code blocks commands and their related keys.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-use-speed-commands t)
(setq org-speed-commands-user (quote (("0" . ignore)
("1" . ignore)
that reading and editing code form inside of your Org-mode files is
much more like reading and editing of code using its major mode.
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-src-fontify-natively t)
(setq org-src-tab-acts-natively t)
#+END_SRC
-#+BEGIN_SRC emacs-lisp :tangle yes
+#+BEGIN_SRC emacs-lisp tangle:yes :tangle yes
(setq org-src-preserve-indentation nil)
(setq org-edit-src-content-indentation 0)
#+END_SRC
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-attach-directory "~/org/data/")
#+END_SRC
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(setq org-agenda-sticky t)
#+END_SRC
**** Checklist handling
[2013-05-11 Sat 22:15]
-#+BEGIN_SRC emacs-lisp tangle:yes
+#+BEGIN_SRC emacs-lisp tangle:yes tangle:yes
(require 'org-checklist)
#+END_SRC
** transient mark
For some reason I prefer this mode more than the way without. I want to
see the marked region.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(transient-mark-mode 1)
#+END_SRC
** cua
about its paste/copy/cut keybindings, the really nice part is the great
support for rectangular regions, which I started to use a lot since I
know this mode. The normal keybindings for those are just to useless.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(cua-mode t)
(setq cua-enable-cua-keys (quote shift))
#+END_SRC
even though the above =cua-enable-cua-keys= setting would only enable
them if the selection is done when the region was marked with a shifted
movement keys.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(cua-selection-mode t)
#+END_SRC
This is [[https://github.com/mbunkus/mo-git-blame][mo-git-blame -- An interactive, iterative 'git blame' mode for
Emacs]].
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(autoload 'mo-git-blame-file "mo-git-blame" nil t)
(autoload 'mo-git-blame-current "mo-git-blame" nil t)
#+END_SRC
[[https://github.com/pft/mingus][Mingus]] is a nice interface to mpd, the Music Player Daemon.
I want to access it from anywhere using =F6=.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(autoload 'mingus "mingus-stays-home" nil t)
(global-set-key (kbd "<f6>") 'mingus)
(setq mingus-dired-add-keys t)
(setq mingus-mpd-root "/share/music/")
#+END_SRC
-** saveplace
-Store at which point I have been in files.
-#+BEGIN_SRC emacs-lisp
-(setq-default save-place t)
-(require 'saveplace)
-(setq save-place-file (expand-file-name "saved-places" jj-cache-dir))
-#+END_SRC
-** savehist
+** sessions
+[2013-05-22 Wed 22:40]
+Save and restore the desktop
+#+BEGIN_SRC emacs-lisp tangle:yes
+(setq desktop-path (list jj-cache-dir))
+(desktop-save-mode 1)
+(defadvice desktop-read (around trace-desktop-errors activate)
+ (let ((debug-on-error t))
+ ad-do-it))
+
+
+;;----------------------------------------------------------------------------
+;; Restore histories and registers after saving
+;;----------------------------------------------------------------------------
+(require 'session)
+
+(setq session-save-file (expand-file-name "session" jj-cache-dir))
+(add-hook 'after-init-hook 'session-initialize)
+
+;; save a bunch of variables to the desktop file
+;; for lists specify the len of the maximal saved data also
+(setq desktop-globals-to-save
+ (append '((extended-command-history . 30)
+ (file-name-history . 100)
+ (grep-history . 30)
+ (compile-history . 30)
+ (minibuffer-history . 50)
+ (query-replace-history . 60)
+ (read-expression-history . 60)
+ (regexp-history . 60)
+ (regexp-search-ring . 20)
+ (search-ring . 20)
+ (comint-input-ring . 50)
+ (shell-command-history . 50)
+ kill-ring
+ desktop-missing-file-warning
+ tags-file-name
+ register-alist)))
+
+#+END_SRC
+*** savehist
[2013-04-21 So 20:25]
Save a bit of history
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle no
(require 'savehist)
(setq savehist-additional-variables
'(search ring regexp-search-ring kill-ring compile-history))
(savehist-mode +1)
#+END_SRC
+*** saveplace
+Store at which point I have been in files.
+#+BEGIN_SRC emacs-lisp tangle:yes
+(setq-default save-place t)
+(require 'saveplace)
+(setq save-place-file (expand-file-name "saved-places" jj-cache-dir))
+#+END_SRC
** easypg
EasyPG is a GnuPG interface for Emacs.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'epa-file)
(epa-file-enable)
#+END_SRC
I took the following from [[http://www.emacswiki.org/emacs/EasyPG][EmacsWiki: Easy PG]]
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(defadvice epg--start (around advice-epg-disable-agent disable)
"Don't allow epg--start to use gpg-agent in plain text
terminals."
(ad-activate 'epg--start)
#+END_SRC
** message
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'message)
(setq message-kill-buffer-on-exit t)
#+END_SRC
Most of my gnus config is in an own file, [[file:gnus.org][gnus.org]], here I only have
what I want every emacs to know.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
;;*** Keyboardmacros
(global-unset-key "\M-n")
(global-set-key "\M-n" 'gnus) ; Start gnus with M-n
url contains code to parse and handle URLs - who would have thought? I
set it to send Accept-language header and tell it to not send email,
operating system or location info.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq url-mime-language-string "de,en")
(setq url-privacy-level (quote (email os lastloc)))
#+END_SRC
** hippie-exp
Crazy way of completion. It looks at the word before point and then
tries to expand it in various ways.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'hippie-exp)
(setq hippie-expand-try-functions-list '(try-expand-dabbrev
try-expand-dabbrev-all-buffers
[2013-04-27 Sa 23:16]
Yasnippet is a template system. Type an abbreviation, expand it into
whatever the snippet holds.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(setq yas-snippet-dirs (expand-file-name "yasnippet/snippets" jj-elisp-dir))
(require 'yasnippet)
(yas-global-mode 1)
The Emacs Lisp Package Archive (may) contain(s) some things I
want. Even though I usually only use it to get the package, then when I
like it move it into my own space. My elpa subdir stays empty.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(when (> emacs-major-version 23)
(require 'package)
(setq package-user-dir (expand-file-name "elpa" jj-cache-dir))
[2013-04-08 Mon 23:57]
Use multiple cursors mode. See [[http://emacsrocks.com/e13.html][Emacs Rocks! multiple cursors]] and
[[https://github.com/emacsmirror/multiple-cursors][emacsmirror/multiple-cursors · GitHub]]
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'multiple-cursors)
(define-key region-bindings-mode-map "a" 'mc/mark-all-like-this)
depth. Each successive level is highlighted a different color. This
makes it easy to spot matching delimiters, orient yourself in the code,
and tell which statements are at the same depth.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(when (require 'rainbow-delimiters nil 'noerror)
(global-rainbow-delimiters-mode))
#+END_SRC
crappy ways one usually knows from other systems which lose
information. undo-tree is different - it helps keeping you sane while
keeping the full power of emacs undo/redo.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'undo-tree)
(global-undo-tree-mode)
(diminish 'undo-tree-mode)
Additionally I would like to keep the region active should I undo
while I have one.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
;; Keep region when undoing in region
(defadvice undo-tree-undo (around keep-region activate)
(if (use-region-p)
** windmove
[2013-04-21 So 20:27]
Use shift + arrow keys to switch between visible buffers
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'windmove)
(windmove-default-keybindings 'hyper)
(setq windmove-wrap-around t)
such as ‘undo’, ‘yank’/’yank-pop’, etc. The highlight disappears at the
next command. The highlighting gives useful visual feedback for what
your operation actually changed in the buffer.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'volatile-highlights)
(volatile-highlights-mode t)
(diminish 'volatile-highlights-mode)
#+END_SRC
** re-builder
Saner regex syntax
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 're-builder)
(setq reb-re-syntax 'string)
#+END_SRC
** magit
[2013-04-21 So 20:48]
magit is a mode for interacting with git.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'magitload)
(require 'magit-svn)
(global-set-key (kbd "C-x g") 'magit-status)
[2013-04-21 So 21:00]
I'm not doing much of it, except for my emacs and gnus configs, but
then I like it nice too...
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(define-key read-expression-map (kbd "TAB") 'lisp-complete-symbol)
(require 'paredit)
+
(setq lisp-coding-hook 'lisp-coding-defaults)
(setq interactive-lisp-coding-hook 'interactive-lisp-coding-defaults)
This highlights some /weaselwords/, a mode to /aid in finding common
writing problems/...
[2013-04-27 Sa 23:29]
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'writegood-mode)
(global-set-key "\C-cg" 'writegood-mode)
#+END_SRC
much possible work for me as it can.
So here, auto-complete-mode, which lets emacs do this, based on what I
already had typed.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'auto-complete)
(setq ac-comphist-file (expand-file-name "ac-comphist.dat" jj-cache-dir))
+(global-auto-complete-mode t)
+
+(setq ac-expand-on-auto-complete nil)
(setq ac-dwim t)
(setq ac-auto-start t)
+;;----------------------------------------------------------------------------
+;; Use Emacs' built-in TAB completion hooks to trigger AC (Emacs >= 23.2)
+;;----------------------------------------------------------------------------
+(setq tab-always-indent 'complete) ;; use 't when auto-complete is disabled
+(add-to-list 'completion-styles 'initials t)
+
+;; hook AC into completion-at-point
+(defun sanityinc/auto-complete-at-point ()
+ (when (and (not (minibufferp))
+ (fboundp 'auto-complete-mode)
+ auto-complete-mode)
+ (auto-complete)))
+
+(defun set-auto-complete-as-completion-at-point-function ()
+ (add-to-list 'completion-at-point-functions 'sanityinc/auto-complete-at-point))
+
+(add-hook 'auto-complete-mode-hook 'set-auto-complete-as-completion-at-point-function)
+
+(require 'ac-dabbrev)
+(set-default 'ac-sources
+ '(ac-source-imenu
+ ac-source-dictionary
+ ac-source-words-in-buffer
+ ac-source-words-in-same-mode-buffers
+ ac-source-words-in-all-buffer
+ ac-source-dabbrev))
+
+(dolist (mode '(magit-log-edit-mode log-edit-mode org-mode text-mode haml-mode
+ sass-mode yaml-mode csv-mode espresso-mode haskell-mode
+ html-mode nxml-mode sh-mode smarty-mode clojure-mode
+ lisp-mode textile-mode markdown-mode tuareg-mode
+ js3-mode css-mode less-css-mode sql-mode ielm-mode))
+ (add-to-list 'ac-modes mode))
+
+;; Exclude very large buffers from dabbrev
+(defun sanityinc/dabbrev-friend-buffer (other-buffer)
+ (< (buffer-size other-buffer) (* 1 1024 1024)))
+
+(setq dabbrev-friend-buffer-function 'sanityinc/dabbrev-friend-buffer)
+
+
;; custom keybindings to use tab, enter and up and down arrows
(define-key ac-complete-mode-map "\t" 'ac-expand)
(define-key ac-complete-mode-map "\r" 'ac-complete)
(define-key ac-complete-mode-map "\M-p" 'ac-previous)
(define-key ac-mode-map (kbd "M-TAB") 'auto-complete)
-(require 'ac-dabbrev)
-(setq ac-sources (list ac-source-dabbrev))
-
(setq auto-completion-syntax-alist (quote (global accept . word))) ;; Use space and punctuation to accept the current the most likely completion.
-(setq auto-completion-min-chars (quote (global . 2))) ;; Avoid completion for short trivial words.
+(setq auto-completion-min-chars (quote (global . 3))) ;; Avoid completion for short trivial words.
(setq completion-use-dynamic t)
(add-hook 'latex-mode-hook 'auto-complete-mode)
[2013-04-28 So 01:13]
YAML is a nice format for data, which is both, human and machine
readable/editable without getting a big headache.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(require 'yaml-mode)
(add-to-list 'auto-mode-alist '("\\.yml$" . yaml-mode))
(add-hook 'yaml-mode-hook
Flycheck is a on-the-fly syntax checking tool, supposedly better than Flymake.
As the one time I tried Flymake i wasn't happy, thats easy to
understand for me.
-#+BEGIN_SRC emacs-lisp
+#+BEGIN_SRC emacs-lisp tangle:yes
(when (> emacs-major-version 23)
(require 'flycheck)
(add-hook 'after-init-hook #'global-flycheck-mode))
#+END_SRC
+** crontab-mode
+[2013-05-21 Tue 23:18]
+#+BEGIN_SRC emacs-lisp tangle:yes
+(require 'crontab-mode)
+(add-auto-mode 'crontab-mode "\\.?cron\\(tab\\)?\\'")
+#+END_SRC
+
+** nxml
+[2013-05-22 Wed 22:02]
+
+nxml-mode is a major mode for editing XML.
+#+BEGIN_SRC emacs-lisp tangle:yes
+(add-auto-mode
+ 'nxml-mode
+ (concat "\\."
+ (regexp-opt
+ '("xml" "xsd" "sch" "rng" "xslt" "svg" "rss"
+ "gpx" "tcx"))
+ "\\'"))
+(setq magic-mode-alist (cons '("<\\?xml " . nxml-mode) magic-mode-alist))
+(fset 'xml-mode 'nxml-mode)
+(setq nxml-slash-auto-complete-flag t)
+
+
+;; See: http://sinewalker.wordpress.com/2008/06/26/pretty-printing-xml-with-emacs-nxml-mode/
+(defun pp-xml-region (begin end)
+ "Pretty format XML markup in region. The function inserts
+linebreaks to separate tags that have nothing but whitespace
+between them. It then indents the markup by using nxml's
+indentation rules."
+ (interactive "r")
+ (save-excursion
+ (nxml-mode)
+ (goto-char begin)
+ (while (search-forward-regexp "\>[ \\t]*\<" nil t)
+ (backward-char) (insert "\n"))
+ (indent-region begin end)))
+
+;;----------------------------------------------------------------------------
+;; Integration with tidy for html + xml
+;;----------------------------------------------------------------------------
+;; tidy is autoloaded
+(eval-after-load 'tidy
+ '(progn
+ (add-hook 'nxml-mode-hook (lambda () (tidy-build-menu nxml-mode-map)))
+ (add-hook 'html-mode-hook (lambda () (tidy-build-menu html-mode-map)))
+ ))
+(add-auto-mode 'html-mode "\\.(jsp|tmpl)\\'")
+
+#+END_SRC
+** ruby
+[2013-05-22 Wed 22:33]
+Programming in ruby...
+
+#+BEGIN_SRC emacs-lisp tangle:yes
+(add-auto-mode 'ruby-mode
+ "Rakefile\\'" "\\.rake\\'" "\.rxml\\'"
+ "\\.rjs\\'" ".irbrc\\'" "\.builder\\'" "\\.ru\\'"
+ "\\.gemspec\\'" "Gemfile\\'" "Kirkfile\\'")
+
+(setq ruby-use-encoding-map nil)
+
+(eval-after-load 'ruby-mode
+ '(progn
+ (define-key ruby-mode-map (kbd "RET") 'reindent-then-newline-and-indent)
+ (define-key ruby-mode-map (kbd "TAB") 'indent-for-tab-command)))
+
+;; Stupidly the non-bundled ruby-mode isn't a derived mode of
+;; prog-mode: we run the latter's hooks anyway in that case.
+(add-hook 'ruby-mode-hook
+ (lambda ()
+ (unless (derived-mode-p 'prog-mode)
+ (run-hooks 'prog-mode-hook))))
+
+;;; ERB
+(defun sanityinc/ensure-mmm-erb-loaded ()
+ (require 'mmm-erb))
+
+(require 'derived)
+
+(defun sanityinc/set-up-mode-for-erb (mode)
+ (add-hook (derived-mode-hook-name mode) 'sanityinc/ensure-mmm-erb-loaded)
+ (mmm-add-mode-ext-class mode "\\.erb\\'" 'erb))
+
+(let ((html-erb-modes '(html-mode html-erb-mode nxml-mode)))
+ (dolist (mode html-erb-modes)
+ (sanityinc/set-up-mode-for-erb mode)
+ (mmm-add-mode-ext-class mode "\\.r?html\\(\\.erb\\)?\\'" 'html-js)
+ (mmm-add-mode-ext-class mode "\\.r?html\\(\\.erb\\)?\\'" 'html-css)))
+
+(mapc 'sanityinc/set-up-mode-for-erb
+ '(coffee-mode js-mode js2-mode js3-mode markdown-mode textile-mode))
+
+(mmm-add-mode-ext-class 'html-erb-mode "\\.jst\\.ejs\\'" 'ejs)
+
+(add-auto-mode 'html-erb-mode "\\.rhtml\\'" "\\.html\\.erb\\'")
+(add-to-list 'auto-mode-alist '("\\.jst\\.ejs\\'" . html-erb-mode))
+(mmm-add-mode-ext-class 'yaml-mode "\\.yaml\\'" 'erb)
+
+(dolist (mode (list 'js-mode 'js2-mode 'js3-mode))
+ (mmm-add-mode-ext-class mode "\\.js\\.erb\\'" 'erb))
+
+#+END_SRC
* Thats it
And thats it for this file, control passes "back" to [[file:../initjj.org][initjj.org/el]]
which then may load more files.
--- /dev/null
+;;; crontab-mode.el --- Mode for editing crontab files
+;; Version: 20090510.2255
+;;
+;; ~/share/emacs/pkg/crontab/crontab-mode.el ---
+;;
+;; $Id: crontab-mode.el,v 1.20 2005/10/04 03:58:52 harley Exp $
+;;
+
+;; Author: Harley Gorrell <harley@mahalito.net>
+;; URL: http://www.mahalito.net/~harley/elisp/crontab-mode.el
+;; License: GPL v2
+;; Keywords: cron, crontab, emacs
+
+;;; Commentary:
+;; * I want to keep my crontabs under rcs to keep a history of
+;; the file. Editing them with 'crontab -e' is rather
+;; cumbersome. My method is to keep the crontab as a file,
+;; under rcs, and check in the changes with 'C-c C-c' after
+;; editing.
+;;
+;; * The remote systems are expected to share a filesystem.
+;; If they dont, modify crontab-shell or crontab-apply to
+;; suit your needs.
+;;
+;; * You may want to add one of these to your startup:
+;; (add-to-list 'auto-mode-alist '("\\.cron\\(tab\\)?\\'" . crontab-mode))
+;; (add-to-list 'auto-mode-alist '("cron\\(tab\\)?\\." . crontab-mode))
+
+;;; History:
+;; 2003-03-16: Updated URL and contact info
+;; 2004-02-26: Use ssh to apply crontabs to remote hosts.
+
+;;; Code:
+
+(defvar crontab-suffix ".crontab"
+ "*Suffix for crontab buffers.")
+
+(defvar crontab-apply-after-save nil
+ "*Non-nil to apply the crontab after a save.")
+(make-variable-buffer-local 'crontab-apply-after-save)
+
+(defvar crontab-host nil
+ "*Hostname to use when saving the crontab to a remote host.")
+(make-variable-buffer-local 'crontab-host)
+
+(defvar crontab-user nil
+ "*Username to use when saving the crontab to a remote host.")
+(make-variable-buffer-local 'crontab-user)
+
+;; Would be better to have "\\([0-9]\\([-,][0-9]+\\)+\\|...
+(defvar crontab-unit-regexp "\\(\\(?:[-,0-9]+\\|\\*\\)\\(?:/[0-9]+\\)?\\)"
+ "A regexp which matches a cron time unit.")
+
+(defvar crontab-sep-regexp "[ \t]+"
+ "A regexp to match whitespace seperating cron time units.")
+
+(defvar crontab-ruler "
+# min hour day month day-of-week command
+#(0-59) (0-23) (1-31) (1-12) (0-6)
+#------------------------------------------------------------
+"
+ "*The ruler `crontab-insert-ruler' inserts.")
+
+;;
+(defvar crontab-mode-hook nil
+ "*Hook for customising `crontab-mode'.")
+
+(defvar crontab-load-hook nil
+ "*Hook run when the `crontab-mode' is loaded.")
+
+;;
+(defvar crontab-font-lock-keywords
+ (list
+ ;; Comments
+ '("^#.*$" . font-lock-comment-face)
+ ;; Blank lines are bad!
+ '("^[ \t]+$" . highlight)
+ ;; Variable defs
+ '("^\\([A-Z_]+\\)=\\(.*\\)$" .
+ ((1 font-lock-keyword-face)
+ (2 font-lock-string-face)) )
+ ;; Cron lines
+ ;; 50 * * * * /usr/gnu/bin/bash
+ (cons
+ (concat "^"
+ crontab-unit-regexp crontab-sep-regexp
+ crontab-unit-regexp crontab-sep-regexp
+ crontab-unit-regexp crontab-sep-regexp
+ crontab-unit-regexp crontab-sep-regexp
+ crontab-unit-regexp crontab-sep-regexp
+ "\\(.*\\)$")
+ '((1 font-lock-keyword-face)
+ (2 font-lock-keyword-face)
+ (3 font-lock-keyword-face)
+ (4 font-lock-keyword-face)
+ (5 font-lock-keyword-face)
+ (6 font-lock-string-face))) )
+ "Info for function `font-lock-mode'.")
+
+(defvar crontab-mode-map nil
+ "Keymap used in `crontab-mode'.")
+
+(if crontab-mode-map
+ ()
+ (setq crontab-mode-map (make-sparse-keymap))
+ (define-key crontab-mode-map "\C-c\C-c" 'crontab-save-and-apply)
+ (define-key crontab-mode-map "\C-cc" 'crontab-save-and-apply)
+ (define-key crontab-mode-map "\C-ca" 'crontab-save-and-apply-to)
+ (define-key crontab-mode-map "\C-ci" 'crontab-insert-local-var)
+ (define-key crontab-mode-map "\C-cr" 'crontab-insert-ruler))
+
+;; This will barf without the correct agent or key setup.
+(defvar crontab-rsh-cmd "ssh" ;; "rsh"
+ "Program to use for remote shells.")
+
+(defun crontab-rsh-cmd ()
+ "Generate the rsh command. Redefine as needed."
+ (if crontab-user
+ (concat crontab-rsh-cmd " -l " (format "%s" crontab-user)) ;; str-ify
+ crontab-rsh-cmd) )
+
+(defun crontab-localhost-p (&optional host)
+ "True if this is the same HOST Emacs is on."
+ (or (null host)
+ (string= host "")
+ (string= host "localhost")
+ (string= host (system-name))) )
+
+(defun crontab-shell (host cmd out-buffer)
+ "On a possibly remote HOST, run CMD Output to OUT-BUFFER."
+ (when (not (crontab-localhost-p host))
+ (setq cmd (concat (crontab-rsh-cmd) " " host " " cmd)))
+ (shell-command cmd out-buffer) )
+
+;;;###autoload
+(defun crontab-mode ()
+ "Major mode for editing crontabs.
+Defines commands for getting and applying crontabs for hosts.
+Sets up command `font-lock-mode'.
+
+\\{crontab-mode-map}"
+ (interactive)
+ ;;
+ (kill-all-local-variables)
+ (setq mode-name "crontab")
+ (setq major-mode 'crontab-mode)
+ (use-local-map crontab-mode-map)
+ ;;
+ (setq comment-start "#")
+ (setq comment-start-skip "#+ *")
+ ;;
+ (make-local-variable 'font-lock-defaults)
+ (setq font-lock-defaults '(crontab-font-lock-keywords))
+ ;; Add to the end of the buffers save hooks.
+ (add-hook 'after-save-hook 'crontab-after-save t t)
+ ;;
+ (run-hooks 'crontab-mode-hook) )
+
+
+;;;###autoload
+(defun crontab-get (host)
+ "Get the crontab for the HOST into a buffer."
+ (interactive "sCrontab for host:")
+ (let ((cbn (generate-new-buffer-name (concat host crontab-suffix))))
+ (switch-to-buffer-other-window cbn)
+ (erase-buffer)
+ (crontab-mode)
+ (crontab-insert host)
+ (not-modified)
+ (setq crontab-host host)) )
+
+(defun crontab-insert (&optional host)
+ "Insert the crontab for the HOST into the current buffer."
+ (crontab-shell host "crontab -l" t) )
+
+(defun crontab-apply (&optional host)
+ "Apply the crontab to a HOST. The filesystem must be common."
+ (if (buffer-file-name)
+ (crontab-shell host (concat "crontab " (buffer-file-name)) nil)
+ (error "No filename for this buffer")))
+
+(defun crontab-save-and-apply ()
+ "Save and apply the buffer to the HOST."
+ (interactive)
+ (save-buffer)
+ (if (not crontab-apply-after-save) ;; Dont apply it twice.
+ (crontab-apply (crontab-host))) )
+
+(defun crontab-save-and-apply-to (host)
+ "Prompt for the HOST and apply the file."
+ (interactive "sApply to host:")
+ (setq crontab-host host) ;; remember the change
+ (crontab-save-and-apply) )
+
+(defun crontab-insert-ruler ()
+ "Insert a ruler with comments into the crontab."
+ (interactive)
+ (end-of-line)
+ (insert crontab-ruler) )
+
+(defun crontab-insert-local-var ()
+ "Insert the current values of buffer local variables."
+ (interactive)
+ (goto-char (point-max))
+ (insert "
+" comment-start " Local " "Variables:
+" comment-start " mode: " (format "%s" (or mode-name "crontab")) "
+" comment-start " crontab-host: " (crontab-host) "
+" comment-start " crontab-apply-after-save: "
+(format "%s" crontab-apply-after-save) "
+" comment-start " End:
+") )
+
+(defun crontab-host ()
+ "Return the hostname as a string, defaulting to the local host.
+The variable `crontab-host' could be a symbol or a string."
+ (format "%s" (or crontab-host system-name)) )
+
+;;
+(defun crontab-after-save ()
+ "If `crontab-apply-after-save' is set, apply the crontab after a save."
+ (if crontab-apply-after-save (crontab-apply (crontab-host))) )
+
+(provide 'crontab-mode)
+(run-hooks 'crontab-load-hook)
+
+;;; crontab-mode.el ends here
--- /dev/null
+;;; flymake-css.el --- Flymake support for css using csslint
+;;
+;;; Author: Steve Purcell <steve@sanityinc.com>
+;;; Homepage: https://github.com/purcell/flymake-css
+;; Version: 20121104.1904
+;;; X-Original-Version: DEV
+;;; Package-Requires: ((flymake-easy "0.1"))
+;;
+;;; Commentary:
+;;
+;; Usage:
+;; (require 'flymake-css)
+;; (add-hook 'css-mode-hook 'flymake-css-load)
+;;
+;; Beware that csslint is quite slow, so there can be a significant lag
+;; between editing and the highlighting of resulting errors.
+;;
+;; Like the author's many other flymake-*.el extensions, this code is
+;; designed to configure flymake in a buffer-local fashion, which
+;; avoids the dual pitfalls of 1) inflating the global list of
+;; `flymake-err-line-patterns' and 2) being required to specify the
+;; matching filename extensions (e.g. "*.css") redundantly.
+;;
+;; Based mainly on the author's flymake-jslint.el, and using the
+;; error regex from Arne Jørgensen's similar flymake-csslint.el.
+;;
+;; Uses flymake-easy, from https://github.com/purcell/flymake-easy
+
+(require 'flymake-easy)
+
+;;; Code:
+
+(defgroup flymake-css nil
+ "Flymake checking of CSS using csslint"
+ :group 'programming
+ :prefix "flymake-css-")
+
+;;;###autoload
+(defcustom flymake-css-lint-command "csslint"
+ "Name (and optionally full path) of csslint executable."
+ :type 'string :group 'flymake-css)
+
+(defvar flymake-css-err-line-patterns
+ '(("^\\(.*\\): line \\([[:digit:]]+\\), col \\([[:digit:]]+\\), \\(.+\\)$" 1 2 3 4)))
+
+(defun flymake-css-command (filename)
+ "Construct a command that flymake can use to check css source."
+ (list flymake-css-lint-command "--format=compact" filename))
+
+
+;;;###autoload
+(defun flymake-css-load ()
+ "Configure flymake mode to check the current buffer's css syntax."
+ (interactive)
+ (when (eq major-mode 'css-mode)
+ ;; Don't activate in derived modes, e.g. less-css-mode
+ (flymake-easy-load 'flymake-css-command
+ flymake-css-err-line-patterns
+ 'tempdir
+ "css")))
+
+
+(provide 'flymake-css)
+;;; flymake-css.el ends here
--- /dev/null
+;;; flymake-easy.el --- Helpers for easily building flymake checkers
+
+;; Copyright (C) 2012 Steve Purcell
+
+;; Author: Steve Purcell <steve@sanityinc.com>
+;; URL: https://github.com/purcell/flymake-easy
+;; Version: 20130520.1855
+;; X-Original-Version: DEV
+;; Keywords: convenience, internal
+
+;; 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 <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This library provides the `flymake-easy-load' helper function for
+;; setting up flymake checkers. Just call that function with the
+;; appropriate arguments in a major mode hook function. See
+;; `flymake-ruby' for an example:
+;; https://github.com/purcell/flymake-ruby
+
+;;; Code:
+
+(require 'flymake)
+
+(defvar flymake-easy--active nil
+ "Indicates when flymake-easy-load has successfully run in this buffer.")
+(defvar flymake-easy--command-fn nil
+ "The user-specified function for building the flymake command.")
+(defvar flymake-easy--location nil
+ "Where to create the temp file when checking, one of 'tempdir or 'inplace.")
+(defvar flymake-easy--extension nil
+ "The canonical file name extension to use for the current file.")
+
+(mapc 'make-variable-buffer-local
+ '(flymake-easy--active
+ flymake-easy--command-fn
+ flymake-easy--location
+ flymake-easy--extension))
+
+(defun flymake-easy--tempfile-in-temp-dir (file-name prefix)
+ "Create a temporary file for storing the contents of FILE-NAME in the system tempdir.
+Argument PREFIX temp file prefix, supplied by flymake."
+ (make-temp-file (or prefix "flymake-easy")
+ nil
+ (concat "." flymake-easy--extension)))
+
+(defun flymake-easy--flymake-init ()
+ "A catch-all flymake init function for use in `flymake-allowed-file-name-masks'."
+ (let* ((tempfile
+ (flymake-init-create-temp-buffer-copy
+ (cond
+ ((eq 'tempdir flymake-easy--location)
+ 'flymake-easy--tempfile-in-temp-dir)
+ ((eq 'inplace flymake-easy--location)
+ 'flymake-create-temp-inplace)
+ (t
+ (error "unknown location for flymake-easy: %s" flymake-easy--location)))))
+ (command (funcall flymake-easy--command-fn tempfile)))
+ (list (car command) (cdr command))))
+
+(defun flymake-easy-exclude-buffer-p ()
+ "Whether to skip flymake in the current buffer."
+ (and (fboundp 'tramp-tramp-file-p)
+ (buffer-file-name)
+ (tramp-tramp-file-p (buffer-file-name))))
+
+(defun flymake-easy-load (command-fn &optional err-line-patterns location extension warning-re info-re)
+ "Enable flymake in the containing buffer using a specific narrow configuration.
+Argument COMMAND-FN function called to build the
+ command line to run (receives filename, returns list).
+Argument ERR-LINE-PATTERNS patterns for identifying errors (see `flymake-err-line-patterns').
+Argument EXTENSION a canonical extension for this type of source file, e.g. \"rb\".
+Argument LOCATION where to create the temporary copy: one of 'tempdir (default) or 'inplace.
+Argument WARNING-RE a pattern which identifies error messages as warnings.
+Argument INFO-RE a pattern which identifies messages as infos (supported only
+by the flymake fork at https://github.com/illusori/emacs-flymake)."
+ (let ((executable (car (funcall command-fn "dummy"))))
+ (if (executable-find executable) ;; TODO: defer this checking
+ (unless (flymake-easy-exclude-buffer-p)
+ (setq flymake-easy--command-fn command-fn
+ flymake-easy--location (or location 'tempdir)
+ flymake-easy--extension extension
+ flymake-easy--active t)
+ (set (make-local-variable 'flymake-allowed-file-name-masks)
+ '(("." flymake-easy--flymake-init)))
+ (when err-line-patterns
+ (set (make-local-variable 'flymake-err-line-patterns) err-line-patterns))
+ (dolist (var '(flymake-warning-re flymake-warn-line-regexp))
+ (set (make-local-variable var) (or warning-re "^[wW]arn")))
+ (when (boundp 'flymake-info-line-regexp)
+ (set (make-local-variable 'flymake-info-line-regexp)
+ (or info-re "^[iI]nfo")))
+ (flymake-mode t))
+ (message "Not enabling flymake: '%s' program not found" executable))))
+
+;; Internal overrides for flymake
+
+(defun flymake-easy--find-all-matches (str)
+ "Return all matched for error line patterns in STR.
+
+This is a judicious override for `flymake-split-output', enabled
+by the advice below, which allows for matching multi-line
+patterns."
+ (let (matches
+ (last-match-end-pos 0))
+ (dolist (pattern flymake-err-line-patterns)
+ (let ((regex (car pattern))
+ (pos 0))
+ (while (string-match regex str pos)
+ (push (match-string 0 str) matches)
+ (setq pos (match-end 0)))
+ (setf last-match-end-pos (max pos last-match-end-pos))))
+ (let ((residual (substring str last-match-end-pos)))
+ (list matches
+ (unless (string= "" residual) residual)))))
+
+(defadvice flymake-split-output (around flymake-easy--split-output (output) activate protect)
+ "Override `flymake-split-output' to support mult-line error messages."
+ (setq ad-return-value (if flymake-easy--active
+ (flymake-easy--find-all-matches output)
+ ad-do-it)))
+
+
+(defadvice flymake-post-syntax-check (before flymake-easy--force-check-was-interrupted activate)
+ (when flymake-easy--active
+ (setq flymake-check-was-interrupted t)))
+
+
+(provide 'flymake-easy)
+
+;; Local Variables:
+;; coding: utf-8
+;; byte-compile-warnings: (not cl-functions)
+;; eval: (checkdoc-minor-mode 1)
+;; End:
+
+;;; flymake-easy.el ends here
;;;***
\f
+;;;### (autoloads (crontab-get crontab-mode) "crontab-mode" "crontab-mode.el"
+;;;;;; (20891 58911 0 0))
+;;; Generated autoloads from crontab-mode.el
+
+(autoload 'crontab-mode "crontab-mode" "\
+Major mode for editing crontabs.
+Defines commands for getting and applying crontabs for hosts.
+Sets up command `font-lock-mode'.
+
+\\{crontab-mode-map}
+
+\(fn)" t nil)
+
+(autoload 'crontab-get "crontab-mode" "\
+Get the crontab for the HOST into a buffer.
+
+\(fn HOST)" t nil)
+
+;;;***
+\f
;;;### (autoloads (diminished-modes diminish-undo diminish) "diminish"
;;;;;; "diminish.el" (20865 30363 579223 949000))
;;; Generated autoloads from diminish.el
;;;***
\f
-;;;### (autoloads (toggle-follow-mouse turn-off-follow-mouse turn-on-follow-mouse)
-;;;;;; "follow-mouse" "follow-mouse.el" (20858 49922 453891 89000))
-;;; Generated autoloads from follow-mouse.el
+;;;### (autoloads (flymake-css-load flymake-css-lint-command) "flymake-css"
+;;;;;; "flymake-css.el" (20891 59932 137784 394000))
+;;; Generated autoloads from flymake-css.el
-(autoload 'turn-on-follow-mouse "follow-mouse" "\
-Moving the mouse will automatically select the window under it.
+(defvar flymake-css-lint-command "csslint" "\
+Name (and optionally full path) of csslint executable.")
-\(fn)" t nil)
+(custom-autoload 'flymake-css-lint-command "flymake-css" t)
-(autoload 'turn-off-follow-mouse "follow-mouse" "\
-Moving the mouse will not automatically select the window under it.
+(autoload 'flymake-css-load "flymake-css" "\
+Configure flymake mode to check the current buffer's css syntax.
\(fn)" t nil)
-(autoload 'toggle-follow-mouse "follow-mouse" "\
-Toggle whether moving the mouse automatically selects the window under it.
-If the optional prefix ARG is specified, follow-mouse is enabled if it is
-positive, and disabled otherwise. If called interactively, or the optional
-VERBOSE argument is non-nil, display a confirmation message.
-
-\(fn &optional ARG VERBOSE)" t nil)
-
;;;***
\f
;;;### (autoloads (just-one-space-with-newline prelude-kill-other-buffers
;;;;;; force-backup-of-buffer clean-mode-line prelude-emacs-lisp-mode-defaults
;;;;;; prelude-remove-elc-on-save interactive-lisp-coding-defaults
;;;;;; lisp-coding-defaults prelude-sudo-edit jj-untabify-buffer
-;;;;;; move-line-down move-line-up revert-all-buffers org-mycal-export
-;;;;;; mycal-export-limit org-mycal-export-limit my-c-return epa-dired-mode-hook
-;;;;;; sacha/decrease-font-size sacha/increase-font-size sacha/search-word-forward
-;;;;;; sacha/search-word-backward sacha/isearch-yank-current-word
+;;;;;; move-line-down move-line-up revert-all-buffers my-c-return
+;;;;;; epa-dired-mode-hook sacha/decrease-font-size sacha/increase-font-size
+;;;;;; sacha/search-word-forward sacha/search-word-backward sacha/isearch-yank-current-word
;;;;;; ido-disable-line-trucation my-dired-init) "ganneff" "ganneff.el"
-;;;;;; (20866 32703 266707 225000))
+;;;;;; (20879 28061 273891 427000))
;;; Generated autoloads from ganneff.el
(autoload 'my-dired-init "ganneff" "\
(autoload 'my-c-return "ganneff" "\
When in minibuffer use `icicle-candidate-action', otherwise use `cua-set-rectangle-mark'.
-\(fn)" t nil)
-
-(autoload 'org-mycal-export-limit "ganneff" "\
-Limit the export to items that have a date, time and a range. Also exclude certain categories.
-
-\(fn)" nil nil)
-
-(autoload 'mycal-export-limit "ganneff" "\
-Limit the export to items that don't match an unwanted category
-
-\(fn)" nil nil)
-
-(autoload 'org-mycal-export "ganneff" "\
-
-
\(fn)" t nil)
(autoload 'revert-all-buffers "ganneff" "\
;;;***
\f
-;;;### (autoloads (bh/get-pom-from-agenda-restriction-or-point bh/set-agenda-restriction-lock
+;;;### (autoloads (org-mycal-export mycal-export-limit org-mycal-export-limit
+;;;;;; bh/save-then-publish bh/display-inline-images bh/view-next-project
+;;;;;; bh/get-pom-from-agenda-restriction-or-point bh/set-agenda-restriction-lock
;;;;;; bh/clock-in-last-task bh/clock-out-maybe bh/clock-in-organization-task-as-default
;;;;;; bh/clock-in-parent-task bh/clock-in-default-task bh/punch-out
;;;;;; bh/punch-in bh/find-project-task bh/clock-in-to-next bh/narrow-to-project
;;;;;; bh/org-agenda-to-appt bh/skip-non-subprojects bh/skip-projects-and-habits
;;;;;; bh/skip-project-tasks-maybe bh/skip-projects-and-habits-and-single-tasks
;;;;;; bh/skip-project-trees-and-habits bh/skip-non-projects bh/skip-non-stuck-projects
-;;;;;; bh/list-sublevels-for-projects bh/list-sublevels-for-projects-indented
+;;;;;; bh/skip-stuck-projects bh/list-sublevels-for-projects bh/list-sublevels-for-projects-indented
;;;;;; bh/is-subproject-p bh/is-task-p bh/is-project-subtree-p bh/is-project-p
;;;;;; org-my-archive-done-tasks bh/phone-call bh/prepare-meeting-notes
;;;;;; bh/remove-empty-drawer-on-clock-out bh/insert-heading-inactive-timestamp
;;;;;; bh/is-scheduled bh/is-deadline bh/is-pending-deadline bh/is-late-deadline
;;;;;; bh/is-due-deadline bh/is-not-scheduled-or-deadline bh/agenda-sort
;;;;;; bh/agenda-sort-test-num bh/agenda-sort-test bh/verify-refile-target
-;;;;;; bh/show-org-agenda) "ganneff-org" "ganneff-org.el" (20866
-;;;;;; 32672 234553 345000))
+;;;;;; bh/show-org-agenda) "ganneff-org" "ganneff-org.el" (20879
+;;;;;; 28085 514011 628000))
;;; Generated autoloads from ganneff-org.el
(autoload 'bh/show-org-agenda "ganneff-org" "\
\(fn)" nil nil)
+(autoload 'bh/skip-stuck-projects "ganneff-org" "\
+Skip trees that are not stuck projects
+
+\(fn)" nil nil)
+
(autoload 'bh/skip-non-stuck-projects "ganneff-org" "\
Skip trees that are not stuck projects
\(fn)" nil nil)
+(autoload 'bh/view-next-project "ganneff-org" "\
+
+
+\(fn)" t nil)
+
+(autoload 'bh/display-inline-images "ganneff-org" "\
+
+
+\(fn)" nil nil)
+
+(autoload 'bh/save-then-publish "ganneff-org" "\
+
+
+\(fn &optional FORCE)" t nil)
+
+(autoload 'org-mycal-export-limit "ganneff-org" "\
+Limit the export to items that have a date, time and a range. Also exclude certain categories.
+
+\(fn)" nil nil)
+
+(autoload 'mycal-export-limit "ganneff-org" "\
+Limit the export to items that don't match an unwanted category
+
+\(fn)" nil nil)
+
+(autoload 'org-mycal-export "ganneff-org" "\
+
+
+\(fn)" t nil)
+
;;;***
\f
;;;### (autoloads (gnus-alias-determine-identity gnus-alias-use-identity
;;;***
\f
+;;;### (autoloads (keyfreq-autosave-mode keyfreq-mode) "keyfreq"
+;;;;;; "keyfreq.el" (20870 14397 870087 510000))
+;;; Generated autoloads from keyfreq.el
+
+(defvar keyfreq-mode nil "\
+Non-nil if Keyfreq mode is enabled.
+See the command `keyfreq-mode' for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `keyfreq-mode'.")
+
+(custom-autoload 'keyfreq-mode "keyfreq" nil)
+
+(autoload 'keyfreq-mode "keyfreq" "\
+Keyfreq mode records number of times each command was
+called making it possible to access usage statistics through
+various keyfreq-* functions.
+
+\(fn &optional ARG)" t nil)
+
+(defvar keyfreq-autosave-mode nil "\
+Non-nil if Keyfreq-Autosave mode is enabled.
+See the command `keyfreq-autosave-mode' for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `keyfreq-autosave-mode'.")
+
+(custom-autoload 'keyfreq-autosave-mode "keyfreq" nil)
+
+(autoload 'keyfreq-autosave-mode "keyfreq" "\
+Keyfreq Autosave mode automatically saves
+`keyfreq-table' every `keyfreq-autosave-timeout' seconds
+and when emacs is killed.
+
+\(fn &optional ARG)" t nil)
+
+;;;***
+\f
;;;### (autoloads (mpd-libmpdee-submit-bug-report mpd-output-disable
;;;;;; mpd-output-enable mpd-update mpd-set-password mpd-set-crossfade
;;;;;; mpd-adjust-volume mpd-set-volume mpd-toggle-repeat mpd-toggle-random
;;;***
\f
+;;;### (autoloads (tidy-buffer tidy-save-settings tidy-parse-config-file
+;;;;;; tidy-build-menu) "tidy" "tidy.el" (20893 10149 0 0))
+;;; Generated autoloads from tidy.el
+
+(autoload 'tidy-build-menu "tidy" "\
+Set up the tidy menu in MAP. Used to set up a Tidy menu in your
+favourite mode.
+
+\(fn &optional MAP)" t nil)
+
+(autoload 'tidy-parse-config-file "tidy" "\
+If `tidy-config-file' is non-nil parse that file setting variables accordingly.
+
+\(fn)" t nil)
+
+(autoload 'tidy-save-settings "tidy" "\
+Query saving the current settings to your `tidy-config-file'.
+Perhaps put this on your `kill-buffer-hook'.
+
+\(fn &optional CONFIG-FILE)" t nil)
+
+(autoload 'tidy-buffer "tidy" "\
+Run the HTML Tidy program on the current buffer.
+If PREFIX is non-nil, or if called interactively with a prefix argument,
+then Tidy is applied to the currently selected region. Any error messages
+generated by that program are sent to \"*tidy-errors*\" buffer.
+
+\(fn &optional PREFIX)" t nil)
+
+;;;***
+\f
;;;### (autoloads (global-undo-tree-mode undo-tree-mode) "undo-tree"
;;;;;; "undo-tree.el" (20858 49922 501891 327000))
;;; Generated autoloads from undo-tree.el
;;;***
\f
;;;### (autoloads nil nil ("beamer.el" "bind-key.el" "buildd-gnus.el"
-;;;;;; "crypt++.el" "dash.el" "filladapt.el" "ganneff2.el" "ldap-mode.el"
+;;;;;; "crypt++.el" "dash.el" "filladapt.el" "flymake-easy.el" "ldap-mode.el"
;;;;;; "mingus-stays-home.el" "mingus.el" "moinmoin-mode.el" "nnir.el"
;;;;;; "nntodo.el" "randomsig.el" "region-bindings-mode.el" "s.el"
-;;;;;; "typing.el" "use-package.el" "volatile-highlights.el") (20866
-;;;;;; 32858 445377 86000))
+;;;;;; "typing.el" "use-package.el" "volatile-highlights.el") (20893
+;;;;;; 13603 30386 364000))
;;;***
\f
--- /dev/null
+;;; tidy.el --- Interface to the HTML Tidy program
+
+;; Copyright (C) 2001, 2002, 2003 by Free Software Foundation, Inc.
+
+;; Emacs Lisp Archive Entry
+;; Filename: tidy.el
+;; Author: Kahlil (Kal) HODGSON <dorge@tpg.com.au>
+;; X-URL: http://www.emacswiki.org/elisp/tidy.el
+;; Time-stamp: <2002-09-30 13:16:23 kahlil>
+;; Version: 20111222.1756
+;; X-Original-Version: 2.12
+;; Keywords: languages
+
+;; This file is NOT part of GNU Emacs.
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;;; Commentary:
+
+;; Provides a simple interface to the HTML Tidy program -- a free
+;; utility that can fix common errors in your mark-up and clean up
+;; sloppy editing automatically. See
+;;
+;; <http://tidy.sourceforge.net/>
+;;
+;; for more details. This package provides the following functions:
+;;
+;; `tidy-buffer',
+;; `tidy-parse-config-file',
+;; `tidy-save-settings', and
+;; `tidy-describe-options',
+;;
+;; These can be invoked interactively (using M-x) or via the menu-bar.
+;; The function `tidy-buffer' sends the current buffer to HTML Tidy,
+;; replacing the existing contents with a "tidied" version. If
+;; `tidy-buffer' is given a prefix argument, tidy operates on the
+;; current region, ignoring mark-up outside <BODY>...</BODY> tags
+;; (useful for writhing cgi scripts in Pearl). Warnings and errors
+;; are presented in a compilation buffer to facilitate tracking down
+;; necessary changes (e.g. C-x ` is bound to `next-error').
+;;
+;; This package also provides menu-bar support for setting Tidy's many
+;; options, and includes support for Tidy configuration files. The
+;; function `tidy-parse-config-file' will synchronise options
+;; displayed in the menu-bar with the settings in `tidy-config-file'.
+;; This is normally called by the load-hook for your HTML editing mode
+;; (see installation instructions below). The function
+;; `tidy-save-settings' will save the current option settings to your
+;; `tidy-config-file'. Finally `tidy-describe-options' allows you to
+;; browse the documentation strings associated with each option.
+
+;;;
+
+;;;; Installation:
+
+;; This package assumes you have and up-to-date HTML Tidy program
+;; installed on your system. See the URL above for instructions on
+;; how to do this. To set up this support package, first place the
+;; "tidy.el" file somewhere in your `load-path' and open it in Emacs.
+;; Byte-compile and load this package using the command
+;;
+;; M-x emacs-lisp-byte-compile-and-load <RET>
+;;
+;; Next customise the variables `tidy-config-file', `tidy-temp-dir'
+;; `tidy-shell-command', `tidy-menu-lock' and `tidy-menu-x-position'
+;;
+;; M-x customize-group <RET> tidy <RET>
+;;
+;; Now add the following autoloads to your ".emacs.el" file:
+;;
+;; (autoload 'tidy-buffer "tidy" "Run Tidy HTML parser on current buffer" t)
+;; (autoload 'tidy-parse-config-file "tidy" "Parse the `tidy-config-file'" t)
+;; (autoload 'tidy-save-settings "tidy" "Save settings to `tidy-config-file'" t)
+;; (autoload 'tidy-build-menu "tidy" "Install an options menu for HTML Tidy." t)
+;;
+;; If you use html-mode to edit HTML files then add something like
+;; this as well
+
+;; (defun my-html-mode-hook () "Customize my html-mode."
+;; (tidy-build-menu html-mode-map)
+;; (local-set-key [(control c) (control c)] 'tidy-buffer)
+;; (setq sgml-validate-command "tidy"))
+;;
+;; (add-hook 'html-mode-hook 'my-html-mode-hook)
+
+;; This will set up a "tidy" menu in the menu bar and bind the key
+;; sequence "C-c C-c" to `tidy-buffer' in html-mode (normally bound to
+;; `validate-buffer').
+;;
+;; For other modes (like html-helper-mode) simple change the variables
+;; `html-mode-hook' and `html-mode-map' to whatever is appropriate e.g.
+
+;; (defun my-html-mode-hook () "Customize my html-helper-mode."
+;; (tidy-build-menu html-helper-mode-map)
+;; (local-set-key [(control c) (control c)] 'tidy-buffer)
+;; (setq sgml-validate-command "tidy"))
+;;
+;; (add-hook 'html-helper-mode-hook 'my-html-mode-hook)
+
+;; Finally, restart Emacs and open an HTML file to test-drive the tidy
+;; package. For people new to HTML tidy check that the option "markup"
+;; under the "Input/Output" sub menu is set. You can read the
+;; documentation on this option via the menu item "Describe Options".
+;;
+;; Enjoy!
+
+;;;; New Features:
+;;
+;; 0. Now compatible with CVS version of Tidy as at 22 May 2003
+;; 1. Improved menu support to facillitate incorporting new options
+;; 2. Menu lock option makes menu stick when toggling options.
+;; 3. Now runs on XEmacs!!
+;; 4. Uses error file rather than std-error to retrieve errors (this
+;; fixes some odd pop up behaviour)
+;; 5. minor bug fix (empty config files)
+;; 6. handle buffer modified query in error buffer better
+;; 7. make it impossible to mark the error buffer as modified
+;; 8. Added the variable `tidy-temp-directory'.
+;; 9. Bugfix in tidy-buffer: call find-file-noselect with NOWARN
+
+;;;; ToDo:
+;;
+;; 1. Automatically set "char-encoding" according to the buffer encoding
+;; 2. Should check value of HTML_TIDY environment variable.
+
+
+;;;; Bugs:
+
+;; Requires a version of HTML Tidy that understands the "-f"
+;; "-config" "--show-body-only" command line options e.g. source-forge
+;; pre-release.
+;;
+;; There may be a bug with setting doctypes. I don't use this feature
+;; yet and, well, don't really know how its supposed to work:-)
+;;
+;; Care with character encodings!!
+
+;;;; Credits
+
+;; This code was inspired by an Emacs "tip" suggested by Pete Gelbman.
+;;
+;; Thanks to Hans-Michael Stahl for comments regarding XEmacs
+;; compatibility.
+;;
+;; Thanks to Thomas Baumann for bugfix's in `tidy-parse-config-file'
+;; and `tidy-buffer'.
+;;
+;; Thanks to Chris Lott for comments regarding installation and menu
+;; display
+;;
+;; Thanks to Jeroen Baekelandt for noting a problem with ange-ftp and
+;; inspiring `tidy-temp-directory'.
+
+;;;; Code:
+
+;;;;; Forward references (stuff which must come first)
+
+(require 'easymenu) ;; This makes menus so much easier!
+(require 'compile) ;; To make the error buffer more sexy
+
+;; The following two are functions so that the same compiled code will
+;; work in both situations (time cost is negligible)
+
+(defsubst tidy-xemacs-p ()
+ "Return t iff we are running XEmacs this session."
+ (not (null (string-match "^XEmacs.*" (emacs-version)))))
+
+(defsubst tidy-windows-p ()
+ "Return t iff we are running on a Windows system."
+ (memq system-type '(emx win32 w32 mswindows ms-dos windows-nt)))
+
+;; function definitions
+
+;; XEmacs
+(defalias 'tidy-x-event-function 'event-function)
+(defalias 'tidy-x-event-object 'event-object)
+(defalias 'tidy-x-find-menu-item 'find-menu-item)
+(defalias 'tidy-x-get-popup-menu-response 'get-popup-menu-response)
+(defalias 'tidy-x-make-event 'make-event)
+(defalias 'tidy-x-misc-user-event-p 'misc-user-event-p)
+
+;;;;; User Variables
+
+(defgroup tidy nil
+"*Provides a simple interface to the HTML Tidy program -- a free
+utility that can fix common errors in your mark-up and clean up
+sloppy editing automatically. See
+
+ <http://tidy.sourceforge.net/>
+
+for more details. This package provides the following functions:
+
+ `tidy-buffer',
+ `tidy-parse-config-file',
+ `tidy-save-settings', and
+ `tidy-describe-options',
+
+These can be invoked interactively (using M-x) or via the menu-bar.
+The function `tidy-buffer' sends the current buffer to HTML Tidy,
+replacing the existing contents with a \"tidied\" version. If
+`tidy-buffer' is given a prefix argument, tidy operates on the
+current region, ignoring mark-up outside <BODY>...</BODY> tags
+\(useful for writhing cgi scripts in Pearl). Warnings and errors
+are presented in a compilation buffer to facilitate tracking down
+necessary changes (e.g. C-x ` is bound to `next-error').
+
+This package also provides menu-bar support for setting Tidy's many
+options, and includes support for Tidy configuration files. The
+function `tidy-parse-config-file' will synchronise options
+displayed in the menu-bar with the settings in `tidy-config-file'.
+This is normally called by the load-hook for your HTML editing mode
+\(see installation instructions below). The function
+`tidy-save-settings' will save the current option settings to your
+`tidy-config-file'. Finally `tidy-describe-options' allows you to
+browse the documentation strings associated with each option.
+")
+
+
+(defcustom tidy-config-file "~/.tidyrc"
+ "*Path to your default tidy configuration file.
+
+This is used by `tidy-parse-config-file' to synchronise Tidy's behaviour
+inside Emacs with its behaviour outside, and by `tidy-save-settings' to
+set your configuration file from within Emacs. If you never want this to
+happen, set `tidy-config-file' to nil."
+ :group 'tidy
+ :type 'string)
+
+(defcustom tidy-shell-command "/usr/bin/tidy"
+ "*Full path to command to call HTML tidy from a shell."
+ :group 'tidy
+ :type 'string)
+
+(defcustom tidy-temp-directory "."
+ "Directory where tidy places its temp files. The default is the
+current directory which works fine unless you are operating on remote
+files via `ange-ftp' and its ilk, in which case it will try to place
+the temp files on the remote server (and will probably fail). If this
+is the case try setting this variable to something like \"/tmp/\" or
+\"/var/tmp/\"."
+ :group 'tidy
+ :type 'string)
+
+(defcustom tidy-menu-lock t
+ " *Non-nil means menu is locked (i.e. doesn't pop down) when
+selecting toggle and radio options.
+
+See also `tidy-menu-x-position'."
+ :type 'boolean
+ :group 'tidy)
+
+(defcustom tidy-menu-x-position 211
+ "*Specify menu position height in pixels.
+
+This variable is used to set the horizontal position of the locked
+menu, so don't forget to adjust it if menu position is not ok.
+
+See also `tidy-menu-lock'."
+ :type 'integer
+ :group 'tidy)
+
+;;;;; Local Variables
+
+(defvar tidy-debug nil
+ "If t then we rebuild everything on reload. Useful for debugging.")
+
+;;(eval-when-compile (setq tidy-debug t))
+
+(defun tidy-toggle-debug () "Toggle value of tidy-debug."
+ (interactive)
+ (message "tidy-debug is %s" (setq tidy-debug (not tidy-debug))))
+
+(defvar tidy-options-alist nil
+ "An alist containing all valid tidy options.
+Each element is a list of the form
+ (NAME, SUB-MENU, VALUE-TYPE, DEFAULT-VALUE, DOC-STRING).
+This is used to automatically construct variables and a menu bar.
+To add new or modify exiting options simply modify this list.")
+
+(when (or (null tidy-options-alist) tidy-debug)
+ (setq tidy-options-alist
+ '(
+ ("add-xml-decl" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should add the XML declaration when
+outputting XML or XHTML. Note that if the input already includes an <?xml
+... ?> declaration then this option will be ignored.")
+
+ ("add-xml-pi" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option is the same as the add-xml-decl option.")
+
+ ("add-xml-space" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should add xml:space=\"preserve\" to elements
+such as <PRE>, <STYLE> and <SCRIPT> when generating XML. This is needed if
+the whitespace in such elements is to be parsed appropriately without
+having access to the DTD.")
+
+ ("alt-text" "Fix Markup" "String" ""
+ "
+Type: String
+Default: -none-
+
+This option specifies the default \"alt=\" text Tidy uses for <IMG>
+attributes. This feature is dangerous as it suppresses further
+accessibility warnings. You are responsible for making your documents
+accessible to people who can not see the images!")
+
+ ("ascii-chars" "Fix Markup" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+Can be used to modify behavior of -c (--clean yes) option.
+Defaults to \"yes\" when using -c. Set to \"no\" to prevent
+converting &emdash;, ”, and other named character entities
+to their ascii equivalents.")
+
+ ("assume-xml-procins" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should change the parsing of processing
+instructions to require ?> as the terminator rather than >. This option is
+automatically set if the input is in XML.")
+
+ ("bare" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should strip Microsoft specific HTML from
+Word 2000 documents, and output spaces rather than non-breaking spaces
+where they exist in the input.")
+
+ ("break-before-br" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should output a line break before each <BR>
+element.")
+
+ ("char-encoding" "Encoding" "Encoding" "ascii"
+ "
+Type: Encoding
+Default: ascii
+Example: ascii, latin1, raw, utf8, iso2022, mac, win1252
+
+This option specifies the character encoding Tidy uses for both the input
+and output. Possible values are: ascii, latin1, raw, utf8, iso2022, mac,
+win1252. For ascii, Tidy will accept Latin-1 (ISO-8859-1) character
+values, but will use entities for all characters whose value > 127. For
+raw, Tidy will output values above 127 without translating them into
+entities. For latin1, characters above 255 will be written as
+entities. For utf8, Tidy assumes that both input and output is encoded as
+UTF-8. You can use iso2022 for files encoded using the ISO-2022 family of
+encodings e.g. ISO-2022-JP. For mac and win1252, Tidy will accept vendor
+specific character values, but will use entities for all characters whose
+value > 127.")
+
+ ("clean" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should strip out surplus presentational tags
+and attributes replacing them by style rules and structural markup as
+appropriate. It works well on the HTML saved by Microsoft Office products.")
+
+ ("doctype" "Fix Markup" "DocType" "auto"
+ "
+Type: DocType
+Default: auto
+Example: auto, omit, strict, loose, transitional, user specified fpi \(string\)
+
+This option specifies the DOCTYPE declaration generated by Tidy. If set to
+\"omit\" the output won't contain a DOCTYPE declaration. If set to \"auto\"
+\(the default\) Tidy will use an educated guess based upon the contents of
+the document. If set to \"strict\", Tidy will set the DOCTYPE to the strict
+DTD. If set to \"loose\", the DOCTYPE is set to the loose \(transitional\)
+DTD. Alternatively, you can supply a string for the formal public
+identifier \(FPI\). For example:
+
+ doctype: \"-//ACME//DTD HTML 3.14159//EN\"
+
+If you specify the FPI for an XHTML document, Tidy will set
+the system identifier to the empty string. Tidy leaves the DOCTYPE for
+generic XML documents unchanged.")
+
+ ("drop-empty-paras" "Fix Markup" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should discard empty paragraphs. If set to
+no, empty paragraphs are replaced by a pair of <BR> elements as HTML4
+precludes empty paragraphs.")
+
+ ("drop-font-tags" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should discard <FONT> and <CENTER> tags
+rather than creating the corresponding style rules, but only if the clean
+option is also set to yes.")
+
+ ("drop-proprietary-attributes" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should strip out proprietary attributes,
+such as MS data binding attributes.")
+
+ ("enclose-block-text" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should insert a <P> element to enclose any
+text it finds in any element that allows mixed content for HTML
+transitional but not HTML strict.")
+
+ ("enclose-text" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should enclose any text it finds in the body
+element within a <P> element. This is useful when you want to take
+existing HTML and use it with a style sheet.")
+
+ ("error-file" "Omit" "String" "-none-"
+ "
+Type: String
+Default: -none-
+
+This option specifies the error file Tidy uses for errors and
+warnings. Normally errors and warnings are output to \"stderr\".
+
+This is option is ignored in Emacs.")
+
+ ("escape-cdata" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should convert <![CDATA[]]> sections to
+normal text.")
+
+ ("fix-backslash" "Fix Markup" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should replace backslash characters \"\\\" in
+URLs by forward slashes \"/\".")
+
+ ("fix-bad-comments" "Fix Markup" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should replace unexpected hyphens with \"=\"
+characters when it comes across adjacent hyphens. The default is yes. This
+option is provided for users of Cold Fusion which uses the comment syntax:
+<!--- --->")
+
+ ("fix-uri" "Fix Markup" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should check attribute values that carry
+URIsfor illegal characters and if such are found, escape them as HTML 4
+recommends.")
+
+ ("force-output" "Input/Output" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should produce output even if errors are
+encountered. Use this option with care - if Tidy reports an error,
+this means Tidy was not able to, or is not sure how to, fix the error,
+so the resulting output may not reflect your intention.")
+
+ ("gnu-emacs" "Omit" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should change the format for reporting
+errors and warnings to a format that is more easily parsed by GNU
+Emacs.
+
+This option is automatically set in Emacs." )
+
+ ("hide-comments" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should print out comments.")
+
+ ("hide-endtags" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should omit optional end-tags when
+generating the pretty printed markup. This option is ignored if you are
+outputting to XML.")
+
+ ("indent" "Indentation" "AutoBool" "no"
+ "
+Type: AutoBool
+Default: no
+Example: auto, y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should indent block-level tags. If set to
+\"auto\", this option causes Tidy to decide whether or not to indent the
+content of tags such as TITLE, H1-H6, LI, TD, TD, or P depending on whether
+or not the content includes a block-level element. You are advised to avoid
+setting indent to yes as this can expose layout bugs in some browsers.")
+
+ ("indent-attributes" "Indentation" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should begin each attribute on a new line.")
+
+ ("indent-cdata" "Indent" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should indent <![CDATA[]]> sections.")
+
+ ("indent-spaces" "Indentation" "Integer" "2"
+ "
+Type: Integer
+Default: 2
+Example: 0, 1, 2, ...
+
+This option specifies the number of spaces Tidy uses to indent content,
+when indentation is enabled.")
+
+ ("input-encoding" "Encoding" "Encoding" "latin1"
+ "
+Type: Encoding
+Default: ascii
+Example: ascii, latin1, raw, utf8, iso2022, mac, win1252
+
+This option specifies the character encoding Tidy uses for the input. See
+char-encoding for more info.")
+
+ ("input-xml" "Input/Output" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should use the XML parser rather than the
+error correcting HTML parser.")
+
+ ("join-classes" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should combine class names to generate a
+single new class name, if multiple class assignments are detected on an
+element.")
+
+ ("join-styles" "Fix Markup" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should combine styles to generate a single
+new style, if multiple style values are detected on an element.")
+
+ ("keep-time" "Preference" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should alter the last modified time for
+files it writes back to. The default is no, which allows you to tidy files
+without affecting which ones will be uploaded to a Web server when using a
+tool such as 'SiteCopy'. Note that this feature may not work on some
+platforms.")
+
+ ("literal-attributes" "Preference" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should ensure that whitespace characters
+within attribute values are passed through unchanged.")
+
+ ("logical-emphasis" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should replace any occurrence of <I> by <EM>
+and any occurrence of <B> by <STRONG>. In both cases, the attributes are
+preserved unchanged. This option can be set independently of the clean and
+drop-font-tags options.")
+
+ ("lower-literals" "Preference" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should convert the value of an attribute
+that takes a list of predefined values to lower case. This is required for
+XHTML documents.")
+
+ ("markup" "Input/Output" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should generate a pretty printed version of
+the markup. Note that Tidy won't generate a pretty printed version if it
+finds significant errors (see force-output).")
+
+ ("ncr" "Preference" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should allow numeric character references.")
+
+ ("new-blocklevel-tags" "Tags" "Tag names" ""
+ "
+Type: Tag names
+Default: -none-
+Example: tagX, tagY, ...
+
+This option specifies new block-level tags. This option takes a space or
+comma separated list of tag names. Unless you declare new tags, Tidy will
+refuse to generate a tidied file if the input includes previously unknown
+tags. Note you can't change the content model for elements such as
+<TABLE>, <UL>, <OL> and <DL>.")
+
+ ("new-empty-tags" "Tags" "Tag names" ""
+ "
+Type: Tag names
+Default: -none-
+Example: tagX, tagY, ...
+
+This option specifies new empty inline tags. This option takes a space or
+comma separated list of tag names. Unless you declare new tags, Tidy will
+refuse to generate a tidied file if the input includes previously unknown
+tags. Remember to also declare empty tags as either inline or blocklevel.")
+
+ ("new-inline-tags" "Tags" "Tag names" ""
+ "
+Type: Tag names
+Default: -none-
+Example: tagX, tagY, ...
+
+This option specifies new non-empty inline tags. This option takes a space
+or comma separated list of tag names. Unless you declare new tags, Tidy
+will refuse to generate a tidied file if the input includes previously
+unknown tags.")
+
+ ("new-pre-tags" "Tags" "Tag names" ""
+ "
+Type: Tag names
+Default: -none-
+Example: tagX, tagY, ...
+
+This option specifies new tags that are to be processed in exactly the
+same way as HTML's <PRE> element. This option takes a space or comma
+separated list of tag names. Unless you declare new tags, Tidy will refuse
+to generate a tidied file if the input includes previously unknown
+tags. Note you can not as yet add new CDATA elements (similar to
+<SCRIPT>).")
+
+ ("numeric-entities" "Preference" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should output entities other than the
+built-in HTML entities \(&, <, > and "\) in the numeric
+rather than the named entity form.")
+
+ ("output-bom" "Encoding" "AutoBool" "auto"
+ "
+Type: AutoBool
+Default: auto
+Example: auto, y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should write a Unicode Byte Order Mark
+character (BOM; also known as Zero Width No-Break Space; has value of
+U+FEFF) to the beginning of the output; only for UTF-8 and UTF-16 output
+encodings. If set to \"auto\", this option causes Tidy to write a BOM to the
+output only if a BOM was present at the beginning of the input. A BOM is
+always written for XML/XHTML output using UTF-16 output encodings.")
+
+ ("output-encoding" "Encoding" "Encoding" "ascii"
+ "
+Type: Encoding
+Default: ascii
+Example: ascii, latin1, raw, utf8, iso2022, mac, win1252
+
+This option specifies the character encoding Tidy uses for the output. See
+char-encoding for more info. May only be different from input-encoding for
+Latin encodings (ascii, latin1, mac, win1252).")
+
+ ("output-xhtml" "Input/Output" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should generate pretty printed output,
+writing it as extensible HTML. This option causes Tidy to set the DOCTYPE
+and default namespace as appropriate to XHTML. If a DOCTYPE or namespace
+is given they will checked for consistency with the content of the
+document. In the case of an inconsistency, the corrected values will
+appear in the output. For XHTML, entities can be written as named or
+numeric entities according to the setting of the \"numeric-entities\"
+option. The original case of tags and attributes will be preserved,
+regardless of other options.")
+
+ ("output-xml" "Input/Output" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should pretty print output, writing it as
+well-formed XML. Any entities not defined in XML 1.0 will be written as
+numeric entities to allow them to be parsed by a XML parser. The original
+case of tags and attributes will be preserved, regardless of other
+options.")
+
+ ("quiet" "Input/Output" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should output the summary of the numbers of
+errors and warnings, or the welcome or informational messages.")
+
+ ("quote-ampersand" "Preference" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should output unadorned & characters as
+&.")
+
+ ("quote-marks" "Preference" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should output \" characters as " as is
+preferred by some editing environments. The apostrophe character \' is
+written out as ' since many web browsers don't yet support '.")
+
+ ("quote-nbsp" "Preference" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should output non-breaking space characters
+as entities, rather than as the Unicode character value 160 (decimal).")
+
+ ("raw" "Omit" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0 char-encoding
+
+Currently not used, but this option would be the same as the
+char-encoding: raw option.")
+
+ ("repeated-attributes" "Fix Markup" ("keep-first" "keep-last") "keep-last"
+ "
+Type: -
+Default: keep-last
+Example: keep-first, keep-last
+
+This option specifies if Tidy should keep the first or last attribute, if
+an attribute is repeated, e.g. has two align attributes.")
+
+
+ ("replace-color" "Fix Markup" "Boolean"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should replace numeric values in color
+attributes by HTML/XHTML color names where defined, e.g. replace
+\"#ffffff\" with \"white\"." )
+
+ ("slide-style" "Omit" "String"
+ "
+Type: Name
+Default: -none-
+split Currently not used.")
+
+ ("show-body-only" "Omit" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should print only the contents of the body
+tag as an HTML fragment. Useful for incorporating existing whole pages as
+a portion of another page.
+
+Emacs overrides this option.")
+
+ ("show-errors" "Input/Output" "Integer" "6"
+ "
+Type: Integer
+Default: 6
+Example: 0, 1, 2, ...
+
+This option specifies the number Tidy uses to determine if further errors
+should be shown. If set to 0, then no errors are shown.")
+
+ ("show-warnings" "Input/Output" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should suppress warnings. This can be useful
+when a few errors are hidden in a flurry of warnings.")
+
+ ("slide-style" "Omit" "String" ""
+ "
+Type: Name
+Default: -none-
+
+Currently not used.")
+
+ ("split" "Omit" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should create a sequence of slides from
+the input, splitting the markup prior to each successive <H2>. The
+slides are written to \"slide001.html\", \"slide002.html\" etc.
+
+There is currently no Emacs support for this option.")
+
+ ("tab-size" "Indentation" "Integer" "4"
+ "
+Type: Integer
+Default: 4
+Example: 0, 1, 2, ...
+
+This option specifies the number of columns that Tidy uses between
+successive tab stops. It is used to map tabs to spaces when reading the
+input. Tidy never outputs tabs.")
+
+ ("tidy-mark" "Preference" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should add a meta element to the document
+head to indicate that the document has been tidied. Tidy won't add a meta
+element if one is already present.")
+
+ ("uppercase-attributes" "Preference" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should output attribute names in upper
+case. The default is no, which results in lower case attribute names,
+except for XML input, where the original case is preserved.")
+
+ ("uppercase-tags" "Preference" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should output tag names in upper case. The
+default is no, which results in lower case tag names, except for XML
+input, where the original case is preserved.")
+
+ ("word-2000" "Fix Markup" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should go to great pains to strip out all
+the surplus stuff Microsoft Word 2000 inserts when you save Word documents
+as \"Web pages\". Doesn't handle embedded images or VML.")
+
+ ("wrap" "Line Wrapping" "Integer" "68"
+ "
+Type: Integer
+Default: 68
+Example: 0, 1, 2, ...
+
+This option specifies the right margin Tidy uses for line wrapping. Tidy
+tries to wrap lines so that they do not exceed this length. Set wrap to
+zero if you want to disable line wrapping.")
+
+ ("wrap-asp" "Line Wrapping" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should line wrap text contained within ASP
+pseudo elements, which look like: <% ... %>.")
+
+ ("wrap-attributes" "Line Wrapping" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should line wrap attribute values, for
+easier editing. This option can be set independently of
+wrap-script-literals.")
+
+ ("wrap-jste" "Line Wrapping" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should line wrap text contained within JSTE
+pseudo elements, which look like: <# ... #>.")
+
+ ("wrap-php" "Line Wrapping" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should line wrap text contained within PHP
+pseudo elements, which look like: <?php ... ?>.")
+
+ ("wrap-script-literals" "Line Wrapping" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should line wrap string literals that appear
+in script attributes. Tidy wraps long script string literals by inserting
+a backslash character before the line break.")
+
+ ("wrap-sections" "Line Wrapping" "Boolean" "yes"
+ "
+Type: Boolean
+Default: yes
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should line wrap text contained within
+<![... ]> section tags.")
+
+ ("write-back" "Omit" "Boolean" "no"
+ "
+Type: Boolean
+Default: no
+Example: y/n, yes/no, t/f, true/false, 1/0
+
+This option specifies if Tidy should write back the tidied markup to
+the same file it read from. You are advised to keep copies of
+important files before tidying them, as on rare occasions the result
+may not be what you expect.
+
+This option is ignored by Emacs.")
+ ))
+ )
+
+;;;;; Create a variable for each option in `tidy-options-alist'"
+
+;; these variables are made buffer local so that different buffers can
+;; use a different set of options
+
+(let ((options-alist tidy-options-alist)
+ option name symbol docstring)
+
+ (while (setq option (car options-alist))
+ (setq name (nth 0 option)
+ docstring (nth 4 option)
+ symbol (intern (concat "tidy-" name)))
+ ;; create the variable on the fly
+ (put symbol 'variable-documentation docstring)
+ (make-variable-buffer-local symbol)
+ (set symbol nil) ;;default)
+ (setq options-alist (cdr options-alist))
+ )
+ )
+
+;;;;; Menu Lock (adapted from printing.el)
+
+;; quite compiler
+(eval-when-compile
+ (progn
+ (or (boundp 'current-menubar)
+ (defvar current-menubar nil))
+ (or (fboundp 'tidy-menu-position)
+ (defun tidy-menu-position () ""))
+ (or (fboundp 'tidy-menu-lock)
+ (defun tidy-menu-lock (entry state path) ""))
+ (or (fboundp 'tidy-menu-lookup)
+ (defun tidy-menu-lookup (path) ""))
+ ))
+
+;; always define these
+(defvar tidy-menu-position nil)
+(defvar tidy-menu-state nil)
+
+(cond
+ ((tidy-xemacs-p)
+ ;; XEmacs
+ (defun tidy-menu-position ()
+ (tidy-x-make-event
+ 'button-release
+ (list 'button 1
+ 'x tidy-menu-x-position
+ 'y -5
+ )))
+
+ ;; XEmacs
+ (defun tidy-menu-lock (entry state path)
+ (when (and (not (interactive-p)) tidy-menu-lock)
+ (or (and tidy-menu-position (eq state tidy-menu-state))
+ (setq tidy-menu-position (tidy-menu-position)
+ tidy-menu-state state))
+ (let* ((menu (tidy-menu-lookup path))
+ (result (tidy-x-get-popup-menu-response menu tidy-menu-position)))
+ (and (tidy-x-misc-user-event-p result)
+ (funcall (tidy-x-event-function result)
+ (tidy-x-event-object result))))
+ (setq tidy-menu-position nil)))
+
+ ;; XEmacs
+ (defun tidy-menu-lookup (path)
+ (car (tidy-x-find-menu-item current-menubar (cons "Tidy" path)))))
+
+ (t
+ ;; GNU Emacs
+ (defun tidy-menu-position ()
+ (let ()
+ (list (list tidy-menu-x-position '-5)
+ (selected-frame)))) ; frame
+
+ ;; GNU Emacs
+ (defun tidy-menu-lock (entry state path)
+ (when (and (not (interactive-p)) tidy-menu-lock)
+ (or (and tidy-menu-position (eq state tidy-menu-state))
+ (setq tidy-menu-position (tidy-menu-position )
+ tidy-menu-state state))
+ (let* ((menu (tidy-menu-lookup path))
+ (result (x-popup-menu tidy-menu-position menu)))
+ (and result
+ (let ((command (lookup-key menu (vconcat result))))
+ (if (fboundp command)
+ (funcall command)
+ (eval command)))))
+ (setq tidy-menu-position nil)))
+
+ ;; GNU Emacs
+ (defun tidy-menu-lookup (dummy)
+ (lookup-key (current-local-map) [menu-bar Tidy])))
+ )
+
+;;;;; Define classes of menu items
+
+(defun tidy-set (var-sym value mess entry state &optional path)
+ "Set the value of the symbol VAR-SYM to VALUE giving a message
+derived from VALUE and MESS. Pass on menu data to `tidy-menu-lock'."
+ (set var-sym value)
+ (message "%s is %s" mess value)
+ (tidy-menu-lock entry state path))
+
+(defun tidy-boolean-entry (symbol name type default menu)
+ "Returns a menu entry that allows us to toggle the value of SYMBOL.
+SYMBOL refers to the option called NAME which has default value
+DEFAULT. TYPE should always have the value \"Boolean\". MENU refers
+to the sub-menu that this item belongs to and POSITION its position in
+that list."
+ (cond ((equal default "no")
+ (list (vector name
+ (list 'tidy-set (list 'quote symbol)
+ (list 'if symbol 'nil "yes")
+ name
+ (list 'quote menu)
+ '(quote toggle)
+ )
+ :style 'toggle
+ :selected (list 'if symbol 't 'nil))))
+
+ ((equal default "yes")
+ (list (vector name (list 'tidy-set (list 'quote symbol)
+ (list 'if symbol 'nil "no")
+ name
+ (list 'quote menu)
+ '(quote toggle)
+ )
+ :style 'toggle
+ :selected (list 'if symbol 'nil 't))))))
+
+(defun tidy-list-entry (symbol name type default menu)
+"Returns a menu entry that allows us to set via a radio button the
+value of SYMBOL. SYMBOL refers to the option called NAME which has
+default value DEFAULT. TYPE should be a list of the possible
+values. MENU refers to the sub-menu that this item belongs to and
+POSITION its position in that list."
+ (let (value element)
+ (while (setq value (car type))
+ (if (equal value default)
+ (setq element
+ (append element
+ (list
+ (vector
+ (concat name " is \"" value "\"")
+ (list 'tidy-set (list 'quote symbol)
+ (list 'if symbol 'nil value)
+ name
+ (list 'quote menu)
+ '(quote toggle)
+ )
+ :style 'radio
+ :selected (list 'if symbol 'nil 't)
+ ))))
+ (setq element
+ (append element
+ (list
+ (vector
+ (concat name " is \"" value "\"")
+
+ (list 'tidy-set (list 'quote symbol)
+ (list 'if symbol 'nil value)
+ name
+ (list 'quote menu)
+ '(quote toggle)
+ )
+
+ :style 'radio
+ :selected (list
+ 'if (list 'string-equal symbol value)
+ 't 'nil)
+ )))))
+ (setq type (cdr type)))
+ element))
+
+(defun tidy-set-string (symbol name default)
+ "Set the value of SYMBOL identified by name to VALUE,
+unless VALUE equals DEFAULT, in which case we set it to nil."
+ (interactive)
+ (let* ((last-value (symbol-value symbol))
+ (new-value
+ (if (tidy-xemacs-p)
+ (read-string (format "Set %s to: " name)
+ (or last-value default) nil) ;; no default arg
+ (read-string (format "Set %s to: " name)
+ (or last-value default) nil default))))
+ (set symbol (if (equal new-value default) nil new-value))))
+
+(defun tidy-set-integer (symbol name default)
+ "Set the value of SYMBOL identified by name to VALUE,
+unless VALUE = DEFAULT, in which case we set it to nil."
+ (interactive)
+ (let* ((last-value (symbol-value symbol))
+ ;; careful to interpret the string as a number
+ (new-value
+ (string-to-number
+ (if (tidy-xemacs-p)
+ (read-string (format "Set %s to: " name)
+ (or last-value default) nil)
+ (read-string (format "Set %s to: " name)
+ (or last-value default) nil default)
+ ))))
+ (set symbol (if (= new-value (string-to-number default)) nil
+ (number-to-string new-value)))))
+
+
+(defun tidy-string-entry (symbol name type default menu)
+ "Returns a menu entry that allows us to set the value of SYMBOL.
+SYMBOL refers to the option called NAME which has default value
+DEFAULT. TYPE should always be one of \"String\" \"Tags\", or
+\"DocType\". MENU and POSITION are not used in this case."
+
+ (list (vector (concat "set " name)
+ (list 'tidy-set-string
+ (list 'quote symbol)
+ name default))))
+
+(defun tidy-integer-entry (symbol name type default menu)
+"Returns a menu entry that allows us to set the value of SYMBOL.
+SYMBOL refers to the option called NAME which has default value
+DEFAULT. TYPE should always have the value \"Integer\". MENU and
+POSITION are not used in this case. "
+ (list (vector (concat "set " name)
+ (list 'tidy-set-integer
+ (list 'quote symbol)
+ name default))))
+
+(defvar tidy-top-menu nil
+ "The first part of teh menu.")
+(when (or (null tidy-top-menu) tidy-debug)
+ (setq tidy-top-menu
+ '("Tidy"
+ ["Tidy buffer" tidy-buffer
+ :active (and tidy-shell-command ;; check that tidy can be executed
+ (file-executable-p (car (split-string tidy-shell-command))))]
+
+ ["Tidy region" (tidy-buffer 1)
+ :active (and tidy-shell-command ;; check that tidy can be executed
+ (file-executable-p (car (split-string tidy-shell-command))))
+ :keys "C-u \\[tidy-buffer]"]
+
+ "----------------------------------------------"
+
+ ["Parse config file" tidy-parse-config-file
+ :active (and tidy-config-file (file-exists-p tidy-config-file))]
+
+ ["Save settings" tidy-save-settings
+ :active (and tidy-config-file (file-exists-p tidy-config-file))]
+
+ "----------------------------------------------"
+
+ ["Menu Lock" (tidy-set 'tidy-menu-lock
+ (if tidy-menu-lock nil t)
+ "Menu Lock"
+ 'top
+ 'toggle)
+ :style toggle
+ :selected (if tidy-menu-lock t nil)
+ ]
+ )))
+
+(defvar tidy-doctype-menu nil "The second to last sub-menu.")
+(when (or (null tidy-doctype-menu) tidy-debug)
+ (setq tidy-doctype-menu
+ '("Set doctype" ;; ==>
+
+ ["auto" (tidy-set 'tidy-doctype
+ nil
+ "doctype"
+ 'doctype
+ 'toggle)
+ :style radio
+ :selected (if (null tidy-doctype) t nil)]
+
+ ["omit" (tidy-set 'tidy-doctype
+ "omit"
+ "doctype"
+ 'doctype
+ 'toggle)
+ :style radio
+ :selected (if (equal tidy-doctype "omit") t nil)]
+
+ ["strict" (tidy-set 'tidy-doctype
+ "strict"
+ "doctype"
+ 'doctype
+ 'toggle)
+ :style radio
+ :selected (if (equal tidy-doctype "strict") t nil)]
+
+ ["loose" (tidy-set 'tidy-doctype
+ "loose"
+ "doctype"
+ 'doctype
+ 'toggle)
+ :style radio
+ :selected (if (equal tidy-doctype "loose") t nil)]
+
+ ["transitional" (tidy-set 'tidy-doctype
+ "transitional"
+ "doctype"
+ 'doctype
+ 'toggle)
+ :style radio
+ :selected (if (equal tidy-doctype "transitional") t nil)]
+
+ ["fpi" (null nil) ;; stub function
+ :style radio
+ :selected (if (or (null tidy-doctype)
+ (equal tidy-doctype "omit")
+ (equal tidy-doctype "strict")
+ (equal tidy-doctype "loose"))
+ nil t) ]
+
+ ["reset fpi" (tidy-set-string 'tidy-doctype "doctype" "" "")]
+ )))
+
+(defvar tidy-char-encoding-menu nil "The last sub-menu.")
+(when (or (null tidy-char-encoding-menu) tidy-debug)
+ (setq tidy-char-encoding-menu
+ '("Set char-encoding" ;; ==>
+ ["ascii" (tidy-set 'tidy-char-encoding
+ nil
+ "char-encoding"
+ 'encoding
+ 'toggle)
+ :style radio
+ :selected (if (null tidy-char-encoding) t nil) ;; default
+ ]
+
+ ["raw" (tidy-set 'tidy-char-encoding
+ "raw"
+ "char-encoding"
+ 'encoding
+ 'toggle)
+ :style radio
+ :selected (if (equal tidy-char-encoding "raw") t nil)]
+
+ ["latin1" (tidy-set 'tidy-char-encoding
+ "latin1"
+ "char-encoding"
+ 'encoding
+ 'toggle)
+ :style radio
+ :selected (if (equal tidy-char-encoding "latin1") t nil)]
+
+ ["utf8" (tidy-set 'tidy-char-encoding
+ "utf8"
+ "char-encoding"
+ 'encoding
+ 'toggle)
+ :style radio
+ :selected (if (equal tidy-char-encoding "utf8") t nil)]
+
+ ["iso2022" (tidy-set 'tidy-char-encoding
+ "iso2022"
+ "char-encoding"
+ 'encoding
+ 'toggle)
+ :style radio
+ :selected (if (equal tidy-char-encoding "iso2022") t nil)]
+
+ ["mac" (tidy-set 'tidy-char-encoding
+ "mac"
+ "char-encoding"
+ 'encoding
+ 'toggle)
+ :style radio
+ :selected (if (equal tidy-char-encoding "mac") t nil)]
+
+ ["win1252" (tidy-set 'tidy-char-encoding
+ "win1252"
+ "char-encoding"
+ 'encoding
+ 'toggle)
+ :style radio
+ :selected (if (equal tidy-char-encoding "win1252") t nil)]
+
+ )))
+
+;;;;; Create a menu item for each option that has a valid sub-menu
+;; field
+
+(defvar tidy-menu nil "Menu used by tidy.")
+(when (or (null tidy-menu) tidy-debug)
+ (let ((options-alist tidy-options-alist)
+
+ ;; sub menus are divided into two parts with list type options
+ ;; coming first, followed by the rest
+
+ markup-menu-bool markup-menu-set
+ line-wrap-menu-bool line-wrap-menu-set
+ preference-menu-bool preference-menu-set
+ indent-menu-bool indent-menu-set
+ io-menu-bool io-menu-set
+ tags-menu-bool tags-menu-set
+
+ name sub-menu type default symbol entry entry-function option)
+
+ (while (setq option (car options-alist))
+ (setq name (nth 0 option)
+ sub-menu (nth 1 option)
+ type (nth 2 option)
+ default (nth 3 option)
+ symbol (intern (concat "tidy-" name))
+ entry nil)
+
+ (cond ((equal type "Boolean")
+ (setq entry-function 'tidy-boolean-entry))
+
+ ((equal type "AutoBool")
+ (setq entry-function 'tidy-list-entry)
+ (setq type '("auto" "yes" "no")))
+
+ ((equal type "DocType")
+ (setq entry '())) ;; handled below
+
+ ((equal type "Tag names")
+ (setq entry-function 'tidy-string-entry))
+
+ ((equal type "String")
+ (setq entry-function 'tidy-string-entry))
+
+ ((equal type "Integer")
+ (setq entry-function 'tidy-integer-entry))
+
+ ((equal type "Encoding")
+ (setq entry '()));; handled below
+
+ ((listp type)
+ (setq entry-function 'tidy-list-entry))
+ (t
+ (error (concat "Tidy: unhandled value type " type " for " name))))
+
+ (cond ((equal sub-menu "Fix Markup")
+ (setq entry (funcall
+ entry-function
+ symbol
+ name
+ type
+ default
+ 'markup))
+
+ (if (or (equal type "Boolean") (equal type "AutoBool") (listp type))
+ (setq markup-menu-bool (append markup-menu-bool entry))
+ (setq markup-menu-set (append markup-menu-set entry))))
+
+ ((equal sub-menu "Indentation")
+ (setq entry (funcall
+ entry-function
+ symbol
+ name
+ type
+ default
+ 'indent))
+
+ (if (or (equal type "Boolean") (equal type "AutoBool") (listp type))
+ (setq indent-menu-bool (append indent-menu-bool entry))
+ (setq indent-menu-set (append indent-menu-set entry))))
+
+ ((equal sub-menu "Line Wrapping")
+ (setq entry (funcall
+ entry-function
+ symbol
+ name
+ type
+ default
+ 'line-wrap))
+
+ (if (or (equal type "Boolean") (equal type "AutoBool") (listp type))
+ (setq line-wrap-menu-bool (append line-wrap-menu-bool entry))
+ (setq line-wrap-menu-set (append line-wrap-menu-set entry))))
+
+ ((equal sub-menu "Input/Output")
+ (setq entry (funcall
+ entry-function
+ symbol
+ name
+ type
+ default
+ 'io))
+
+ (if (or (equal type "Boolean") (equal type "AutoBool") (listp type))
+ (setq io-menu-bool (append io-menu-bool entry))
+ (setq io-menu-set (append io-menu-set entry))))
+
+ ((equal sub-menu "Preference")
+ (setq entry (funcall
+ entry-function
+ symbol
+ name
+ type
+ default
+ 'preference))
+
+ (if (or (equal type "Boolean") (equal type "AutoBool") (listp type))
+ (setq preference-menu-bool (append preference-menu-bool entry))
+ (setq preference-menu-set (append preference-menu-set entry))))
+
+ ((equal sub-menu "Tags")
+ (setq entry (funcall
+ entry-function
+ symbol
+ name
+ type
+ default
+ 'tags))
+
+ (if (or (equal type "Boolean") (equal type "AutoBool"))
+ (setq tags-menu-bool (append tags-menu-bool entry))
+ (setq tags-menu-set (append tags-menu-set entry))))
+ (t)) ;; we simple omit all other menus
+
+ (setq options-alist (cdr options-alist)))
+
+ (setq tidy-menu (append
+ tidy-top-menu
+ (list (append (list "Fix Markup")
+ markup-menu-bool
+ markup-menu-set))
+ (list (append (list "Line Wrapping")
+ line-wrap-menu-bool
+ line-wrap-menu-set))
+ (list (append (list "Preference")
+ preference-menu-bool
+ preference-menu-set))
+ (list (append (list "Indentation")
+ indent-menu-bool
+ indent-menu-set))
+ (list (append(list "Input/Output")
+ io-menu-bool
+ io-menu-set))
+ (list (append (list "Tags")
+ tags-menu-bool
+ tags-menu-set))
+ (list tidy-doctype-menu)
+ (list tidy-char-encoding-menu)
+ '(["Describe options" tidy-describe-options t])))
+ )
+)
+
+;;;###autoload
+(defun tidy-build-menu (&optional map)
+ "Set up the tidy menu in MAP. Used to set up a Tidy menu in your
+favourite mode."
+ (interactive) ;; for debugging
+ (or map (setq map (current-local-map)))
+ (tidy-parse-config-file)
+ (easy-menu-remove tidy-menu)
+ (easy-menu-define tidy-menu-symbol map "Menu for tidy.el" tidy-menu)
+ (easy-menu-add tidy-menu map))
+
+;;;;; Option description support
+
+;; quiet FSF Emacs and XEmacs compilers
+(eval-when-compile
+ (progn (or (fboundp 'event-point) (defun event-point (dummy) ""))
+ (or (fboundp 'posn-point) (defun posn-point (dummy) ""))
+ (or (fboundp 'event-start) (defun event-start (dummy) ""))))
+
+(defun tidy-describe-this-option (click)
+ "Describe variable associated with the text at point."
+ (interactive "e")
+
+ (let* ((variable (get-text-property
+ (if (tidy-xemacs-p)
+ (event-point click)
+ (posn-point (event-start click))) 'tidy-variable))
+ value
+ buffer) ;; reuse the help buffer
+ (when variable
+ (save-selected-window
+ (setq value (symbol-value variable)
+ buffer (get-buffer-create "*Help*"))
+ (set-buffer buffer)
+ (setq buffer-read-only nil)
+ (delete-region (point-min) (point-max)) ;; empty the buffer
+ (insert (substring (symbol-name variable) 5) ;; clip the `tidy-' prefix
+ " is set to ")
+ (if value (insert value) (insert "set to the default value"))
+
+ (insert "\n\n" (documentation-property variable 'variable-documentation))
+ (setq buffer-read-only t)
+ (local-set-key [(q)] 'tidy-quit-describe-options)
+ (pop-to-buffer buffer)))))
+
+(defun tidy-quit-describe-options ()
+"Rid thyself of any display associated with Tidy's options."
+ (interactive)
+ (bury-buffer (get-buffer "*tidy-options*"))
+ (delete-windows-on (get-buffer "*tidy-options*"))
+ (bury-buffer (get-buffer "*Help*"))
+ (delete-windows-on (get-buffer "*Help*")))
+
+;; nicked this from cal-desk-calendar.el:-)
+(defun tidy-current-line ()
+ "Get the current line number (in the buffer) of point."
+ (interactive)
+ (save-restriction
+ (widen)
+ (save-excursion
+ (beginning-of-line)
+ (1+ (count-lines 1 (point))))))
+
+(defun tidy-describe-options ()
+ "Interactively access documentation strings for `tidy-' variables."
+ (interactive)
+ (let ((buffer (get-buffer "*tidy-options*")))
+ (if buffer (pop-to-buffer buffer)
+ ;; else build it from scratch
+ (setq buffer (get-buffer-create "*tidy-options*"))
+ (let* ((start 0)
+ (end 0)
+ name
+ (count 0)
+ (option-alist tidy-options-alist)
+ (column2a (+ (length "drop-proprietary-attributes") 3))
+ (column2b (/ (window-width) 3))
+ (column2 (if (> column2a column2b) column2a column2b))
+ (column3 (* 2 column2))
+ (start-line 0)
+ (third-length 0)
+ (two-third-length 0))
+
+ (set-buffer buffer)
+
+ (setq buffer-read-only nil)
+ (delete-region (point-min) (point-max)) ;; empty the buffer
+
+ ;; set up local bindings
+ (if (tidy-xemacs-p)
+ (local-set-key [(button2)] 'tidy-describe-this-option)
+ (local-set-key [(mouse-2)] 'tidy-describe-this-option))
+
+ (local-set-key [(q)] 'tidy-quit-describe-options)
+
+ (insert "Click [mouse-2] over option to see its description. "
+ "Type \"q\" to quit." "\n\n")
+
+ (setq start-line (tidy-current-line))
+ (setq third-length (1+ (/ (length option-alist) 3) ))
+ (setq two-third-length (1- (* 2 third-length)))
+
+ (while (setq name (car (car-safe option-alist)))
+ (setq option-alist (cdr option-alist))
+ (setq count (+ count 1))
+
+ (cond
+ ((< count third-length) ;; 0 <= count < third-length
+ (setq start (point))
+ (insert name)
+ (setq end (point))
+ (insert "\n"))
+ ((< count two-third-length) ;; third-length <= count < two-third-length
+ (if (= count third-length)
+ (goto-line start-line)
+ (forward-line 1))
+ (end-of-line)
+ (setq start (point))
+ (indent-to-column column2)
+ (setq end (point))
+ (put-text-property start end 'mouse-face 'default)
+ (setq start (point))
+ (insert name)
+ (setq end (point)))
+ (t ;; two-third-length <= count < length
+ (if (= count two-third-length)
+ (goto-line start-line)
+ (forward-line 1))
+ (end-of-line)
+ (setq start (point))
+ (indent-to-column column3)
+ (setq end (point))
+ (put-text-property start end 'mouse-face 'default)
+ (setq start (point))
+ (insert name)
+ (setq end (point))))
+
+ ;; make the strings funky
+ (put-text-property start end 'mouse-face 'highlight)
+ (put-text-property start end 'tidy-variable (intern (concat "tidy-" name)))
+ )
+ (setq buffer-read-only t)
+ (beginning-of-buffer)
+ (pop-to-buffer buffer)
+ ))))
+
+;;;;; Configuration file support
+
+;;;###autoload
+(defun tidy-parse-config-file ()
+ "If `tidy-config-file' is non-nil parse that file setting variables accordingly."
+ (interactive)
+ (when tidy-config-file
+ (if (not (file-exists-p tidy-config-file))
+ (message "Could not find config file \"%s\". Winging it." tidy-config-file)
+ (message "Parsing config file...")
+ (let ((html-buffer (current-buffer))
+ (config-buffer (find-file-noselect tidy-config-file t)))
+ (save-excursion
+ (set-buffer config-buffer)
+ (goto-char (point-min)) ;; unnecessary but pedantic
+
+ ;; delete all comments
+ (while (re-search-forward "//.*\n" nil t)
+ (replace-match "" nil nil))
+
+ (goto-char (point-min))
+ (while (re-search-forward "\\([a-z,-]+\\):\\s-*\\(.*\\)\\s-*" nil t)
+ ;; set the variable
+ ;; Thanks to Thomas Baumann for this bugfix
+ (let ((variable (concat "tidy-" (match-string 1)))
+ (value (match-string 2)))
+ (save-excursion
+ (set-buffer html-buffer)
+ (set (intern variable) value))))
+
+ (set-buffer-modified-p nil) ;; don't save changes
+ (kill-buffer config-buffer)))
+ (message "Parsing config file...done")
+ )))
+
+;;;###autoload
+(defun tidy-save-settings (&optional config-file)
+ "Query saving the current settings to your `tidy-config-file'.
+Perhaps put this on your `kill-buffer-hook'."
+ (interactive)
+ (or config-file (setq config-file tidy-config-file))
+ (when config-file
+
+ ;; should check for locks!
+ (if (or (not (interactive-p))
+ (y-or-n-p "Save settings to your tidy configuration file? "))
+
+ (let ((buffer (find-file-noselect config-file t))
+ (option-alist tidy-options-alist)
+ (outer-buffer (current-buffer))
+ option name symbol value)
+ (save-excursion
+ (set-buffer buffer)
+ (delete-region (point-min) (point-max)) ;; clear the buffer
+
+ ;; need this line so that config file is always non empty
+ (insert "// HTML Tidy configuration file \n")
+ (while (setq option (car option-alist))
+ (setq option-alist (cdr option-alist))
+ (setq name (nth 0 option)
+ symbol (intern (concat "tidy-" name)))
+ (save-excursion ;; this is a local variable
+ (set-buffer outer-buffer)
+ (setq value (symbol-value symbol)))
+ (when value ;; nil iff default
+ (insert (car option) ": " value "\n")))
+
+ (save-buffer)
+ (kill-buffer buffer)
+ )))))
+
+
+;;;;; Main user function
+
+(eval-when-compile (defvar tidy-markup nil ""))
+
+(defun tidy-set-buffer-unmodified (dummy1 dummy2 dumm3)
+ "Used to prevent error buffer form being marked as modified."
+ (set-buffer-modified-p nil))
+
+;;;###autoload
+(defun tidy-buffer (&optional prefix)
+ "Run the HTML Tidy program on the current buffer.
+If PREFIX is non-nil, or if called interactively with a prefix argument,
+then Tidy is applied to the currently selected region. Any error messages
+generated by that program are sent to \"*tidy-errors*\" buffer."
+
+ (interactive "P")
+
+ (let* ((start (if (null prefix) (point-min) (mark)))
+ (end (if (null prefix) (point-max) (point)))
+ (filename (file-name-nondirectory (buffer-file-name (current-buffer))))
+ ;; Gasp! We have to use temp files here because the command
+ ;; line would likely get too long!
+
+ (error-file (concat
+ ;; name may or may not end in "/"
+ (directory-file-name tidy-temp-directory)
+ "/temp-tidy-errors"))
+
+ (error-buffer (get-buffer error-file))
+
+ (temp-buffer " *tidy-temp*") ;; invisible
+
+ (config-file (concat
+ ;; name may or may not end in "/"
+ (directory-file-name tidy-temp-directory)
+ "/temp-tidy-config"))
+
+ (command (concat tidy-shell-command
+ ;; load configuration file first so that
+ ;; options are overridden by command line
+ " -config " config-file
+ " --error-file " error-file
+ " --write-back no"
+ (if prefix " --show-body-only yes"
+ " --show-body-only no")
+ " --gnu-emacs yes"
+ " --gnu-emacs-file \"" filename "\""
+ ))
+ (errors 0)
+ (warnings 0)
+ (tidy-message "")
+ (seg-error nil))
+
+ (if (> start end) (setq end (mark) start (point))) ;; rare case swap
+
+ (when error-buffer ;; flush the error buffer
+ (save-excursion
+ (set-buffer error-buffer)
+ (set-buffer-modified-p nil)
+ (kill-buffer error-buffer)))
+
+ (when (get-buffer temp-buffer) ;; flush the temp buffer
+ (save-excursion
+ (set-buffer temp-buffer)
+ (delete-region (point-min) (point-max))))
+
+ (tidy-save-settings config-file)
+
+ ;; OK do the tidy
+ (shell-command-on-region start end command temp-buffer nil)
+
+ ;; Since XEmacs can't grab the std error stream we use an error file
+ (setq error-buffer (find-file-noselect error-file t))
+
+ ;; avoid leaving theses guys lying around
+ (if (file-exists-p error-file) (delete-file error-file))
+ (if (file-exists-p config-file) (delete-file config-file))
+
+ ;; scan the buffer for error strings
+ (save-excursion
+ (set-buffer error-buffer)
+ (goto-char (point-min))
+ (when (re-search-forward (concat
+ "\\([0-9]+\\) warnings?, "
+ "\\([0-9]+\\) errors? were found!")
+ nil t)
+ (setq warnings (string-to-number (match-string 1)))
+ (setq errors (string-to-number (match-string 2)))
+ (setq tidy-message (match-string 0)))
+
+ (goto-char (point-min))
+ (while (re-search-forward "stdin:" nil t)
+ (replace-match (concat filename ":")))
+ (setq buffer-read-only t)
+ (compilation-mode)
+ ;; don't save changes
+ (set-buffer-modified-p nil)
+ ;; Unfortunately as soon as you do `next-error' this will change
+ ;; the buffer again (setting text properties), so we make it
+ ;; impossible to mark this buffer as modified by setting the
+ ;; following buffer local variable:
+ (make-variable-buffer-local 'after-change-functions)
+ (add-hook 'after-change-functions 'tidy-set-buffer-unmodified t t)
+ ;; (remove-hook 'after-change-functions 'tidy-set-buffer-unmodified t)
+ (goto-char (point-min))
+ )
+
+ ;; Catch segmentation violations
+ ;; Sometimes get this when editing files from Macs
+ ;; See the function at the bottom of the file
+
+ (if (buffer-live-p temp-buffer)
+ (save-excursion
+ (set-buffer temp-buffer)
+ (goto-char (point-min))
+ (let ((case-fold-search t))
+ (if (looking-at "Segmentation") ;; might work with XEmacs
+ (setq seg-error t)))))
+
+ (unless (or (> errors 0) seg-error)
+ (let* ((window (get-buffer-window (current-buffer)))
+ (top (window-start window)))
+
+ (unless tidy-markup ;; default is "yes" hence inverted logic
+ (delete-region start end) ;; delete the buffer/region
+ (insert-buffer temp-buffer)) ;; replace with tidied text
+
+ ;; Try not to move the window too much when we tidy the whole buffer
+ (set-window-start window top)))
+
+ ;; only pop-up window if there's an error
+
+ (if (and (= warnings 0)
+ (= errors 0))
+ (delete-windows-on error-buffer t) ;; else delete the pop-up window
+
+;;; Thanks to Thomas Baumann for the following fix
+;;; (pop-to-buffer error-buffer t)
+;;; (beginning-of-buffer))
+ ;; display the error-buffer, but do not select it
+ ;; one can use C-x ` or mouse-2 to jump to the errors
+ (display-buffer error-buffer t))
+;;;
+
+ (delete-windows-on temp-buffer t) ;; sometimes pops up
+
+ (if seg-error
+ (message (concat "Tidy: Segmentation violation!!!"
+ " Check your character encoding."))
+ (message "%s" tidy-message)
+ )
+ ))
+
+;;;}}} +
+
+;;;}}}
+
+(provide 'tidy)
+
+;;; tidy.el ends here
--- /dev/null
+;;; mmm-auto.el --- loading and enabling MMM Mode automatically
+
+;; Copyright (C) 2000 by Michael Abraham Shulman
+
+;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file contains functions and hooks to load and enable MMM Mode
+;; automatically. It sets up autoloads for the main MMM Mode functions
+;; and interactive commands, and also sets up MMM Global Mode.
+
+;;{{{ Comments on MMM Global Mode
+
+;; This is a kludge borrowed from `global-font-lock-mode'. The idea
+;; is the same: we have a function (here `mmm-mode-on-maybe') that we
+;; want to be run whenever a major mode starts. Unfortunately, there
+;; is no hook (like, say `major-mode-hook') that all major modes run
+;; when they are finished. `post-command-hook', however, is run after
+;; *every* command, so we do our work in there. (Actually, using
+;; `post-command-hook' is even better than being run by major mode
+;; functions, since it is run after all local variables and text are
+;; loaded, which may not be true in certain cases for the other.)
+
+;; In order to do this magic, we rely on the fact that there *is* a
+;; hook that all major modes run when *beginning* their work. They
+;; call `kill-all-local-variables' (unless they are broken), which in
+;; turn runs `change-major-mode-hook'. So we add a function to *that*
+;; hook which saves the current buffer and temporarily adds a function
+;; to `post-command-hook' which processes that buffer.
+
+;; Actually, in the interests of generality, what that function does
+;; is run the hook `mmm-major-mode-hook'. Our desired function
+;; `mmm-mode-on-maybe' is then added to that hook. This way, if the
+;; user wants to run something else on every major mode, they can just
+;; add it to `mmm-major-mode-hook' and take advantage of this hack.
+
+;;}}}
+
+;;; Code:
+
+(require 'cl)
+(require 'mmm-vars)
+
+;;{{{ Autoload Submode Classes
+
+(defvar mmm-autoloaded-classes
+ '((mason "mmm-mason" nil)
+ (myghty "mmm-myghty" nil)
+ (html-css "mmm-sample" nil)
+ (html-js "mmm-sample" nil)
+ (here-doc "mmm-sample" nil)
+ (embperl "mmm-sample" nil)
+ (eperl "mmm-sample" nil)
+ (jsp "mmm-sample" nil)
+ (file-variables "mmm-sample" nil)
+ (rpm-sh "mmm-rpm" t)
+ (rpm "mmm-rpm" nil)
+ (cweb "mmm-cweb" nil)
+ (sgml-dtd "mmm-sample" nil)
+ (noweb "mmm-noweb" nil)
+ (html-php "mmm-sample" nil)
+ )
+ "Alist of submode classes autoloaded from files.
+Elements look like \(CLASS FILE PRIVATE) where CLASS is a submode
+class symbol, FILE is a string suitable for passing to `load', and
+PRIVATE is non-nil if the class is invisible to the user. Classes can
+be added to this list with `mmm-autoload-class'.")
+
+(defun mmm-autoload-class (class file &optional private)
+ "Autoload submode class CLASS from file FILE.
+PRIVATE, if non-nil, means the class is user-invisible. In general,
+private classes need not be autoloaded, since they will usually be
+invoked by a public class in the same file."
+ ;; Don't autoload already defined classes
+ (unless (assq class mmm-classes-alist)
+ (add-to-list 'mmm-autoloaded-classes
+ (list class file private))))
+
+;;}}}
+;;{{{ Autoload Functions
+
+;; To shut up the byte compiler.
+(eval-and-compile
+ (autoload 'mmm-mode-on "mmm-mode" "Turn on MMM Mode. See `mmm-mode'.")
+ (autoload 'mmm-mode-off "mmm-mode" "Turn off MMM Mode. See `mmm-mode'.")
+ (autoload 'mmm-update-font-lock-buffer "mmm-region")
+ (autoload 'mmm-ensure-fboundp "mmm-utils")
+ (autoload 'mmm-mode "mmm-mode"
+ "Minor mode to allow multiple major modes in one buffer.
+Without ARG, toggle MMM Mode. With ARG, turn MMM Mode on iff ARG is
+positive and off otherwise." t))
+
+;; These may actually be used.
+(autoload 'mmm-ify-by-class "mmm-cmds" "" t)
+(autoload 'mmm-ify-by-regexp "mmm-cmds" "" t)
+(autoload 'mmm-ify-region "mmm-cmds" "" t)
+(autoload 'mmm-parse-buffer "mmm-cmds" "" t)
+(autoload 'mmm-parse-region "mmm-cmds" "" t)
+(autoload 'mmm-parse-block "mmm-cmds" "" t)
+(autoload 'mmm-clear-current-region "mmm-cmds" "" t)
+(autoload 'mmm-reparse-current-region "mmm-cmds" "" t)
+(autoload 'mmm-end-current-region "mmm-cmds" "" t)
+(autoload 'mmm-insertion-help "mmm-cmds" "" t)
+(autoload 'mmm-insert-region "mmm-cmds" "" t)
+
+;;}}}
+;;{{{ MMM Global Mode
+
+(defvar mmm-changed-buffers-list ()
+ "Buffers that need to be checked for running the major mode hook.")
+
+(defun mmm-major-mode-change ()
+ "Add this buffer to `mmm-changed-buffers-list' for checking.
+When the current command is over, MMM Mode will be turned on in this
+buffer depending on the value of `mmm-global-mode'. Actually,
+everything in `mmm-major-mode-hook' will be run."
+ (and (boundp 'mmm-mode)
+ mmm-mode
+ (mmm-mode-off))
+ (add-to-list 'mmm-changed-buffers-list (current-buffer))
+ (add-hook 'post-command-hook 'mmm-check-changed-buffers))
+
+(add-hook 'change-major-mode-hook 'mmm-major-mode-change)
+
+(defun mmm-check-changed-buffers ()
+ "Run major mode hook for the buffers in `mmm-changed-buffers-list'."
+ (remove-hook 'post-command-hook 'mmm-check-changed-buffers)
+ (dolist (buffer mmm-changed-buffers-list)
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (mmm-run-major-mode-hook))))
+ (setq mmm-changed-buffers-list '()))
+
+(defun mmm-mode-on-maybe ()
+ "Conditionally turn on MMM Mode.
+Turn on MMM Mode if `mmm-global-mode' is non-nil and there are classes
+to apply, or always if `mmm-global-mode' is t."
+ (cond ((eq mmm-global-mode t) (mmm-mode-on))
+ ((not mmm-global-mode))
+ ((mmm-get-all-classes nil) (mmm-mode-on)))
+ (when mmm-mode
+ (mmm-update-font-lock-buffer)))
+
+(add-hook 'mmm-major-mode-hook 'mmm-mode-on-maybe)
+
+(defalias 'mmm-add-find-file-hooks 'mmm-add-find-file-hook)
+(defun mmm-add-find-file-hook ()
+ "Equivalent to \(setq mmm-global-mode 'maybe).
+This function is deprecated and may be removed in future."
+ (message "Warning: `mmm-add-find-file-hook' is deprecated.")
+ (setq mmm-global-mode 'maybe))
+
+;;}}}
+
+(provide 'mmm-auto)
+
+;;; mmm-auto.el ends here
--- /dev/null
+;;; mmm-class.el --- MMM submode class variables and functions
+
+;; Copyright (C) 2000, 2004 by Michael Abraham Shulman
+
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file contains variable and function definitions for
+;; manipulating and applying MMM submode classes. See `mmm-vars.el'
+;; for variables that list classes.
+
+;;; Code:
+
+(require 'cl)
+(require 'mmm-vars)
+(require 'mmm-region)
+
+;;; CLASS SPECIFICATIONS
+;;{{{ Get Class Specifications
+
+(defun mmm-get-class-spec (class)
+ "Get the class specification for CLASS.
+CLASS can be either a symbol to look up in `mmm-classes-alist' or a
+class specifier itself."
+ (cond ((symbolp class) ; A symbol must be looked up
+ (or (cdr (assq class mmm-classes-alist))
+ (and (cadr (assq class mmm-autoloaded-classes))
+ (load (cadr (assq class mmm-autoloaded-classes)))
+ (cdr (assq class mmm-classes-alist)))
+ (signal 'mmm-invalid-submode-class (list class))))
+ ((listp class) ; A list must be a class spec
+ class)
+ (t (signal 'mmm-invalid-submode-class (list class)))))
+
+;;}}}
+;;{{{ Get and Set Class Parameters
+
+(defun mmm-get-class-parameter (class param)
+ "Get the value of the parameter PARAM for CLASS, or nil if none."
+ (cadr (member param (mmm-get-class-spec class))))
+
+(defun mmm-set-class-parameter (class param value)
+ "Set the value of the parameter PARAM for CLASS to VALUE.
+Creates a new parameter if one is not present."
+ (let* ((spec (mmm-get-class-spec class))
+ (current (member param spec)))
+ (if current
+ (setcar (cdr current) value)
+ (nconc spec (list param value)))))
+
+;;}}}
+;;{{{ Apply Classes
+
+(defun* mmm-apply-class
+ (class &optional (start (point-min)) (stop (point-max)) face)
+ "Apply the submode class CLASS from START to STOP in FACE.
+If FACE is nil, the face for CLASS is used, or the default face if
+none is specified by CLASS."
+ ;; The "special" class t means do nothing. It is used to turn on
+ ;; MMM Mode without applying any classes.
+ (unless (eq class t)
+ (apply #'mmm-ify :start start :stop stop
+ (append (mmm-get-class-spec class)
+ (list :face face)))
+ (mmm-run-class-hook class)
+ ;; Hack in case class hook sets mmm-buffer-mode-display-name etc.
+ (mmm-set-mode-line)))
+
+(defun* mmm-apply-classes
+ (classes &key (start (point-min)) (stop (point-max)) face)
+ "Apply all submode classes in CLASSES, in order.
+All classes are applied regardless of any errors that may occur in
+other classes. If any errors occur, `mmm-apply-classes' exits with an
+error once all classes have been applied."
+ (let (invalid-classes)
+ (dolist (class classes)
+ (condition-case err
+ (mmm-apply-class class start stop face)
+ (mmm-invalid-submode-class
+ ;; Save the name of the invalid class, so we can report them
+ ;; all together at the end.
+ (add-to-list 'invalid-classes (second err)))))
+ (when invalid-classes
+ (signal 'mmm-invalid-submode-class invalid-classes))))
+
+;;}}}
+;;{{{ Apply All Classes
+
+(defun* mmm-apply-all (&key (start (point-min)) (stop (point-max)))
+ "MMM-ify from START to STOP by all submode classes.
+The classes come from mode/ext, `mmm-classes', `mmm-global-classes',
+and interactive history."
+ (mmm-clear-overlays start stop 'strict)
+ (mmm-apply-classes (mmm-get-all-classes t) :start start :stop stop)
+ (mmm-update-submode-region)
+ (syntax-ppss-flush-cache start)
+ (mmm-refontify-maybe start stop))
+
+;;}}}
+
+;;; BUFFER SCANNING
+;;{{{ Scan for Regions
+
+(defun* mmm-ify
+ (&rest all &key classes handler
+ submode match-submode
+ (start (point-min)) (stop (point-max))
+ front back save-matches (case-fold-search t)
+ (beg-sticky (not (number-or-marker-p front)))
+ (end-sticky (not (number-or-marker-p back)))
+ include-front include-back
+ (front-offset 0) (back-offset 0)
+ (front-delim nil) (back-delim nil)
+ (delimiter-mode mmm-delimiter-mode)
+ front-face back-face
+ front-verify back-verify
+ front-form back-form
+ creation-hook
+ face match-face
+ save-name match-name
+ (front-match 0) (back-match 0)
+ end-not-begin
+ ;insert private
+ &allow-other-keys
+ )
+ "Create submode regions from START to STOP according to arguments.
+If CLASSES is supplied, it must be a list of valid CLASSes. Otherwise,
+the rest of the arguments are for an actual class being applied. See
+`mmm-classes-alist' for information on what they all mean."
+ ;; Make sure we get the default values in the `all' list.
+ (setq all (append
+ all
+ (list :start start :stop stop
+ :beg-sticky beg-sticky :end-sticky end-sticky
+ :front-offset front-offset :back-offset back-offset
+ :front-delim front-delim :back-delim back-delim
+ :front-match 0 :back-match 0
+ )))
+ (cond
+ ;; If we have a class list, apply them all.
+ (classes
+ (mmm-apply-classes classes :start start :stop stop :face face))
+ ;; Otherwise, apply this class.
+ ;; If we have a handler, call it.
+ (handler
+ (apply handler all))
+ ;; Otherwise, we search from START to STOP for submode regions,
+ ;; continuining over errors, until we don't find any more. If FRONT
+ ;; and BACK are number-or-markers, this should only execute once.
+ (t
+ (mmm-save-all
+ (goto-char start)
+ (loop for (beg end front-pos back-pos matched-front matched-back
+ matched-submode matched-face matched-name
+ invalid-resume ok-resume) =
+ (apply #'mmm-match-region :start (point) all)
+ while beg
+ if end ; match-submode, if present, succeeded.
+ do
+ (condition-case nil
+ (progn
+ (mmm-make-region
+ (or matched-submode submode) beg end
+ :face (or matched-face face)
+ :front front-pos :back back-pos
+ :evaporation 'front
+ :match-front matched-front :match-back matched-back
+ :beg-sticky beg-sticky :end-sticky end-sticky
+ :name matched-name
+ :delimiter-mode delimiter-mode
+ :front-face front-face :back-face back-face
+ :creation-hook creation-hook
+ )
+ (goto-char ok-resume))
+ ;; If our region is invalid, go back to the end of the
+ ;; front match and continue on.
+ (mmm-error (goto-char invalid-resume)))
+ ;; If match-submode was unable to find a match, go back to
+ ;; the end of the front match and continue on.
+ else do (goto-char invalid-resume)
+ )))))
+
+;;}}}
+;;{{{ Match Regions
+
+(defun* mmm-match-region
+ (&key start stop front back front-verify back-verify
+ front-delim back-delim
+ include-front include-back front-offset back-offset
+ front-form back-form save-matches match-submode match-face
+ front-match back-match end-not-begin
+ save-name match-name
+ &allow-other-keys)
+ "Find the first valid region between point and STOP.
+Return \(BEG END FRONT-POS BACK-POS FRONT-FORM BACK-FORM SUBMODE FACE
+NAME INVALID-RESUME OK-RESUME) specifying the region. See
+`mmm-match-and-verify' for the valid values of FRONT and BACK
+\(markers, regexps, or functions). A nil value for END means that
+MATCH-SUBMODE failed to find a valid submode. INVALID-RESUME is the
+point at which the search should continue if the region is invalid,
+and OK-RESUME if the region is valid."
+ (when (mmm-match-and-verify front start stop front-verify)
+ (let ((beg (mmm-match->point include-front front-offset front-match))
+ (front-pos (if front-delim
+ (mmm-match->point t front-delim front-match)
+ nil))
+ (invalid-resume (match-end front-match))
+ (front-form (mmm-get-form front-form)))
+ (let ((submode (if match-submode
+ (condition-case nil
+ (mmm-save-all
+ (funcall match-submode front-form))
+ (mmm-no-matching-submode
+ (return-from
+ mmm-match-region
+ (values beg nil nil nil nil nil nil nil nil
+ invalid-resume nil))))
+ nil))
+ (name (cond ((functionp match-name)
+ (mmm-save-all (funcall match-name front-form)))
+ ((stringp match-name)
+ (if save-name
+ (mmm-format-matches match-name)
+ match-name))))
+ (face (cond ((functionp match-face)
+ (mmm-save-all
+ (funcall match-face front-form)))
+ (match-face
+ (cdr (assoc front-form match-face))))))
+ (when (mmm-match-and-verify
+ (if save-matches
+ (mmm-format-matches back)
+ back)
+ beg stop back-verify)
+ (let* ((end (mmm-match->point (not include-back)
+ back-offset back-match))
+ (back-pos (if back-delim
+ (mmm-match->point nil back-delim back-match)
+ nil))
+ (back-form (mmm-get-form back-form))
+ (ok-resume (if end-not-begin
+ (match-end back-match)
+ end)))
+ (values beg end front-pos back-pos front-form back-form
+ submode face name
+ invalid-resume ok-resume)))))))
+
+(defun mmm-match->point (beginp offset match)
+ "Find a point of starting or stopping from the match data. If
+BEGINP, start at \(match-beginning MATCH), else \(match-end MATCH),
+and move OFFSET. Handles all values of OFFSET--see `mmm-classes-alist'."
+ (save-excursion
+ (goto-char (if beginp
+ (match-beginning match)
+ (match-end match)))
+ (dolist (spec (if (listp offset) offset (list offset)))
+ (if (numberp spec)
+ (forward-char (or spec 0))
+ (funcall spec)))
+ (point)))
+
+(defun mmm-match-and-verify (pos start stop &optional verify)
+ "Find first match for POS between point and STOP satisfying VERIFY.
+Return non-nil if a match was found, and set match data. POS can be a
+number-or-marker, a regexp, or a function.
+
+If POS is a number-or-marker, it is used as-is. If it is a string, it
+is searched for as a regexp until VERIFY returns non-nil. If it is a
+function, it is called with argument STOP and must return non-nil iff
+a match is found, and set the match data. Note that VERIFY is ignored
+unless POS is a regexp."
+ (cond
+ ;; A marker can be used as-is, but only if it's in bounds.
+ ((and (number-or-marker-p pos) (>= pos start) (<= pos stop))
+ (goto-char pos)
+ (looking-at "")) ; Set the match data
+ ;; Strings are searched for as regexps.
+ ((stringp pos)
+ (loop always (re-search-forward pos stop 'limit)
+ until (or (not verify) (mmm-save-all (funcall verify)))))
+ ;; Otherwise it must be a function.
+ ((functionp pos)
+ (funcall pos stop))))
+
+;;}}}
+;;{{{ Get Delimiter Forms
+
+(defun mmm-get-form (form)
+ "Return the delimiter form specified by FORM.
+If FORM is nil, call `mmm-default-get-form'. If FORM is a string,
+return it. If FORM is a function, call it. If FORM is a list, return
+its `car' \(usually in this case, FORM is a one-element list
+containing a function to be used as the delimiter form."
+ (cond ((stringp form) form)
+ ((not form) (mmm-default-get-form))
+ ((functionp form) (mmm-save-all (funcall form)))
+ ((listp form) (car form))))
+
+(defun mmm-default-get-form ()
+ (regexp-quote (match-string 0)))
+
+;;}}}
+
+(provide 'mmm-class)
+
+;;; mmm-class.el ends here
--- /dev/null
+;;; mmm-cmds.el --- MMM Mode interactive commands and keymap
+
+;; Copyright (C) 2000 by Michael Abraham Shulman
+
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file contains the interactive commands for MMM Mode.
+
+;;; Code:
+
+(require 'cl)
+(require 'font-lock)
+(require 'mmm-compat)
+(require 'mmm-vars)
+(require 'mmm-class)
+
+;; APPLYING CLASSES
+;;{{{ Applying Predefined Classes
+
+(defun mmm-ify-by-class (class)
+ "Add submode regions according to an existing submode class."
+ (interactive
+ (list (intern
+ (completing-read
+ "Submode Class: "
+ (remove-duplicates
+ (mapcar #'(lambda (spec) (list (symbol-name (car spec))))
+ (append
+ (remove-if #'(lambda (spec) (plist-get (cdr spec) :private))
+ mmm-classes-alist)
+ (remove-if #'caddr mmm-autoloaded-classes)))
+ :test #'equal)
+ nil t))))
+ (unless (eq class (intern ""))
+ (mmm-apply-class class)
+ (mmm-add-to-history class)
+ (mmm-update-font-lock-buffer)))
+
+;;}}}
+;;{{{ Applying by the Region
+
+(defun mmm-ify-region (submode front back)
+ "Add a submode region for SUBMODE coinciding with current region."
+ (interactive "aSubmode: \nr")
+ (mmm-ify :submode submode :front front :back back)
+ (setq front (mmm-make-marker front t nil)
+ back (mmm-make-marker back nil nil))
+ (mmm-add-to-history `(:submode ,submode :front ,front :back ,back))
+ (mmm-enable-font-lock submode))
+
+;;}}}
+;;{{{ Applying Simple Regexps
+
+(defun mmm-ify-by-regexp
+ (submode front front-offset back back-offset save-matches)
+ "Add SUBMODE regions to the buffer delimited by FRONT and BACK.
+With prefix argument, prompts for all additional keywords arguments.
+See `mmm-classes-alist'."
+ (interactive "aSubmode:
+sFront Regexp:
+nOffset from Front Regexp:
+sBack Regexp:
+nOffset from Back Regexp:
+nNumber of matched substrings to save: ")
+ (let ((args (mmm-save-keywords submode front back front-offset
+ back-offset save-matches)))
+ (apply #'mmm-ify args)
+ (mmm-add-to-history args))
+ (mmm-enable-font-lock submode))
+
+;;}}}
+
+;; EDITING WITH REGIONS
+;;{{{ Re-parsing Areas
+
+(defun mmm-parse-buffer ()
+ "Re-apply all applicable submode classes to current buffer.
+Clears all current submode regions, reapplies all past interactive
+mmm-ification, and applies `mmm-classes' and mode-extension classes."
+ (interactive)
+ (message "MMM-ifying buffer...")
+ (mmm-apply-all)
+ (message "MMM-ifying buffer...done"))
+
+(defun mmm-parse-region (start stop)
+ "Re-apply all applicable submode classes between START and STOP.
+Clears all current submode regions, reapplies all past interactive
+mmm-ification, and applies `mmm-classes' and mode-extension classes."
+ (interactive "r")
+ (message "MMM-ifying region...")
+ (mmm-apply-all :start start :stop stop)
+ (message "MMM-ifying region...done"))
+
+(defun mmm-parse-block (&optional lines)
+ "Re-parse LINES lines before and after point \(default 1).
+Clears all current submode regions, reapplies all past interactive
+mmm-ification, and applies `mmm-classes' and mode-extension classes.
+
+This command is intended for use when you have just typed what should
+be the delimiters of a submode region and you want to create the
+region. However, you may want to look into the various types of
+delimiter auto-insertion that MMM Mode provides. See, for example,
+`mmm-insert-region'."
+ (interactive "p")
+ (message "MMM-ifying block...")
+ (destructuring-bind (start stop) (mmm-get-block lines)
+ (when (< start stop)
+ (mmm-apply-all :start start :stop stop)))
+ (message "MMM-ifying block...done"))
+
+(defun mmm-get-block (lines)
+ (let ((inhibit-point-motion-hooks t))
+ (list (save-excursion
+ (forward-line (- lines))
+ (beginning-of-line)
+ (point))
+ (save-excursion
+ (forward-line lines)
+ (end-of-line)
+ (point)))))
+
+;;}}}
+;;{{{ Reparse Current Region
+
+(defun mmm-reparse-current-region ()
+ "Clear and reparse the area of the current submode region.
+Use this command if a submode region's boundaries have become wrong."
+ (interactive)
+ (let ((ovl (mmm-overlay-at (point) 'all)))
+ (when ovl
+ (let ((beg (save-excursion
+ (goto-char (mmm-front-start ovl))
+ (forward-line -1)
+ (point)))
+ (end (save-excursion
+ (goto-char (mmm-back-end ovl))
+ (forward-line 1)
+ (point))))
+ (mmm-parse-region beg end)))))
+
+;;}}}
+;;{{{ Clear Submode Regions
+
+;; See also `mmm-clear-history' which is interactive.
+
+(defun mmm-clear-current-region ()
+ "Deletes the submode region point is currently in, if any."
+ (interactive)
+ (delete-overlay (mmm-overlay-at (point) 'all)))
+
+(defun mmm-clear-regions (start stop)
+ "Deletes all submode regions from START to STOP."
+ (interactive "r")
+ (mmm-clear-overlays start stop))
+
+(defun mmm-clear-all-regions ()
+ "Deletes all submode regions in the current buffer."
+ (interactive)
+ (mmm-clear-overlays))
+
+;;}}}
+;;{{{ End Current Region
+
+(defun* mmm-end-current-region (&optional arg)
+ "End current submode region.
+If ARG is nil, end it at the most appropriate place, usually its
+current back boundary. If ARG is non-nil, end it at point. If the
+current region is correctly bounded, the first does nothing, but the
+second deletes that delimiter as well.
+
+If the region's BACK property is a string, it is inserted as above and
+the overlay moved if necessary. If it is a function, it is called with
+two arguments--the overlay, and \(if ARG 'middle t)--and must do the
+entire job of this function."
+ (interactive "P")
+ (let ((ovl (mmm-overlay-at)))
+ (when ovl
+ (combine-after-change-calls
+ (save-match-data
+ (save-excursion
+ (when (mmm-match-back ovl)
+ (if arg
+ (replace-match "")
+ (return-from mmm-end-current-region)))))
+ (let ((back (overlay-get ovl 'back)))
+ (cond ((stringp back)
+ (save-excursion
+ (unless arg (goto-char (overlay-end ovl)))
+ (save-excursion (insert back))
+ (move-overlay ovl (overlay-start ovl) (point))))
+ ((functionp back)
+ (funcall back ovl (if arg 'middle t))))))
+ (mmm-refontify-maybe (save-excursion (forward-line -1) (point))
+ (save-excursion (forward-line 1) (point))))))
+
+;;}}}
+;;{{{ Narrow to Region
+
+(defun mmm-narrow-to-submode-region (&optional pos)
+ "Narrow to the submode region at point."
+ (interactive)
+ ;; Probably don't use mmm-current-overlay here, because this is
+ ;; sometimes called from inside messy functions.
+ (let ((ovl (mmm-overlay-at pos)))
+ (when ovl
+ (narrow-to-region (overlay-start ovl) (overlay-end ovl)))))
+
+;; The inverse command is `widen', usually on `C-x n w'
+
+;;}}}
+
+;; INSERTING REGIONS
+;;{{{ Insert regions by keystroke
+
+;; This is the "default" binding in the MMM Mode keymap. Keys defined
+;; by classes should be control keys, to avoid conflicts with MMM
+;; commands.
+(defun mmm-insert-region (arg)
+ "Insert a submode region based on last character in invoking keys.
+Keystrokes after `mmm-mode-prefix-key' which are not bound to an MMM
+Mode command \(see `mmm-command-modifiers') are passed on to this
+function. If they have the modifiers `mmm-insert-modifiers', then they
+are looked up, sans those modifiers, in all current submode classes to
+find an insert skeleton. For example, in Mason, `p' \(with appropriate
+prefix and modifiers) will insert a <%perl>...</%perl> region."
+ (interactive "P")
+ (let* ((seq (this-command-keys))
+ (event (aref seq (1- (length seq))))
+ (mods (event-modifiers event))
+ (key (mmm-event-key event)))
+ (if (subsetp mmm-insert-modifiers mods)
+ (mmm-insert-by-key
+ (append (set-difference mods mmm-insert-modifiers)
+ key)
+ arg))))
+
+(defun mmm-insert-by-key (key &optional arg)
+ "Insert a submode region based on event KEY.
+Inspects all the classes of the current buffer to find a matching
+:insert key sequence. See `mmm-classes-alist'. ARG, if present, is
+passed on to `skeleton-proxy-new' to control wrapping.
+
+KEY must be a list \(MODIFIERS... . BASIC-KEY) where MODIFIERS are
+symbols such as shift, control, etc. and BASIC-KEY is a character code
+or a symbol such as tab, return, etc. Note that if there are no
+MODIFIERS, the dotted list becomes simply BASIC-KEY."
+ (multiple-value-bind (class skel str) (mmm-get-insertion-spec key)
+ (when skel
+ (let ((after-change-functions nil)
+ (old-undo buffer-undo-list) undo)
+ ;; XEmacs' skeleton doesn't manage positions by itself, so we
+ ;; have to do it.
+ (if mmm-xemacs (setq skeleton-positions nil))
+ (skeleton-proxy-new skel str arg)
+ (destructuring-bind (back end beg front) skeleton-positions
+ ;; TODO: Find a way to trap invalid-parent signals from
+ ;; make-region and undo the skeleton insertion.
+ (let ((match-submode (plist-get class :match-submode))
+ (match-face (plist-get class :match-face))
+ (match-name (plist-get class :match-name))
+ (front-form (regexp-quote (buffer-substring front beg)))
+ (back-form (regexp-quote (buffer-substring end back)))
+ submode face name)
+ (setq submode
+ (mmm-modename->function
+ (if match-submode
+ (mmm-save-all (funcall match-submode front-form))
+ (plist-get class :submode))))
+ (setq face
+ (cond ((functionp match-face)
+ (mmm-save-all
+ (funcall match-face front-form)))
+ (match-face
+ (cdr (assoc front-form match-face)))
+ (t
+ (plist-get class :face))))
+ (setq name
+ (cond ((plist-get class :skel-name)
+ ;; Optimize the name to the user-supplied str
+ ;; if we are so instructed.
+ str)
+ ;; Call it if it is a function
+ ((functionp match-name)
+ (mmm-save-all (funcall match-name front-form)))
+ ;; Now we know it's a string, does it need to
+ ;; be formatted?
+ ((plist-get class :save-name)
+ ;; Yes. Haven't done a match before, so
+ ;; match the front regexp against the given
+ ;; form to format the string
+ (string-match (plist-get class :front)
+ front-form)
+ (mmm-format-matches match-name front-form))
+ (t
+ ;; No, just use it as-is
+ match-name)))
+ (mmm-make-region
+ submode beg end
+ :face face
+ :name name
+ :front front :back back
+ :match-front front-form :match-back back-form
+ :evaporation 'front
+;;; :beg-sticky (plist-get class :beg-sticky)
+;;; :end-sticky (plist-get class :end-sticky)
+ :beg-sticky t :end-sticky t
+ :creation-hook (plist-get class :creation-hook))
+ (mmm-enable-font-lock submode)))
+ ;; Now get rid of intermediate undo boundaries, so that the entire
+ ;; insertion can be undone as one action. This should really be
+ ;; skeleton's job, but it doesn't do it.
+ (setq undo buffer-undo-list)
+ (while (not (eq (cdr undo) old-undo))
+ (when (eq (cadr undo) nil)
+ (setcdr undo (cddr undo)))
+ (setq undo (cdr undo)))))))
+
+(defun mmm-get-insertion-spec (key &optional classlist)
+ "Get the insertion info for KEY from all classes in CLASSLIST.
+Return \(CLASS SKEL STR) where CLASS is the class spec a match was
+found in, SKEL is the skeleton to insert, and STR is the argument.
+CLASSLIST defaults to the return value of `mmm-get-all-classes',
+including global classes."
+ (loop for classname in (or classlist (mmm-get-all-classes t))
+ for class = (mmm-get-class-spec classname)
+ for inserts = (plist-get class :insert)
+ for skel = (cddr (assoc key inserts))
+ with str
+ ;; If SKEL is a dotted pair, it means call another key's
+ ;; insertion spec with an argument.
+ unless (consp (cdr skel))
+ do (setq str (cdr skel)
+ skel (cddr (assoc (car skel) inserts)))
+ if skel return (list class skel str)
+ ;; If we have a group class, recurse.
+ if (plist-get class :classes)
+ if (mmm-get-insertion-spec key it)
+ return it))
+
+;;}}}
+;;{{{ Help on Insertion
+
+(defun mmm-insertion-help ()
+ "Display help on currently available MMM insertion commands."
+ (interactive)
+ (with-output-to-temp-buffer "*Help*"
+ (princ "Available MMM Mode Insertion Commands:\n")
+ (princ "Key Inserts\n")
+ (princ "--- -------\n\n")
+ (mapcar #'mmm-display-insertion-key
+ (mmm-get-all-insertion-keys))))
+
+(defun mmm-display-insertion-key (spec)
+ "Print an insertion binding to standard output.
+SPEC should be \(KEY NAME ...) where KEY is an insertion key and NAME
+is a symbol naming the insertion."
+ (let* ((str (make-string 16 ?\ ))
+ ;; This gets us a dotted list, because of the way insertion
+ ;; keys are specified.
+ (key (append mmm-insert-modifiers (car spec)))
+ (lastkey (nthcdr (max (1- (safe-length key)) 0) key)))
+ ;; Now we make it a true list
+ (if (consp key)
+ (setcdr lastkey (list (cdr lastkey)))
+ (setq key (list key)))
+ ;; Get the spacing right
+ (store-substring str 0
+ (key-description
+ (apply #'vector (append mmm-mode-prefix-key (list key)))))
+ (princ str)
+ ;; Now print the binding symbol
+ (princ (cadr spec))
+ (princ "\n")))
+
+(defun mmm-get-all-insertion-keys (&optional classlist)
+ "Return an alist of all currently available insertion keys.
+Elements look like \(KEY NAME ...) where KEY is an insertion key and
+NAME is a symbol naming the insertion."
+ (remove-duplicates
+ (loop for classname in (or classlist (mmm-get-all-classes t))
+ for class = (mmm-get-class-spec classname)
+ append (plist-get class :insert) into keys
+ ;; If we have a group class, recurse.
+ if (plist-get class :classes)
+ do (setq keys (append keys (mmm-get-all-insertion-keys it)))
+ finally return keys)
+ :test #'equal
+ :key #'(lambda (x) (cons (car x) (cadr x)))
+ :from-end t))
+
+;;}}}
+
+;;{{{ Auto Insertion (copied from interactive session);-COM-
+;-COM-
+;-COM-;; Don't use `mmm-ify-region' of course. And rather than having
+;-COM-;; classes define their own functions, we should have them pass a
+;-COM-;; skeleton as an attribute. Then our insert function can turn off
+;-COM-;; after-change hooks and add the submode region afterward.
+;-COM-
+;-COM-(define-skeleton mmm-see-inline
+;-COM- "" nil
+;-COM- -1 @ " " _ " " @ "%>"
+;-COM- '(apply #'mmm-ify-region 'cperl-mode (reverse skeleton-positions)))
+;-COM-
+;-COM-(define-skeleton mmm-see-other
+;-COM- "" nil
+;-COM- @ ";\n" _ "\n" @ "<%/" str ">"
+;-COM- '(apply #'mmm-ify-region 'cperl-mode (reverse skeleton-positions)))
+;-COM-
+;-COM-(make-local-hook 'after-change-functions)
+;-COM-(add-hook 'after-change-functions 'mmm-detect t)
+;-COM-
+;-COM-(defun mmm-detect (beg end length)
+;-COM- (when (mmm-looking-back-at "<% ")
+;-COM- (mmm-see-inline))
+;-COM- (when (mmm-looking-back-at "<%\\(\\w+\\)>")
+;-COM- (mmm-see-other (match-string 1))))
+;-COM-
+;;}}}
+
+(provide 'mmm-cmds)
+
+;;; mmm-cmds.el ends here
--- /dev/null
+;;; mmm-compat.el --- MMM Hacks for compatibility with other Emacsen
+
+;; Copyright (C) 2000 by Michael Abraham Shulman
+
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file provides a number of hacks that are necessary for MMM
+;; Mode to function in different Emacsen. MMM Mode is designed for
+;; FSF Emacs, but these hacks usually enable it to work
+;; almost perfectly in XEmacs 21.
+
+;;; Code:
+
+(require 'cl)
+
+;;{{{ Emacsen Detection
+
+(defvar mmm-xemacs (featurep 'xemacs)
+ "Whether we are running XEmacs.")
+
+;;}}}
+;;{{{ Regexp-Opt (XEmacs)
+
+;; As of XEmacs' xemacs-base package version 1.82,
+;; the regexp-opt API is compatible with GNU Emacs.
+(defalias 'mmm-regexp-opt 'regexp-opt)
+
+;;}}}
+;;{{{ Overlays (XEmacs)
+
+;; The main thing we use from FSF Emacs that XEmacs doesn't support
+;; are overlays. XEmacs uses extents instead, but comes with a package
+;; to emulate overlays.
+(when mmm-xemacs
+ ;; This does almost everything we need.
+ (require 'overlay))
+
+;; We also use a couple "special" overlay properties which have
+;; different names for XEmacs extents.
+(defvar mmm-evaporate-property
+ (if (featurep 'xemacs) 'detachable 'evaporate)
+ "The name of the overlay property controlling evaporation.")
+
+;; We don't use this any more, since its behavior is different in FSF
+;; and XEmacs: in the one it replaces the buffer's local map, but in
+;; the other it gets stacked on top of it. Instead we just set the
+;; buffer's local map temporarily.
+;;;(defvar mmm-keymap-property
+;;; (if (featurep 'xemacs) 'keymap 'local-map)
+;;; "The name of the overlay property controlling keymaps.")
+
+;;}}}
+;;{{{ Keymaps and Events (XEmacs)
+
+;; In XEmacs, keymaps are a primitive type, while in FSF Emacs, they
+;; are a list whose car is the symbol `keymap'. Among other things,
+;; this means that they handle default bindings differently.
+(defmacro mmm-set-keymap-default (keymap binding)
+ (if (featurep 'xemacs)
+ `(set-keymap-default-binding ,keymap ,binding)
+ `(define-key ,keymap [t] ,binding)))
+
+;; In XEmacs, events are a primitive type, while in FSF Emacs, they
+;; are represented by characters or vectors. We treat them as vectors.
+;; We can use `event-modifiers' in both Emacsen to extract the
+;; modifiers, but the function to extract the basic key is different.
+(defmacro mmm-event-key (event)
+ (if (featurep 'xemacs)
+ `(event-key ,event)
+ `(event-basic-type ,event)))
+
+;;}}}
+;;{{{ Skeleton (XEmacs)
+
+;; XEmacs' `skeleton' package doesn't provide `@' to record positions.
+(defvar skeleton-positions ())
+(defun mmm-fixup-skeleton ()
+ "Add `@' to `skeleton-further-elements' if XEmacs and not there.
+This makes `@' in skeletons act approximately like it does in FSF."
+ (and (featurep 'xemacs)
+ (defvar skeleton-further-elements ())
+ (not (assoc '@ skeleton-further-elements))
+ (add-to-list 'skeleton-further-elements
+ '(@ ''(push (point) skeleton-positions)))))
+
+;;}}}
+;;{{{ Make Temp Buffers (XEmacs)
+
+(defmacro mmm-make-temp-buffer (buffer name)
+ "Return a buffer with name based on NAME including the text of BUFFER.
+This text should not be modified."
+ (if (fboundp 'make-indirect-buffer)
+ `(make-indirect-buffer ,buffer (generate-new-buffer-name ,name))
+ `(save-excursion
+ (set-buffer (generate-new-buffer ,name))
+ (insert-buffer ,buffer)
+ (current-buffer))))
+
+(provide 'mmm-compat)
+
+;;; mmm-compat.el ends here
--- /dev/null
+;;; mmm-cweb.el --- MMM submode class for CWeb programs
+
+;; Copyright (C) 2001 by Alan Shutko
+
+;; Author: Alan Shutko <ats@acm.org>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file contains the definition of an MMM Mode submode class for
+;; editing CWeb programs.
+
+;;; Code:
+
+(require 'mmm-compat)
+(require 'mmm-vars)
+(require 'mmm-auto)
+
+(defvar mmm-cweb-section-tags
+ '("@ " "@*"))
+
+(defvar mmm-cweb-section-regexp
+ (concat "^" (mmm-regexp-opt mmm-cweb-section-tags t)))
+
+(defvar mmm-cweb-c-part-tags
+ '("@c" "@>=" "@>+=" "@p"))
+
+(defvar mmm-cweb-c-part-regexp
+ (concat (mmm-regexp-opt mmm-cweb-c-part-tags t)))
+
+(defun mmm-cweb-in-limbo (pos)
+ "Check to see if POS is in limbo, ie before any cweb sections."
+ (save-match-data
+ (save-excursion
+ (goto-char pos)
+ (not (re-search-backward mmm-cweb-section-regexp nil t)))))
+
+(defun mmm-cweb-verify-brief-c ()
+ "Verify function for cweb-brief-c class.
+Checks whether the match is in limbo."
+ (not (mmm-cweb-in-limbo (match-beginning 0))))
+
+(mmm-add-group
+ 'cweb
+ `(
+ (cweb-c-part
+ :submode c-mode
+ :front ,mmm-cweb-c-part-regexp
+ :back ,mmm-cweb-section-regexp)
+ (cweb-label
+ :submode tex-mode
+ :front "@<"
+ :back "@>"
+ :face mmm-comment-submode-face
+ :insert ((?l cweb-label nil @ "@<" @ "@>")))
+ (cweb-brief-c
+ :submode c-mode
+ :front "[^\\|]\\(|\\)[^|]"
+ :front-match 1
+ :front-verify mmm-cweb-verify-brief-c
+; :front-offset -1
+ :back "[^\\|]\\(|\\)"
+ :back-match 1
+; :back-offset 1
+ :end-not-begin t
+ :insert ((?| cweb-c-in-tex nil "|" @ "|")))
+ (cweb-comment
+ :submode tex-mode
+ :front "/[*]"
+ :back "[*]/"
+ :face mmm-comment-submode-face)
+))
+
+;; (add-to-list 'mmm-mode-ext-classes-alist
+;; '(plain-tex-mode "\\.w\\'" cweb))
+;; (add-to-list 'mmm-mode-ext-classes-alist
+;; '(latex-mode "\\.w\\'" cweb))
+;; (add-to-list 'auto-mode-alist '("\\.w\\'" . tex-mode))
+
+(provide 'mmm-cweb)
+
+;;; mmm-cweb.el ends here
--- /dev/null
+;;; mmm-erb.el --- ERB templates editing support
+
+;; Copyright (C) 2012, 2013 by Dmitry Gutov
+
+;; Author: Dmitry Gutov <dgutov@yandex.ru>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file contains definitions of ERB and EJS submode classes, and well as
+;; support functions for proper indentation.
+
+;; Usage:
+
+;; (require 'mmm-auto)
+
+;; (setq mmm-global-mode 'auto)
+
+;; (mmm-add-mode-ext-class 'html-erb-mode "\\.html\\.erb\\'" 'erb)
+;; (mmm-add-mode-ext-class 'html-erb-mode "\\.jst\\.ejs\\'" 'ejs)
+;; (mmm-add-mode-ext-class 'html-erb-mode nil 'html-js)
+;; (mmm-add-mode-ext-class 'html-erb-mode nil 'html-css)
+
+;; (add-to-list 'auto-mode-alist '("\\.html\\.erb\\'" . html-erb-mode))
+;; (add-to-list 'auto-mode-alist '("\\.jst\\.ejs\\'" . html-erb-mode))
+
+;; Optional settings:
+
+;; (setq mmm-submode-decoration-level 2
+;; mmm-parse-when-idle t)
+
+;; nXML as primary mode (supports only JS and CSS subregions):
+
+;; (mmm-add-mode-ext-class 'nxml-web-mode nil 'html-js)
+;; (mmm-add-mode-ext-class 'nxml-web-mode nil 'html-css)
+
+;; (add-to-list 'auto-mode-alist '("\\.xhtml\\'" . nxml-web-mode))
+
+;;; Code:
+
+(require 'sgml-mode)
+(eval-when-compile (require 'cl))
+(require 'mmm-vars)
+(require 'mmm-region)
+
+(mmm-add-classes
+ '((erb :submode ruby-mode :front "<%[#=]?" :back "-?%>"
+ :match-face (("<%#" . mmm-comment-submode-face)
+ ("<%=" . mmm-output-submode-face)
+ ("<%" . mmm-code-submode-face))
+ :insert ((?% erb-code nil @ "<%" @ " " _ " " @ "%>" @)
+ (?# erb-comment nil @ "<%#" @ " " _ " " @ "%>" @)
+ (?= erb-expression nil @ "<%=" @ " " _ " " @ "%>" @))
+ :creation-hook mmm-erb-mark-as-special)
+ (ejs :submode js-mode :front "<%[#=]?" :back "-?%>"
+ :match-face (("<%#" . mmm-comment-submode-face)
+ ("<%=" . mmm-output-submode-face)
+ ("<%" . mmm-code-submode-face))
+ :insert ((?% ejs-code nil @ "<%" @ " " _ " " @ "%>" @)
+ (?# ejs-comment nil @ "<%#" @ " " _ " " @ "%>" @)
+ (?= ejs-expression nil @ "<%=" @ " " _ " " @ "%>" @))
+ :creation-hook mmm-erb-mark-as-special)))
+
+(defun mmm-erb-mark-as-special ()
+ "Hook function to run in ERB and EJS tag regions."
+ (overlay-put mmm-current-overlay 'mmm-special-tag t))
+
+;;;###autoload
+(define-derived-mode html-erb-mode html-mode "ERB-HTML"
+ (setq sgml-unclosed-tags nil) ; Simplifies indentation logic.
+ (set (make-local-variable 'mmm-indent-line-function) 'mmm-erb-indent-line)
+ (add-hook 'mmm-after-syntax-propertize-functions
+ 'html-erb-after-syntax-propertize nil t))
+
+(defun html-erb-after-syntax-propertize (overlay mode beg end)
+ (when overlay
+ (with-silent-modifications
+ (funcall
+ (syntax-propertize-rules ("<\\|>" (0 ".")))
+ beg end))))
+
+(defun mmm-erb-indent-line ()
+ "Indent the current line intelligently."
+ (interactive)
+ (let ((offset (- (current-column) (current-indentation))))
+ (back-to-indentation)
+ (mmm-update-submode-region)
+ (if (and mmm-current-overlay mmm-current-submode
+ (< (overlay-start mmm-current-overlay) (point-at-bol)))
+ ;; Region starts before the current line (and contains indentation).
+ ;; If it starts on the current line, then either first part of the line
+ ;; is in primary mode, or we're on the first line of a script or style
+ ;; tag contents. In the latter case, better to also indent it according
+ ;; to the primary mode (as text): `js-indent-line' ignores narrowing,
+ ;; gets confused by the angle bracket on the previous line and thus
+ ;; breaks our "top level" heuristic.
+ (mmm-erb-indent-line-submode)
+ (mmm-erb-indent-line-primary))
+ (when (> offset 0) (forward-char offset))))
+
+(defun mmm-erb-indent-line-submode ()
+ "Indent line within a submode."
+ (let (added-whitespace)
+ (if (<= (overlay-end mmm-current-overlay)
+ (save-excursion (back-to-indentation) (point)))
+ ;; We're at a closing tag.
+ (mmm-erb-indent-to-region-start)
+ (save-restriction
+ (save-excursion
+ (goto-char (overlay-start mmm-current-overlay))
+ (when (not (looking-at "^\\|\\s-*$"))
+ ;; Submode region has text on the same line as the opening tag,
+ ;; pad it with whitespace to make the following lines line up.
+ (setq added-whitespace (current-column))
+ (insert-char ?\s added-whitespace)))
+ (narrow-to-region (overlay-start mmm-current-overlay)
+ (overlay-end mmm-current-overlay))
+ (funcall (mmm-erb-orig-indent-function mmm-current-submode))
+ (when added-whitespace
+ ;; Remove the padding.
+ (save-excursion
+ (goto-char (overlay-start mmm-current-overlay))
+ (delete-char added-whitespace))))
+ ;; If submode indent function moved us to bol,
+ ;; we're on the top level, indent according to the primary mode.
+ (when (zerop (current-indentation))
+ (mmm-erb-indent-to-region-start
+ (mmm-erb-indent-offset mmm-primary-mode))))))
+
+(defun mmm-erb-indent-to-region-start (&optional additional-offset)
+ "Indent line to match start of region, possibly adding ADDITIONAL-OFFSET."
+ (let ((indent (current-indentation)))
+ (indent-line-to
+ (save-excursion
+ (goto-char (1- (overlay-start mmm-current-overlay)))
+ (+ (current-indentation)
+ (or additional-offset 0))))))
+
+(defun mmm-erb-indent-line-primary ()
+ "Indent line in primary mode."
+ (let* ((here (point))
+ ;; Go before previous line's tag.
+ (start (progn (forward-line -1)
+ (back-to-indentation)
+ (let ((lcon (sgml-lexical-context)))
+ (when (eq (car lcon) 'tag)
+ ;; Tag spreads several lines.
+ (goto-char (cdr lcon))
+ (back-to-indentation)))
+ (point)))
+ (regions (mmm-regions-in start here))
+ (n 0))
+ ;; Collect indent modifier depending on type of tags.
+ (loop for region in regions
+ for type = (mmm-erb-scan-region region)
+ when type do
+ (if (eq type 'close)
+ (when (plusp n) (decf n))
+ (incf n (if (eq type 'close) 0 1))))
+ (let ((eol (progn (goto-char here) (end-of-line 1) (point))))
+ ;; Look for "else" and "end" instructions to adjust modifier.
+ ;; If a block start instruction comes first, abort.
+ (loop for region in (mmm-regions-in here eol)
+ for type = (mmm-erb-scan-region region)
+ until (eq type 'open)
+ when (memq type '(middle close)) do (decf n)))
+ (goto-char here)
+ (funcall (mmm-erb-orig-indent-function mmm-primary-mode))
+ (let* ((indent (current-indentation))
+ (indent-step (mmm-erb-indent-offset mmm-primary-mode)))
+ (indent-line-to (+ indent (if n (* indent-step n) 0))))))
+
+(defun mmm-erb-scan-region (region)
+ (when region ; Can be nil if a line is empty, for example.
+ (destructuring-bind (submode beg end ovl) region
+ (let ((scan-fn (plist-get '(ruby-mode mmm-erb-scan-erb
+ js-mode mmm-erb-scan-ejs)
+ submode)))
+ (and scan-fn
+ (overlay-get ovl 'mmm-special-tag)
+ (save-excursion
+ (goto-char beg)
+ (skip-syntax-forward "-")
+ (funcall scan-fn end)))))))
+
+(defconst mmm-erb-ruby-close-re "\\<end\\>\\|}"
+ "Regexp to match the end of a Ruby block.")
+
+(defun mmm-erb-scan-erb (limit)
+ (cond ((looking-at "\\(?:if\\|unless\\|for\\|while\\)\\b") 'open)
+ ((looking-at "\\(?:else\\|elsif\\)\\b") 'middle)
+ ((looking-at mmm-erb-ruby-close-re) 'close)
+ ((and (re-search-forward (concat "\\(?: +do +\\| *{ *\\)"
+ "\\(?:|[A-Za-z0-9_, ]*|\\)? *")
+ limit t)
+ (let ((pt (point)))
+ (not (when (< pt limit)
+ (goto-char limit)
+ (skip-syntax-backward "-")
+ (looking-back mmm-erb-ruby-close-re pt)))))
+ 'open)))
+
+(defun mmm-erb-scan-ejs (limit)
+ (cond ((looking-at "\\(?:if\\|for\\|while\\)\\b") 'open)
+ ((looking-at "} *else\\b") 'middle)
+ ((looking-at "}") 'close)
+ ((re-search-forward " *{ *" limit t) 'open)))
+
+(defun mmm-erb-orig-indent-function (mode)
+ (get mode 'mmm-indent-line-function))
+
+(defvar mmm-erb-offset-var-alist
+ '((html-erb-mode . sgml-basic-offset)
+ (nxml-web-mode . nxml-child-indent)))
+
+(defun mmm-erb-indent-offset (mode)
+ (let ((name (cdr (assoc mode mmm-erb-offset-var-alist))))
+ (when name (symbol-value name))))
+
+;;;###autoload
+(define-derived-mode nxml-web-mode nxml-mode "nXML-Web"
+ (set (make-local-variable 'mmm-indent-line-function) 'mmm-erb-indent-line))
+
+(provide 'mmm-erb)
+
+;;; mmm-erb.el ends here
--- /dev/null
+;;; mmm-mason.el --- MMM submode class for Mason components
+
+;; Copyright (C) 2000 by Michael Abraham Shulman
+
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file contains the definition of an MMM Mode submode class for
+;; editing Mason components. See the file README.Mason for more
+;; details.
+
+;;; Code:
+
+(require 'mmm-compat)
+(require 'mmm-vars)
+(require 'mmm-auto)
+
+;;{{{ Perl Tags
+
+(defvar mmm-mason-perl-tags
+ '("perl" "init" "cleanup" "once" "filter" "shared"
+ "perl_init" "perl_cleanup" "perl_once" "perl_filter"))
+
+(defvar mmm-mason-pseudo-perl-tags
+ '("args" "perl_args" "attr" "flags"))
+
+(defvar mmm-mason-non-perl-tags
+ '("doc" "perl_doc" "text" "perl_text" "def" "perl_def" "method"))
+
+(defvar mmm-mason-perl-tags-regexp
+ (concat "<%" (mmm-regexp-opt mmm-mason-perl-tags t) ">")
+ "Matches tags beginning Mason sections containing Perl code.
+Saves the name of the tag matched.")
+
+(defvar mmm-mason-pseudo-perl-tags-regexp
+ (concat "<%" (mmm-regexp-opt mmm-mason-pseudo-perl-tags t) ">")
+ "Match tags beginning Mason sections that look like Perl but aren't.
+Saves the name of the tag matched.")
+
+(defvar mmm-mason-tag-names-regexp
+ (regexp-opt (append mmm-mason-perl-tags mmm-mason-non-perl-tags) t)
+ "Matches any Mason tag name after the \"<%\". Used to verify that a
+\"<%\" sequence starts an inline section.")
+
+(defun mmm-mason-verify-inline ()
+ (not (looking-at mmm-mason-tag-names-regexp)))
+
+;;}}}
+;;{{{ Add Classes
+
+(mmm-add-group
+ 'mason
+ `((mason-text
+ :submode nil
+ :front "<%text>"
+ :back "</%text>"
+ :insert ((?t mason-<%text> nil @ "<%text>" @ "\n"
+ _ "\n" @ "</%text>" @)))
+ (mason-doc
+ :submode text-mode
+ :face mmm-comment-submode-face
+ :front "<%doc>"
+ :back "</%doc>"
+ :face nil
+ :insert ((?d mason-<%doc> nil @ "<%doc>" @ "\n"
+ _ "\n" @ "</%doc>" @)))
+ (mason-perl
+ :submode perl
+ :match-face (("<%perl>" . mmm-code-submode-face)
+ ("<%init>" . mmm-init-submode-face)
+ ("<%cleanup>" . mmm-cleanup-submode-face)
+ ("<%once>" . mmm-init-submode-face)
+ ("<%filter>" . mmm-special-submode-face)
+ ("<%shared>" . mmm-init-submode-face))
+ :front ,mmm-mason-perl-tags-regexp
+ :back "</%~1>"
+ :save-matches 1
+ :match-name "~1"
+ :save-name 1
+ :insert ((?, mason-<%TAG> "Perl section: " @ "<%" str ">" @
+ ";\n" _ "\n" @ "</%" str ">" @)
+ (?< mason-<%TAG> ?, . nil)
+ (?p mason-<%perl> ?, . "perl")
+ (?i mason-<%init> ?, . "init")
+ (?c mason-<%cleanup> ?, . "cleanup")
+ (?o mason-<%once> ?, . "once")
+ (?l mason-<%filter> ?, . "filter")
+ (?s mason-<%shared> ?, . "shared")))
+ (mason-pseudo-perl
+ :submode perl
+ :face mmm-declaration-submode-face
+ :front ,mmm-mason-pseudo-perl-tags-regexp
+ :back "</%~1>"
+ :save-matches 1
+ :insert ((?. mason-pseudo-<%TAG> "Pseudo-perl section: " @ "<%" str ">" @
+ "\n" _ "\n" @ "</%" str ">" @)
+ (?> mason-pseudo-<%TAG> ?, . nil)
+ (?a mason-<%args> ?. . "args")
+ (?f mason-<%flags> ?. . "flags")
+ (?r mason-<%attr> ?. . "attr")))
+ (mason-inline
+ :submode perl
+ :face mmm-output-submode-face
+ :front "<%"
+ :front-verify mmm-mason-verify-inline
+ :back "%>"
+ :insert ((?% mason-<%-%> nil @ "<%" @ " " _ " " @ "%>" @)
+ (?5 mason-<%-%> ?% . nil)))
+ (mason-call
+ :submode perl
+ :face mmm-special-submode-face
+ :front "<&"
+ :back "&>"
+ :insert ((?& mason-<&-&> nil @ "<&" @ " " _ " " @ "&>" @)
+ (?7 mason-<&-&> ?% . nil)))
+ (mason-one-line-comment
+ :submode text-mode
+ :face mmm-comment-submode-face
+ :front "^%#"
+ :back "\n"
+ :insert ((?# mason-%-comment nil (mmm-mason-start-line)
+ @ "%" @ "# " _ @ '(mmm-mason-end-line) "\n" @)
+ (?3 mason-%-comment ?# . nil)))
+ (mason-one-line
+ :submode perl
+ :face mmm-code-submode-face
+ :front "^%"
+ :back "\n"
+ :insert ((return mason-%-line nil (mmm-mason-start-line)
+ @ "%" @ " " _ @ '(mmm-mason-end-line) "\n" @)))))
+
+;;}}}
+;;{{{ One-line Sections
+
+(defun mmm-mason-start-line ()
+ (if (bolp)
+ ""
+ "\n"))
+
+(defun mmm-mason-end-line ()
+ (if (eolp)
+ (delete-char 1)))
+
+;;}}}
+;;{{{ Set Mode Line
+
+(defun mmm-mason-set-mode-line ()
+ (setq mmm-buffer-mode-display-name "Mason"))
+(add-hook 'mmm-mason-class-hook 'mmm-mason-set-mode-line)
+
+;;}}}
+
+(provide 'mmm-mason)
+
+;;; mmm-mason.el ends here
--- /dev/null
+;;; mmm-mode-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
+\f
+;;;### (autoloads (nxml-web-mode html-erb-mode) "mmm-erb" "mmm-erb.el"
+;;;;;; (20891 59622 632249 639000))
+;;; Generated autoloads from mmm-erb.el
+
+(autoload 'html-erb-mode "mmm-erb" "\
+
+
+\(fn)" t nil)
+
+(autoload 'nxml-web-mode "mmm-erb" "\
+
+
+\(fn)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil nil ("mmm-auto.el" "mmm-class.el" "mmm-cmds.el"
+;;;;;; "mmm-compat.el" "mmm-cweb.el" "mmm-mason.el" "mmm-mode-pkg.el"
+;;;;;; "mmm-mode.el" "mmm-myghty.el" "mmm-noweb.el" "mmm-region.el"
+;;;;;; "mmm-rpm.el" "mmm-sample.el" "mmm-univ.el" "mmm-utils.el"
+;;;;;; "mmm-vars.el") (20891 59622 643765 210000))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; mmm-mode-autoloads.el ends here
--- /dev/null
+;;; mmm-mode.el --- Allow Multiple Major Modes in a buffer
+
+;; Copyright (C) 1999, 2004 by Michael Abraham Shulman
+;; Copyright (C) 2013 by Dmitry Gutov
+
+;; Emacs Lisp Archive Entry
+;; Package: mmm-mode
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
+;; Maintainer: Dmitry Gutov <dgutov@yandex.ru>
+;; URL: https://github.com/purcell/mmm-mode
+;; Keywords: convenience, faces, languages, tools
+;; Version: 0.5.1
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;;; MMM Mode is a minor mode that allows multiple major modes to
+;;; coexist in a single buffer. Refer to the documentation of the
+;;; function `mmm-mode' for more detailed information. This file
+;;; contains mode on/off functions and the mode keymap, but mostly
+;;; just loads all the subsidiary files.
+
+;;{{{ Parameter Naming
+
+;;; Since version 0.3.7, I've tried to use a uniform scheme for naming
+;;; parameters. Here's a brief summary.
+
+;;; BEG and END refer to the beginning and end of a region.
+;;; FRONT and BACK refer to the respective delimiters of a region.
+;;; FRONT- and BACK-OFFSET are the offsets from delimiter matches.
+;;; FRONT-BEG through BACK-END are the endings of the delimiters.
+;;; START and STOP bound actions, like searching, fontification, etc.
+
+;;}}}
+;;{{{ CL and Parameters
+
+;;; Keyword parameters can be nice because it makes it easier to see
+;;; what's getting passed as what. But I try not to use them in user
+;;; functions, because CL doesn't make good documentation strings.
+;;; Similarly, any hook or callback function can't take keywords,
+;;; since Emacs as a whole doesn't use them. And for small parameter
+;;; lists, they are overkill. So I use them only for a large number of
+;;; optional parameters, such as `mmm-make-region'.
+
+;;; An exception is the various submode class application functions,
+;;; which all take all their arguments as keywords, for consistency
+;;; and so the classes alist looks nice.
+
+;;; When using keyword arguments, defaults should *always* be supplied
+;;; in all arglists. (This pertains mostly to :start and :stop
+;;; arguments, usually defaulting to (point-min) and (point-max)
+;;; respectively.) `mmm-save-keywords' should only be used for lists
+;;; with more than four arguments, such as in `mmm-ify-by-regexp'.
+
+;;; In general, while I have no qualms about using things from CL like
+;;; `mapl', `loop' and `destructuring-bind', I try not to use `defun*'
+;;; more than I have to. For one, it sometimes makes bad documentation
+;;; strings. Furthermore, to a `defun'ned function, a nil argument is
+;;; the same as no argument, so it will use its (manual) default, but
+;;; to a `defun*'ned function, a nil argument *is* the argument, so
+;;; any default specified in the arglist will be ignored. Confusion of
+;;; this type should be avoided when at all possible.
+
+;;}}}
+
+;;; Code:
+
+(require 'cl)
+;; If we don't load font-lock now, but it is loaded later, the
+;; necessary mmm-font-lock-* properties may not be there.
+(require 'font-lock)
+(require 'mmm-compat)
+(require 'mmm-utils)
+(require 'mmm-vars)
+(require 'mmm-auto)
+(require 'mmm-region)
+(require 'mmm-class)
+;; This file is set up to autoload by `mmm-auto.el'.
+;; (require 'mmm-cmds)
+(require 'mmm-univ)
+
+;;{{{ Toggle Function
+
+(defun mmm-mode (&optional arg)
+ "Minor mode to allow multiple major modes in one buffer.
+Without ARG, toggle MMM Mode. With ARG, turn MMM Mode on iff ARG is
+positive and off otherwise.
+
+Commands Available:
+\\<mmm-mode-map>
+\\{mmm-mode-map}
+
+BASIC CONCEPTS
+
+The idea of MMM Mode is to allow multiple major modes to coexist in
+the same buffer. There is one \"primary\" major mode that controls
+most of the buffer, and a number of \"submodes\" that each hold sway
+over certain regions. The submode regions are usually highlighted by
+a background color for ease of recognition. While the point is in a
+submode region, the following changes \(are supposed to) occur:
+
+1. The local keymap and the syntax table are that of the submode.
+2. The mode line changes to show what submode region is active.
+3. The major mode menu and mouse popup menu are that of the submode.
+4. Some local variables of the submode shadow the default mode's.
+5. Font-lock fontifies correctly for the submode.
+6. Indentation function dispatches to the appropriate submode.
+
+For further information, including installation and configuration
+instructions, see the Info file mmm.info which is included with the
+distribution of MMM Mode. Many of MMM's configuration variables are
+available through M-x customize-group RET mmm."
+ (interactive "P")
+ (if (if arg (> (prefix-numeric-value arg) 0) (not mmm-mode))
+ (mmm-mode-on)
+ (mmm-mode-off)))
+
+(add-to-list 'minor-mode-alist (list 'mmm-mode mmm-mode-string))
+
+;;}}}
+;;{{{ Mode On
+
+(defun mmm-mode-on ()
+ "Turn on MMM Mode. See `mmm-mode'."
+ (interactive)
+ ;; This function is called from mode hooks, so we need to make sure
+ ;; we're not in a temporary buffer. We don't need to worry about
+ ;; recursively ending up in ourself, however, since by that time the
+ ;; variable `mmm-mode' will already be set.
+ (mmm-valid-buffer
+ (unless mmm-mode
+ (setq mmm-primary-mode major-mode)
+ (when (fboundp 'c-make-styles-buffer-local)
+ (c-make-styles-buffer-local t))
+ (mmm-update-mode-info major-mode)
+ (setq mmm-region-saved-locals-for-dominant
+ ;; FIXME: Neither is defined in recent Emacs.
+ (list* (list 'font-lock-cache-state nil)
+ (list 'font-lock-cache-position (make-marker))
+ (copy-tree (cdr (assq major-mode mmm-region-saved-locals-defaults)))))
+ ;; Without the next line, the (make-marker) above gets replaced
+ ;; with the starting value of nil, and all comes to naught.
+ (mmm-set-local-variables major-mode nil)
+ (mmm-add-hooks)
+ (mmm-fixup-skeleton)
+ (make-local-variable 'font-lock-fontify-region-function)
+ (setq font-lock-fontify-region-function 'mmm-fontify-region)
+ (set (make-local-variable (if (boundp 'syntax-begin-function) ; Emacs >= 23
+ 'syntax-begin-function
+ 'font-lock-beginning-of-syntax-function))
+ 'mmm-beginning-of-syntax)
+ (set (make-local-variable 'syntax-propertize-function)
+ 'mmm-syntax-propertize-function)
+ (set (make-local-variable 'indent-line-function) mmm-indent-line-function)
+ (setq mmm-mode t)
+ (condition-case err
+ (mmm-apply-all)
+ (mmm-error
+ ;; Complain, but don't die, since we want files to go ahead
+ ;; and be opened anyway, and the mode to go ahead and be
+ ;; turned on. Should we delete all previously made submode
+ ;; regions when we find an invalid one?
+ (message "%s" (error-message-string err))))
+ (run-hooks 'mmm-mode-hook)
+ (mmm-run-major-hook))))
+
+;;}}}
+;;{{{ Mode Off
+
+(defun mmm-mode-off ()
+ "Turn off MMM Mode. See `mmm-mode'."
+ (interactive)
+ (when mmm-mode
+ (mmm-remove-hooks)
+ (mmm-clear-overlays)
+ (mmm-clear-history)
+ (mmm-clear-mode-ext-classes)
+ (mmm-clear-local-variables)
+ (mmm-update-submode-region)
+ (setq font-lock-fontify-region-function
+ (get mmm-primary-mode 'mmm-fontify-region-function))
+ (set (if (boundp 'syntax-begin-function) ; Emacs >= 23
+ 'syntax-begin-function
+ 'font-lock-beginning-of-syntax-function)
+ (get mmm-primary-mode 'mmm-beginning-of-syntax-function))
+ (mmm-update-font-lock-buffer)
+ (mmm-refontify-maybe)
+ (setq mmm-mode nil)
+ ;; Restore the mode line
+ (setq mmm-primary-mode-display-name nil
+ mmm-buffer-mode-display-name nil)
+ (mmm-set-mode-line)))
+
+;;}}}
+;;{{{ Mode Keymap
+
+(defvar mmm-mode-map (make-sparse-keymap)
+ "Keymap for MMM Minor Mode.")
+
+(defvar mmm-mode-prefix-map (make-sparse-keymap)
+ "Keymap for MMM Minor Mode after `mmm-mode-prefix-key'.")
+
+(defvar mmm-mode-menu-map (make-sparse-keymap "MMM")
+ "Keymap for MMM Minor Mode menu.")
+
+(defun mmm-define-key (key binding &optional keymap)
+ (define-key (or keymap mmm-mode-prefix-map)
+ (vector (append mmm-command-modifiers (list key)))
+ binding))
+
+(when mmm-use-old-command-keys
+ (mmm-use-old-command-keys))
+
+(mmm-define-key ?c 'mmm-ify-by-class)
+(mmm-define-key ?x 'mmm-ify-by-regexp)
+(mmm-define-key ?r 'mmm-ify-region)
+
+(mmm-define-key ?b 'mmm-parse-buffer)
+(mmm-define-key ?g 'mmm-parse-region)
+(mmm-define-key ?% 'mmm-parse-block)
+(mmm-define-key ?5 'mmm-parse-block)
+
+(mmm-define-key ?k 'mmm-clear-current-region)
+(mmm-define-key ?\ 'mmm-reparse-current-region)
+(mmm-define-key ?e 'mmm-end-current-region)
+
+(mmm-define-key ?z 'mmm-narrow-to-submode-region)
+
+;; This one is exact, since C-h is (usually) already used for help.
+(define-key mmm-mode-prefix-map [?h] 'mmm-insertion-help)
+
+;; Default bindings to do insertion (dynamic)
+(mmm-set-keymap-default mmm-mode-prefix-map 'mmm-insert-region)
+
+;; Set up the prefix help command, since otherwise the default binding
+;; overrides it.
+(define-key mmm-mode-prefix-map (vector help-char) prefix-help-command)
+
+;; And put it all onto the prefix key
+(define-key mmm-mode-map mmm-mode-prefix-key mmm-mode-prefix-map)
+
+;; Order matters for the menu bar.
+(define-key mmm-mode-menu-map [off]
+ '("MMM Mode Off" . mmm-mode-off))
+(define-key mmm-mode-menu-map [sep0] '(menu-item "----"))
+
+(define-key mmm-mode-menu-map [clhist]
+ '("Clear History" . mmm-clear-history))
+(define-key mmm-mode-menu-map [end]
+ '("End Current" . mmm-end-current-region))
+(define-key mmm-mode-menu-map [clear]
+ '("Clear Current" . mmm-clear-current-region))
+(define-key mmm-mode-menu-map [reparse]
+ '("Reparse Current" . mmm-reparse-current-region))
+
+(define-key mmm-mode-menu-map [sep10] '(menu-item "----"))
+
+(define-key mmm-mode-menu-map [ins-help]
+ '("List Insertion Keys" . mmm-insertion-help))
+
+(define-key mmm-mode-menu-map [sep20] '(menu-item "----"))
+
+(define-key mmm-mode-menu-map [region]
+ '(menu-item "MMM-ify Region" mmm-ify-region :enable mark-active))
+(define-key mmm-mode-menu-map [regexp]
+ '("MMM-ify by Regexp" . mmm-ify-by-regexp))
+(define-key mmm-mode-menu-map [class]
+ '("Apply Submode Class" . mmm-ify-by-class))
+
+(define-key mmm-mode-menu-map [sep30] '(menu-item "----"))
+
+(define-key mmm-mode-menu-map [parse-region]
+ '(menu-item "Parse Region" mmm-parse-region :enable mark-active))
+(define-key mmm-mode-menu-map [parse-buffer]
+ '("Parse Buffer" . mmm-parse-buffer))
+(define-key mmm-mode-menu-map [parse-block]
+ '("Parse Block" . mmm-parse-block))
+
+(define-key mmm-mode-map [menu-bar mmm] (cons "MMM" mmm-mode-menu-map))
+
+(add-to-list 'minor-mode-map-alist (cons 'mmm-mode mmm-mode-map))
+
+;;}}}
+
+(provide 'mmm-mode)
+
+;;; mmm-mode.el ends here
--- /dev/null
+;;; mmm-myghty.el --- MMM submode class for Myghty components
+;;;
+
+;; Copyright (C) 2000 by Michael Abraham Shulman
+;; Copyright (C) 2004 by Ben Bangert
+
+;; Original Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
+
+;; Based on mmm-mason.el, trivial changes by Ben Bangert
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;;; I went to the hard (sarcasm) effort of applying two global
+;;; search/replaces, and adding a few keywords for additional
+;;; blocks that Myghty introduced. Many thanks to Michael for writing
+;;; the mmm-mason without which I would never have found the time
+;;; to patch up for Myghty.
+
+;;; Code:
+
+(require 'mmm-compat)
+(require 'mmm-vars)
+(require 'mmm-auto)
+
+;;{{{ Python Tags
+
+(defvar mmm-myghty-python-tags
+ '("python" "init" "cleanup" "once" "filter" "shared" "global"
+ "threadlocal" "requestlocal"
+ "python_init" "python_cleanup" "python_once" "python_filter"))
+
+(defvar mmm-myghty-pseudo-python-tags
+ '("args" "python_args" "attr" "flags"))
+
+(defvar mmm-myghty-non-python-tags
+ '("doc" "python_doc" "text" "python_text" "def" "python_def" "method"))
+
+(defvar mmm-myghty-python-tags-regexp
+ (concat "<%" (mmm-regexp-opt mmm-myghty-python-tags t) ">")
+ "Matches tags beginning Myghty sections containing Python code.
+Saves the name of the tag matched.")
+
+(defvar mmm-myghty-pseudo-python-tags-regexp
+ (concat "<%" (mmm-regexp-opt mmm-myghty-pseudo-python-tags t) ">")
+ "Match tags beginning Myghty sections that look like Python but aren't.
+Saves the name of the tag matched.")
+
+(defvar mmm-myghty-tag-names-regexp
+ (regexp-opt (append mmm-myghty-python-tags mmm-myghty-non-python-tags) t)
+ "Matches any Myghty tag name after the \"<%\". Used to verify that a
+\"<%\" sequence starts an inline section.")
+
+(defun mmm-myghty-verify-inline ()
+ (not (looking-at mmm-myghty-tag-names-regexp)))
+
+;;}}}
+;;{{{ Add Classes
+
+(mmm-add-group
+ 'myghty
+ `((myghty-text
+ :submode nil
+ :front "<%text>"
+ :back "</%text>"
+ :insert ((?t myghty-<%text> nil @ "<%text>" @ "\n"
+ _ "\n" @ "</%text>" @)))
+ (myghty-doc
+ :submode text-mode
+ :face mmm-comment-submode-face
+ :front "<%doc>"
+ :back "</%doc>"
+ :face nil
+ :insert ((?d myghty-<%doc> nil @ "<%doc>" @ "\n"
+ _ "\n" @ "</%doc>" @)))
+ (myghty-python
+ :submode python
+ :match-face (("<%python>" . mmm-code-submode-face)
+ ("<%init>" . mmm-init-submode-face)
+ ("<%cleanup>" . mmm-cleanup-submode-face)
+ ("<%once>" . mmm-init-submode-face)
+ ("<%global>" . mmm-init-submode-face)
+ ("<%filter>" . mmm-special-submode-face)
+ ("<%shared>" . mmm-init-submode-face)
+ ("<%threadlocal>" . mmm-init-submode-face)
+ ("<%requestlocal>" . mmm-init-submode-face))
+ :front ,mmm-myghty-python-tags-regexp
+ :back "</%~1>"
+ :save-matches 1
+ :match-name "~1"
+ :save-name 1
+ :insert ((?, myghty-<%TAG> "Python section: " @ "<%" str ">" @
+ ";\n" _ "\n" @ "</%" str ">" @)
+ (?< myghty-<%TAG> ?, . nil)
+ (?p myghty-<%python> ?, . "python")
+ (?i myghty-<%init> ?, . "init")
+ (?c myghty-<%cleanup> ?, . "cleanup")
+ (?o myghty-<%once> ?, . "once")
+ (?g myghty-<%global> ?, . "global")
+ (?t myghty-<%threadlocal> ?, . "threadlocal")
+ (?e myghty-<%requestlocal> ?, . "requestlocal")
+ (?l myghty-<%filter> ?, . "filter")
+ (?s myghty-<%shared> ?, . "shared")))
+ (myghty-pseudo-python
+ :submode python
+ :face mmm-declaration-submode-face
+ :front ,mmm-myghty-pseudo-python-tags-regexp
+ :back "</%~1>"
+ :save-matches 1
+ :insert ((?. myghty-pseudo-<%TAG> "Pseudo-python section: " @ "<%" str ">" @
+ "\n" _ "\n" @ "</%" str ">" @)
+ (?> myghty-pseudo-<%TAG> ?, . nil)
+ (?a myghty-<%args> ?. . "args")
+ (?f myghty-<%flags> ?. . "flags")
+ (?r myghty-<%attr> ?. . "attr")))
+ (myghty-inline
+ :submode python
+ :face mmm-output-submode-face
+ :front "<%"
+ :front-verify mmm-myghty-verify-inline
+ :back "%>"
+ :insert ((?% myghty-<%-%> nil @ "<%" @ " " _ " " @ "%>" @)
+ (?5 myghty-<%-%> ?% . nil)))
+ (myghty-call
+ :submode python
+ :face mmm-special-submode-face
+ :front "<&"
+ :back "&>"
+ :insert ((?& myghty-<&-&> nil @ "<&" @ " " _ " " @ "&>" @)
+ (?7 myghty-<&-&> ?% . nil)))
+ (myghty-one-line-comment
+ :submode text-mode
+ :face mmm-comment-submode-face
+ :front "^%#"
+ :back "\n"
+ :insert ((?# myghty-%-comment nil (mmm-myghty-start-line)
+ @ "%" @ "# " _ @ '(mmm-myghty-end-line) "\n" @)
+ (?3 myghty-%-comment ?# . nil)))
+ (myghty-one-line
+ :submode python
+ :face mmm-code-submode-face
+ :front "^%"
+ :back "\n"
+ :insert ((return myghty-%-line nil (mmm-myghty-start-line)
+ @ "%" @ " " _ @ '(mmm-myghty-end-line) "\n" @)))))
+
+;;}}}
+;;{{{ One-line Sections
+
+(defun mmm-myghty-start-line ()
+ (if (bolp)
+ ""
+ "\n"))
+
+(defun mmm-myghty-end-line ()
+ (if (eolp)
+ (delete-char 1)))
+
+;;}}}
+;;{{{ Set Mode Line
+
+(defun mmm-myghty-set-mode-line ()
+ (setq mmm-buffer-mode-display-name "Myghty"))
+(add-hook 'mmm-myghty-class-hook 'mmm-myghty-set-mode-line)
+
+;;}}}
+
+(provide 'mmm-myghty)
+
+;;; mmm-myghty.el ends here
--- /dev/null
+;;; mmm-noweb.el --- MMM submode class for Noweb programs
+;;
+;; Copyright 2003, 2004 Joe Kelsey <joe@zircon.seattle.wa.us>
+;;
+;; The filling, completion and chunk motion commands either taken
+;; directly from or inspired by code in:
+;; noweb-mode.el - edit noweb files with GNU Emacs
+;; Copyright 1995 by Thorsten.Ohl @ Physik.TH-Darmstadt.de
+;; with a little help from Norman Ramsey <norman@bellcore.com>
+;;
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file contains the definition of an MMM Mode submode class for
+;; editing Noweb programs.
+;;
+;; FIXME: The more advanced features don't work: `mmm-name-at' and
+;; `mmm-syntax-region' are undefined. Need to dig around in the bug reports
+;; and/or discussions, wherever the code using them was submitted.
+
+;;; Code:
+
+(require 'cl)
+(require 'mmm-region)
+(require 'mmm-vars)
+(require 'mmm-mode)
+
+;;{{{ Variables
+
+(defvar mmm-noweb-code-mode 'fundamental-mode
+ "*Major mode for editing code chunks.
+This is set to FUNDAMENTAL-MODE by default, but you might want to change
+this in the Local Variables section of your file to something more
+appropriate, like C-MODE, FORTRAN-MODE, or even INDENTED-TEXT-MODE.")
+
+(defvar mmm-noweb-quote-mode nil
+ "*Major mode for quoted code chunks within documentation chunks.
+If nil, defaults to `mmm-noweb-code-mode', which see.")
+
+(defvar mmm-noweb-quote-string "quote"
+ "*String used to form quoted code submode region names.
+See `mmm-noweb-quote'.")
+
+(defvar mmm-noweb-quote-number 0
+ "*Starting value appended to `mmm-noweb-quote-string'.
+See `mmm-noweb-quote'.")
+
+(defvar mmm-noweb-narrowing nil
+ "*Narrow the region to the current pair of chunks.")
+
+;;}}}
+;;{{{ Support for mmm submode stuff
+
+(defun mmm-noweb-chunk (form)
+ "Return the noweb code mode chosen by the user.
+If the next 100 characters of the buffer contain a string of the form
+\"-*- MODE -*-\", then return MODE as the chosen mode, otherwise
+return the value of `mmm-noweb-code-mode'."
+ ;; Look for -*- mode -*- in the first two lines.
+ ;; 120 chars = 40 chars for #! + 80 chars for following line...
+ (if (re-search-forward "-\\*-\\s +\\(\\S-+\\)\\s +-\\*-" (+ (point) 120) t)
+ (let* ((string (match-string-no-properties 1))
+ (modestr (intern (if (string-match "mode\\'" string)
+ string
+ (concat string "-mode")))))
+ (or (mmm-ensure-modename modestr)
+ mmm-noweb-code-mode))
+ mmm-noweb-code-mode))
+
+(defun mmm-noweb-quote (form)
+ "Create a unique name for a quoted code region within a documentation chunk."
+ (or mmm-noweb-quote-mode
+ mmm-noweb-code-mode))
+
+(defun mmm-noweb-quote-name (form)
+ "Create a unique name for a quoted code region within a documentation chunk."
+ (setq mmm-noweb-quote-number (1+ mmm-noweb-quote-number))
+ (concat mmm-noweb-quote-string "-"
+ (number-to-string mmm-noweb-quote-number)))
+
+(defun mmm-noweb-chunk-name (form)
+ "Get the chunk name from FRONT-FORM."
+ (string-match "<<\\(.*\\)>>=" form)
+ (match-string-no-properties 1 form))
+
+;;}}}
+;;{{{ mmm noweb submode group
+
+;; We assume that the global document mode is latex or whatever, the
+;; user wants. This class controls the code chunk submodes. We use
+;; match-submode to either return the value in mmm-noweb-code-mode or to
+;; look at the first line of the chunk for a submode setting. We reset
+;; case-fold-search because chunk names are case sensitive. The front
+;; string identifies the chunk name between the <<>>. Since this is
+;; done, name-match can use the same functions as save-matches for back.
+;; Our insert skeleton places a new code chunk and the skel-name lets us
+;; optimize the skelton naming to use the inserted string.
+
+(mmm-add-group
+ 'noweb
+ '((noweb-chunk
+ :match-submode mmm-noweb-chunk
+ :case-fold-search nil
+ :front "^<<\\(.*\\)>>="
+ :match-name "~1"
+ :save-name 1
+ :front-offset (end-of-line 1)
+ :back "^@\\( \\|$\\|\\( %def .*$\\)\\)"
+ :insert ((?c noweb-code "Code Chunk Name: "
+ "\n" @ "<<" str ">>=" @ "\n" _ "\n" @ "@ " @ "\n"))
+ :skel-name t
+ )
+ (noweb-quote
+ :match-submode mmm-noweb-quote
+ :face mmm-special-submode-face
+ :front "\\[\\["
+; :name-match mmm-noweb-quote-name
+ :back "\\]\\]"
+ :insert ((?q noweb-quote nil @ "[[" @ _ @ "]]" @))
+ )
+ ))
+
+;;}}}
+;;{{{ Noweb regions
+
+(defun mmm-noweb-regions (start stop regexp &optional delim)
+ "Return a liat of regions of the form \(NAME BEG END) that exclude
+names which match REGEXP."
+ (let* ((remove-next nil)
+ (regions
+ (maplist #'(lambda (pos-list)
+ (if (cdr pos-list)
+ (if remove-next
+ (setq remove-next nil)
+ (let ((name (or (mmm-name-at (car pos-list) 'beg)
+ (symbol-name mmm-primary-mode))))
+ (if (and regexp (string-match regexp name) )
+ (progn
+ (setq remove-next t)
+ nil)
+ (list name
+ (car pos-list) (cadr pos-list)))))))
+ (mmm-submode-changes-in start stop t delim))))
+ ;; The above loop leaves lots of nils in the list...
+ ;; Removing them saves us from having to do the (last x 2)
+ ;; trick that mmm-regions-in does.
+ (setq regions (delq nil regions))))
+
+;;}}}
+;;{{{ Filling, etc
+
+(defun mmm-noweb-narrow-to-doc-chunk ()
+ "Narrow to the current doc chunk.
+The current chunk includes all quoted code chunks (i.e., \[\[...\]\]).
+This function is only valid when called with point in a doc chunk or
+quoted code chunk."
+ (interactive)
+ (let ((name (mmm-name-at (point))))
+ (if (or (null name) (string-match "^quote" name))
+ (let ((prev (cond
+ ((= (point) (point-min)) (point))
+ (t (cadar (last (mmm-noweb-regions (point-min) (point)
+ "^quote"))))))
+ (next (cond
+ ((= (point) (point-max)) (point))
+ (t (save-excursion
+ (goto-char (cadr
+ (cadr (mmm-noweb-regions (point)
+ (point-max)
+ "^quote"))))
+ (forward-line -1)
+ (point))))))
+ (narrow-to-region prev next)))))
+
+(defun mmm-noweb-fill-chunk (&optional justify)
+ "Fill the current chunk according to mode.
+Run `fill-region' on documentation chunks and `indent-region' on code
+chunks."
+ (interactive "P")
+ (save-restriction
+ (let ((name (mmm-name-at (point))))
+ (if (and name (not (string-match "^quote" name)))
+ (if (or indent-region-function indent-line-function)
+ (progn
+ (mmm-space-other-regions)
+ (indent-region (overlay-start mmm-current-overlay)
+ (overlay-end mmm-current-overlay) nil))
+ (error "No indentation functions defined in %s!" major-mode))
+ (progn
+ (mmm-word-other-regions)
+ (fill-paragraph justify)))
+ (mmm-undo-syntax-other-regions))))
+
+(defun mmm-noweb-fill-paragraph-chunk (&optional justify)
+ "Fill a paragraph in the current chunk."
+ (interactive "P")
+ (save-restriction
+ (let ((name (mmm-name-at (point))))
+ (if (and name (not (string-match "^quote" name)))
+ (progn
+ (mmm-space-other-regions)
+ (fill-paragraph justify))
+ (progn
+ (mmm-word-other-regions)
+ (fill-paragraph justify)))
+ (mmm-undo-syntax-other-regions))))
+
+(defun mmm-noweb-fill-named-chunk (&optional justify)
+ "Fill the region containing the named chunk."
+ (interactive "P")
+ (save-restriction
+ (let* ((name (or (mmm-name-at) (symbol-name mmm-primary-mode)))
+ (list (cdr (assoc name (mmm-names-alist (point-min) (point-max))))))
+ (if (or (string= name (symbol-name mmm-primary-mode))
+ (string-match "^quote" name))
+ (progn
+ (mmm-word-other-regions)
+ (do-auto-fill))
+ (progn
+ (mmm-space-other-regions)
+ (indent-region (caar list) (cadar (last list)) nil)))
+ (mmm-undo-syntax-other-regions))))
+
+(defun mmm-noweb-auto-fill-doc-chunk ()
+ "Replacement for `do-auto-fill'."
+ (save-restriction
+ (mmm-noweb-narrow-to-doc-chunk)
+ (mmm-word-other-regions)
+ (do-auto-fill)
+ (mmm-undo-syntax-other-regions)))
+
+(defun mmm-noweb-auto-fill-doc-mode ()
+ "Install the improved auto fill function, iff necessary."
+ (if auto-fill-function
+ (setq auto-fill-function 'mmm-noweb-auto-fill-doc-chunk)))
+
+(defun mmm-noweb-auto-fill-code-mode ()
+ "Install the default auto fill function, iff necessary."
+ (if auto-fill-function
+ (setq auto-fill-function 'do-auto-fill)))
+
+;;}}}
+;;{{{ Functions on named chunks
+
+(defun mmm-noweb-complete-chunk ()
+ "Try to complete the chunk name."
+ (interactive)
+ (let ((end (point))
+ (beg (save-excursion
+ (if (re-search-backward "<<"
+ (save-excursion
+ (beginning-of-line)
+ (point))
+ t)
+ (match-end 0)
+ nil))))
+ (if beg
+ (let* ((pattern (buffer-substring beg end))
+ (alist (mmm-names-alist (point-min) (point-max)))
+ (completion (try-completion pattern alist)))
+ (cond ((eq completion t))
+ ((null completion)
+ (message "Can't find completion for \"%s\"" pattern)
+ (ding))
+ ((not (string= pattern completion))
+ (delete-region beg end)
+ (insert completion)
+ (if (not (looking-at ">>"))
+ (insert ">>")))
+ (t
+ (message "Making completion list...")
+ (with-output-to-temp-buffer "*Completions*"
+ (display-completion-list
+ (all-completions pattern alist)))
+ (message "Making completion list...%s" "done"))))
+ (message "Not at chunk name..."))))
+
+(defvar mmm-noweb-chunk-history nil
+ "History for `mmm-noweb-goto-chunk'.")
+
+(defun mmm-noweb-goto-chunk ()
+ "Goto the named chunk."
+ (interactive)
+ (widen)
+ (let* ((completion-ignore-case t)
+ (alist (mmm-names-alist (point-min) (point-max)))
+ (chunk (completing-read
+ "Chunk: " alist nil t
+ (mmm-name-at (point))
+ mmm-noweb-chunk-history)))
+ (goto-char (caadr (assoc chunk alist)))))
+
+(defun mmm-noweb-goto-next (&optional cnt)
+ "Goto the continuation of the current chunk."
+ (interactive "p")
+ (widen)
+ (let ((name (mmm-name-at (point))))
+ (if name
+ (let ((list (cdr (assoc name (mmm-names-alist
+ (overlay-end mmm-current-overlay)
+ (point-max))))))
+ (if list
+ (goto-char (caar (nthcdr (1- cnt) list))))))))
+
+(defun mmm-noweb-goto-previous (&optional cnt)
+ "Goto the continuation of the current chunk."
+ (interactive "p")
+ (widen)
+ (let ((name (mmm-name-at (point))))
+ (if name
+ (let ((list (reverse
+ (cdr (assoc name
+ (mmm-names-alist (point-min)
+ (overlay-start
+ mmm-current-overlay)))))))
+ (if list
+ (goto-char (cadar (nthcdr cnt list))))))))
+
+;;}}}
+;;{{{ Key mappings
+
+(defvar mmm-noweb-map (make-sparse-keymap))
+(defvar mmm-noweb-prefix-map (make-sparse-keymap))
+(define-key mmm-noweb-map mmm-mode-prefix-key mmm-noweb-prefix-map)
+
+(mmm-define-key ?d 'mmm-noweb-narrow-to-doc-chunk mmm-noweb-prefix-map)
+(mmm-define-key ?n 'mmm-noweb-goto-next mmm-noweb-prefix-map)
+(mmm-define-key ?p 'mmm-noweb-goto-previous mmm-noweb-prefix-map)
+(mmm-define-key ?q 'mmm-noweb-fill-chunk mmm-noweb-prefix-map)
+;; Cannot use C-g as goto command, so use C-s.
+(mmm-define-key ?s 'mmm-noweb-goto-chunk mmm-noweb-prefix-map)
+
+(define-key mmm-noweb-prefix-map "\t" 'mmm-noweb-complete-chunk)
+
+;; Don't want to add to either the mmm mode map (used in other mmm
+;; buffers) or the local map (used in other major mode buffers), so we
+;; make a full-buffer spanning overlay and add the map there.
+(defun mmm-noweb-bind-keys ()
+ (save-restriction
+ (widen)
+ (let ((ovl (make-overlay (point-min) (point-max) nil nil t)))
+ ;; 'keymap', not 'local-map'
+ (overlay-put ovl 'keymap mmm-noweb-map))))
+
+(add-hook 'mmm-noweb-class-hook 'mmm-noweb-bind-keys)
+
+;; TODO: make this overlay go away if mmm is turned off
+
+;;}}}
+
+;; These functions below living here temporarily until a real place is
+;; found.
+
+(defun mmm-syntax-region-list (syntax regions)
+ "Apply SYNTAX to a list of REGIONS of the form (BEG END).
+If SYNTAX is not nil, set the syntax-table property of each region.
+If SYNTAX is nil, remove the region syntax-table property.
+See `mmm-syntax-region'."
+ (mapcar #'(lambda (reg)
+ (mmm-syntax-region (car reg) (cadr reg) syntax))
+ regions))
+
+(defun mmm-syntax-other-regions (syntax &optional name)
+ "Apply SYNTAX cell to other regions.
+Regions are separated by name, using either `mmm-name-at' or the
+optional NAME to determine the current region name."
+ (if (null name)
+ (setq name (or (mmm-name-at)
+ (symbol-name mmm-primary-mode))))
+ (mapcar #'(lambda (reg)
+ (if (not (string= (car reg) name))
+ (mmm-syntax-region-list syntax (cdr reg))))
+ (mmm-names-alist (point-min) (point-max))))
+
+(defun mmm-word-other-regions ()
+ "Give all other regions word syntax."
+ (interactive)
+ (mmm-syntax-other-regions '(2 . 0))
+ (setq parse-sexp-lookup-properties t))
+
+(defun mmm-space-other-regions ()
+ "Give all other regions space syntax."
+ (interactive)
+ (mmm-syntax-other-regions '(0 . 0))
+ (setq parse-sexp-lookup-properties t))
+
+(defun mmm-undo-syntax-other-regions ()
+ "Remove syntax-table property from other regions."
+ (interactive)
+ (mmm-syntax-other-regions nil)
+ (setq parse-sexp-lookup-properties nil))
+
+
+(provide 'mmm-noweb)
+
+;;; mmm-noweb.el ends here
--- /dev/null
+;;; mmm-region.el --- Manipulating and behavior of MMM submode regions
+
+;; Copyright (C) 2000 by Michael Abraham Shulman
+;; Copyright (C) 2012, 2013 by Dmitry Gutov
+
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file provides the functions and variables to create, delete,
+;; and inspect submode regions, as well as functions that make them
+;; behave like the submode with respect to syntax tables, local maps,
+;; font lock, etc.
+
+;; See mmm-class.el for functions which scan the buffer and decide
+;; where to create regions.
+
+;;; Code:
+
+(require 'cl)
+(require 'font-lock)
+(require 'mmm-compat)
+(require 'mmm-utils)
+(require 'mmm-auto)
+(require 'mmm-vars)
+
+;; INSPECTION
+;;{{{ Current Overlays
+
+;; Emacs counts an overlay starting at POS as "at" POS, but not an
+;; overlay ending at POS. XEmacs is more sensible and uses beg- and
+;; end-stickiness to determine whether an endpoint is within an
+;; extent. Here we want to act like XEmacs does.
+
+(defsubst mmm-overlay-at (&optional pos type)
+ "Return the highest-priority MMM Mode overlay at POS.
+See `mmm-included-p' for the values of TYPE."
+ (car (mmm-overlays-at pos type)))
+
+(defun mmm-overlays-at (&optional pos type)
+ "Return a list of the MMM overlays at POS, in decreasing priority.
+See `mmm-included-p' for the values of TYPE."
+ (or pos (setq pos (point)))
+ (mmm-sort-overlays
+ (remove-if-not
+ #'(lambda (ovl)
+ (and (overlay-get ovl 'mmm)
+ (mmm-included-p ovl pos type)))
+ ;; XEmacs complains about positions outside the buffer
+ (overlays-in (max (1- pos) (point-min))
+ (min (1+ pos) (point-max))))))
+
+(defun mmm-included-p (ovl pos &optional type)
+ "Return true if the overlay OVL contains POS.
+
+If OVL strictly contains POS, always return true. If OVL starts or
+ends at POS, return true or false based on the value of TYPE, which
+should be one of nil, `beg', `end', `none', or `all'.
+* If TYPE is nil, return true for an overlay starting at POS only if
+ it is beg-sticky, and for one ending at POS only if it is end-sticky.
+* If TYPE is `beg', return true for any overlay starting at POS but
+ false for any ending at POS.
+* If TYPE is `end', return true for any overlay ending at POS but
+ false for any starting at POS.
+* If TYPE is `all', return true for any overlay starting or ending at POS.
+* If TYPE is `none' \(or any other value), return false for any
+ overlay starting or ending at POS."
+ (let ((beg (overlay-start ovl))
+ (end (overlay-end ovl)))
+ (cond ((and (= beg pos) (= end pos))
+ ;; Do the Right Thing for zero-width overlays
+ (case type
+ ((nil) (and (overlay-get ovl 'beg-sticky)
+ (overlay-get ovl 'end-sticky)))
+ ((none) nil)
+ (t t)))
+ ((= beg pos)
+ (case type
+ ((nil) (overlay-get ovl 'beg-sticky))
+ ((beg all) t)
+ (t nil)))
+ ((= end pos)
+ (case type
+ ((nil) (overlay-get ovl 'end-sticky))
+ ((end all) t)
+ (t nil)))
+ ((and (> end pos) (< beg pos))
+ t))))
+
+;;; `mmm-overlays-in' has been retired as altogether too confusing a
+;;; name, when what is really meant is one of the following three:
+
+(defun mmm-overlays-containing (start stop)
+ "Return all MMM overlays containing the region START to STOP.
+The overlays are returned in order of decreasing priority. No
+attention is paid to stickiness."
+ (mmm-sort-overlays
+ (remove-if-not
+ #'(lambda (ovl)
+ (and (overlay-get ovl 'mmm)
+ (<= (overlay-start ovl) start)
+ (>= (overlay-end ovl) stop)))
+ (overlays-in (max start (point-min))
+ (min stop (point-max))))))
+
+(defun mmm-overlays-contained-in (start stop)
+ "Return all MMM overlays entirely contained in START to STOP.
+The overlays are returned in order of decreasing priority. No
+attention is paid to stickiness."
+ (mmm-sort-overlays
+ (remove-if-not
+ #'(lambda (ovl)
+ (and (overlay-get ovl 'mmm)
+ (>= (overlay-start ovl) start)
+ (<= (overlay-end ovl) stop)))
+ (overlays-in (max start (point-min))
+ (min stop (point-max))))))
+
+(defun mmm-overlays-overlapping (start stop)
+ "Return all MMM overlays overlapping the region START to STOP.
+The overlays are returned in order of decreasing priority. No
+attention is paid to stickiness."
+ (mmm-sort-overlays
+ (remove-if-not
+ #'(lambda (ovl)
+ (overlay-get ovl 'mmm))
+ (overlays-in (max start (point-min))
+ (min stop (point-max))))))
+
+(defun mmm-sort-overlays (overlays)
+ "Sort OVERLAYS in order of decreasing priority."
+ (sort (copy-list overlays)
+ #'(lambda (x y) (> (or (overlay-get x 'priority) 0)
+ (or (overlay-get y 'priority) 0)))))
+
+;;}}}
+;;{{{ Current Submode
+
+(defvar mmm-current-overlay nil
+ "What submode region overlay we think we are currently in.
+May be out of date; call `mmm-update-current-submode' to correct it.")
+(make-variable-buffer-local 'mmm-current-overlay)
+
+(defvar mmm-previous-overlay nil
+ "What submode region overlay we were in just before this one.
+Set by `mmm-update-current-submode'.")
+(make-variable-buffer-local 'mmm-previous-overlay)
+
+(defvar mmm-current-submode nil
+ "What submode we think we are currently in.
+May be out of date; call `mmm-update-current-submode' to correct it.")
+(make-variable-buffer-local 'mmm-current-submode)
+
+(defvar mmm-previous-submode nil
+ "What submode we were in just before this one.
+Set by `mmm-update-current-submode'.")
+(make-variable-buffer-local 'mmm-previous-submode)
+
+(defun mmm-update-current-submode (&optional pos)
+ "Update current and previous position variables to POS, or point.
+Return non-nil if the current region changed.
+
+Also deletes overlays that ought to evaporate because their delimiters
+have disappeared."
+ (mapc #'delete-overlay
+ (remove-if #'(lambda (ovl)
+ (or (not (eq (overlay-get ovl 'mmm-evap) 'front))
+ (overlay-buffer (overlay-get ovl 'front))))
+ (mmm-overlays-at pos)))
+ (let ((ovl (mmm-overlay-at pos)))
+ (if (eq ovl mmm-current-overlay)
+ nil
+ (mmm-set-current-pair (if ovl (overlay-get ovl 'mmm-mode)) ovl)
+ t)))
+
+(defun mmm-set-current-pair (mode ovl)
+ "Set the current submode to MODE, the current overlay to OVL
+and update the saved previous values."
+ (setq mmm-previous-overlay mmm-current-overlay
+ mmm-previous-submode mmm-current-submode)
+ (setq mmm-current-submode mode
+ mmm-current-overlay ovl))
+
+(defun mmm-submode-at (&optional pos type)
+ "Return the submode at POS \(or point), or NIL if none.
+See `mmm-included-p' for values of TYPE."
+ (let ((ovl (mmm-overlay-at pos type)))
+ (if ovl (overlay-get ovl 'mmm-mode))))
+
+;;}}}
+;;{{{ Delimiter Matching and Boundaries
+
+(defun mmm-match-front (ovl)
+ "Return non-nil if the front delimiter of OVL matches as it should.
+Sets the match data to the front delimiter, if it is a regexp.
+Otherwise, calls it as a function with point at the beginning of the
+front delimiter overlay \(i.e. where the front delimiter ought to
+start) and one argument being the region overlay. The function should
+return non-nil if the front delimiter matches correctly, and set the
+match data appropriately."
+ (let* ((front-ovl (overlay-get ovl 'front))
+ (front (if front-ovl (overlay-get front-ovl 'match))))
+ (when front
+ (save-excursion
+ (goto-char (overlay-start front-ovl))
+ (if (stringp front)
+ ;; It's a regexp
+ (looking-at front)
+ ;; It's a function
+ (funcall front ovl))))))
+
+(defun mmm-match-back (ovl)
+ "Return non-nil if the back delimiter of OVL matches as it should.
+Sets the match data to the back delimiter, if it is a regexp.
+Otherwise, calls it as a function with point at the beginning of the
+back delimiter overlay \(i.e. where the back delimiter ought to start)
+and one argument being the region overlay. The function should return
+non-nil if the back delimiter matches correctly, and set the match
+data appropriately."
+ (let* ((back-ovl (overlay-get ovl 'back))
+ (back (if back-ovl (overlay-get back-ovl 'match))))
+ (when back
+ (save-excursion
+ (goto-char (overlay-start back-ovl))
+ (if (stringp back)
+ ;; It's a regexp
+ (looking-at back)
+ ;; It's a function
+ (funcall back ovl))))))
+
+(defun mmm-front-start (ovl)
+ "Return the position at which the front delimiter of OVL starts."
+ (let ((front (overlay-get ovl 'front)))
+ ;; Overlays which have evaporated become "overlays in no buffer"
+ (if (and front (overlay-buffer front))
+ (overlay-start front)
+ (overlay-start ovl))))
+
+(defun mmm-back-end (ovl)
+ "Return the position at which the back delimiter of OVL ends."
+ (let ((back (overlay-get ovl 'back)))
+ ;; Overlays which have evaporated become "overlays in no buffer"
+ (if (and back (overlay-buffer back))
+ (overlay-end back)
+ (overlay-end ovl))))
+
+;;}}}
+
+;; CREATION & DELETION
+;;{{{ Make Submode Regions
+
+(defun mmm-valid-submode-region (submode beg end)
+ "Check if the region between BEG and END is valid for SUBMODE.
+This region must be entirely contained within zero or more existing
+submode regions, none of which start or end inside it, and it must be
+a valid child of the highest-priority of those regions, if any.
+Signals errors, returns `t' if no error."
+ ;; First check if the placement is valid. Every existing region
+ ;; that overlaps this one must contain it in its entirety.
+ (let ((violators (set-difference
+ (mmm-overlays-overlapping beg end)
+ (mmm-overlays-containing beg end))))
+ (if violators
+ (signal 'mmm-subregion-invalid-placement
+ violators)))
+ ;; Now check if it is inside a valid parent
+ (let ((parent-mode (mmm-submode-at beg 'beg)))
+ (and parent-mode
+ ;; TODO: Actually check parents here. For present purposes,
+ ;; we just make sure we aren't putting a submode inside one
+ ;; of the same type. Actually, what we should really be
+ ;; doing is checking classes/names of regions, not just the
+ ;; submodes.
+ (eq submode parent-mode)
+ (signal 'mmm-subregion-invalid-parent
+ (list parent-mode))))
+ t)
+
+(defun* mmm-make-region
+ (submode beg end &key face
+ front back (evaporation 'front)
+ delimiter-mode front-face back-face
+ display-name
+ (match-front "") (match-back "")
+ (beg-sticky t) (end-sticky t)
+ name creation-hook
+ )
+ "Make a submode region from BEG to END of SUBMODE.
+
+BEG and END are buffer positions or markers with BEG <= END \(although
+see EVAPORATION below). SUBMODE is a major mode function or a valid
+argument to `mmm-modename->function'. FACE is a valid display face.
+
+FRONT and BACK specify the positions of the front and back delimiters
+for this region, if any. If FRONT is a buffer position or marker, the
+front delimiter runs from it to BEG. FRONT can also be a two-element
+list \(FRONT-BEG FRONT-END) specifying the exact position of the front
+delimiter. One must have FRONT-BEG < FRONT-END <= BEG.
+
+Similarly, BACK may be a buffer position or marker, in which case the
+back delimiter runs from END to BACK. BACK can also be a two-element
+list \(BACK-BEG BACK-END) specifying the exact position, in which case
+we must have END <= BACK-BEG < BACK-END.
+
+EVAPORATION specifies under what conditions this submode region should
+disappear.
+* If `nil', the region never disappears. This can cause serious
+ problems when using cut-and-paste and is not recommended.
+* If the value is t, the region disappears whenever it has zero
+ length. This is recommended for manually created regions used for
+ temporary editing convenience.
+* If the value is `front', the region will disappear whenever the text
+ in its front delimiter disappears, that is, whenever the overlay
+ which marks its front delimiter has zero width.
+The default value is `front'. However, if the parameter FRONT is nil,
+then this makes no sense, so the default becomes `t'. Note that if
+EVAPORATION is `t', then an error is signalled if BEG = END.
+
+MATCH-FRONT \(resp. MATCH-BACK) is a regexp or function to match the
+correct delimiters, see `mmm-match-front' \(resp. `mmm-match-back').
+It is ignored if FRONT \(resp. BACK) is nil. At present these are not
+used much.
+
+DELIMITER-MODE specifies the major mode to use for delimiter regions.
+A `nil' value means they remain in the primary mode.
+
+FACE, FRONT-FACE, and BACK-FACE, are faces to use for the region, the
+front delimiter, and the back delimiter, respectively, under high
+decoration \(see `mmm-submode-decoration-level').
+
+BEG-STICKY and END-STICKY determine whether the front and back of the
+region, respectively, are sticky with respect to new insertion. The
+default is yes.
+
+NAME is a string giving the \"name\" of this submode region. Submode
+regions with the same name are considered part of the same code
+fragment and formatted accordingly.
+
+DISPLAY-NAME is a string to display in the mode line when point is in
+this submode region. If nil or not given, the name associated with
+SUBMODE is used. In delimiter regions, \"--\" is shown.
+
+CREATION-HOOK should be a function to run after the region is created,
+with point at the start of the new region."
+ ;; Check placement of region and delimiters
+ (unless (if (eq evaporation t)
+ (< beg end)
+ (<= beg end))
+ (signal 'mmm-subregion-invalid-placement (list beg end)))
+ (when front
+ (unless (listp front)
+ (setq front (list front beg)))
+ (unless (and (< (car front) (cadr front))
+ (<= (cadr front) beg))
+ (signal 'mmm-subregion-invalid-placement front)))
+ (when back
+ (unless (listp back)
+ (setq back (list end back)))
+ (unless (and (< (car back) (cadr back))
+ (<= end (car back)))
+ (signal 'mmm-subregion-invalid-placement back)))
+ (setq submode (mmm-modename->function submode))
+ ;; Check embedding in existing regions
+ (mmm-valid-submode-region submode beg end)
+ (mmm-mode-on)
+ (when submode
+ (mmm-update-mode-info submode))
+ (and (not front) (eq evaporation 'front) (setq evaporation t))
+ (let ((region-ovl
+ (mmm-make-overlay submode beg end name face beg-sticky end-sticky
+ (or (eq evaporation t) nil) display-name)))
+ ;; Save evaporation type for checking later
+ (overlay-put region-ovl 'mmm-evap evaporation)
+ ;; Calculate priority to supersede anything already there.
+ (overlay-put region-ovl 'priority (length (mmm-overlays-at beg)))
+ ;; Make overlays for the delimiters, with appropriate pointers.
+ (when front
+ (let ((front-ovl
+ (mmm-make-overlay delimiter-mode (car front) (cadr front)
+ nil front-face nil nil t "--" t)))
+ (overlay-put region-ovl 'front front-ovl)
+ (overlay-put front-ovl 'region region-ovl)
+ (overlay-put front-ovl 'match match-front)))
+ (when back
+ (let ((back-ovl
+ (mmm-make-overlay delimiter-mode (car back) (cadr back)
+ nil back-face nil nil t "--" t)))
+ (overlay-put region-ovl 'back back-ovl)
+ (overlay-put back-ovl 'region region-ovl)
+ (overlay-put back-ovl 'match match-back)))
+ ;; Update everything and run all the hooks
+ (mmm-save-all
+ ;; Can be nil when a zero-width region is immediately evaporated
+ (when (overlay-start region-ovl)
+ (goto-char (overlay-start region-ovl)))
+ (mmm-set-current-pair submode region-ovl)
+ (mmm-set-local-variables submode region-ovl)
+ (mmm-run-submode-hook submode)
+ (when creation-hook
+ (funcall creation-hook)))
+ (mmm-update-submode-region)
+ region-ovl))
+
+(defun mmm-make-overlay (submode beg end name face beg-sticky end-sticky evap
+ &optional display-name delim)
+ "Internal function to make submode overlays.
+Does not handle delimiters. Use `mmm-make-region'."
+ (let ((ovl (make-overlay beg end nil (not beg-sticky) end-sticky)))
+ (mapc
+ #'(lambda (pair) (overlay-put ovl (car pair) (cadr pair)))
+ `((mmm t) ; Mark all submode overlays
+ (mmm-mode ,submode)
+ ,@(if delim '((delim t)) nil)
+ (mmm-local-variables
+ ;; Have to be careful to make new list structure here
+ ,(list* (list 'font-lock-cache-state nil)
+ (list 'font-lock-cache-position (make-marker))
+ (copy-tree
+ (cdr (assq submode mmm-region-saved-locals-defaults)))))
+ (name ,name)
+ (display-name ,display-name)
+ ;; Need to save these, because there's no way of accessing an
+ ;; overlay's official "front-advance" parameter once it's created.
+ (beg-sticky ,beg-sticky)
+ (end-sticky ,end-sticky)
+ ;; These have special meaning to Emacs
+ (,mmm-evaporate-property ,evap)
+ (face ,(mmm-get-face face submode delim))
+ ))
+ ovl))
+
+(defun mmm-get-face (face submode &optional delim)
+ (cond ((= mmm-submode-decoration-level 0) nil)
+ ((and (= mmm-submode-decoration-level 2) face) face)
+ (delim 'mmm-delimiter-face)
+ (submode 'mmm-default-submode-face)))
+
+;;}}}
+;;{{{ Clear Overlays
+
+;; See also `mmm-clear-current-region'.
+
+(defun mmm-clear-overlays (&optional start stop strict)
+ "Clears all MMM overlays overlapping START and STOP.
+If STRICT, only clear those entirely included in that region."
+ (mapc #'delete-overlay
+ (if strict
+ (mmm-overlays-contained-in (or start (point-min))
+ (or stop (point-max)))
+ (mmm-overlays-overlapping (or start (point-min))
+ (or stop (point-max)))))
+ (mmm-update-submode-region))
+
+;;}}}
+
+;; BASIC UPDATING
+;;{{{ Submode Info
+
+(defun mmm-update-mode-info (mode &optional force)
+ "Save the global-saved and buffer-saved variables for MODE.
+Global saving is done on properties of the symbol MODE and buffer
+saving in `mmm-buffer-saved-locals'. This function must be called for
+both the dominant mode and all submodes, in each file. Region-saved
+variables are initialized from `mmm-region-saved-locals-defaults',
+which is set here as well. See `mmm-save-local-variables'. If FORCE
+is non-nil, don't quit if the info is already there."
+ (let ((buffer-entry (assq mode mmm-buffer-saved-locals))
+ (region-entry (assq mode mmm-region-saved-locals-defaults))
+ global-vars buffer-vars region-vars
+ ;; http://debbugs.gnu.org/13836
+ buffer-file-truename)
+ (unless (and (not force)
+ (get mode 'mmm-local-variables)
+ buffer-entry
+ region-entry)
+ (let ((temp-buffer (mmm-make-temp-buffer (current-buffer)
+ mmm-temp-buffer-name))
+ (filename (buffer-file-name))
+ (mmm-in-temp-buffer t))
+ (unwind-protect
+ (with-current-buffer temp-buffer
+ ;; Handle stupid modes that need the file name set.
+ (when (memq mode mmm-set-file-name-for-modes)
+ (setq buffer-file-name filename))
+ (funcall mode)
+ (when (featurep 'font-lock)
+ (put mode 'mmm-font-lock-mode font-lock-mode)
+ ;; These can't be in the local variables list, because we
+ ;; replace their actual values, but we want to use their
+ ;; original values elsewhere.
+ (put mode 'mmm-fontify-region-function
+ font-lock-fontify-region-function)
+ (put mode 'mmm-beginning-of-syntax-function
+ (or syntax-begin-function
+ font-lock-beginning-of-syntax-function))
+ (put mode 'mmm-syntax-propertize-function
+ (and (boundp 'syntax-propertize-function)
+ syntax-propertize-function))
+ (put mode 'mmm-indent-line-function indent-line-function))
+ ;; Get variables
+ (setq global-vars (mmm-get-locals 'global)
+ buffer-vars (mmm-get-locals 'buffer)
+ region-vars (mmm-get-locals 'region))
+ (put mode 'mmm-mode-name mode-name))
+ (kill-buffer temp-buffer)))
+ (put mode 'mmm-local-variables global-vars)
+ (if buffer-entry
+ (setcdr buffer-entry buffer-vars)
+ (push (cons mode buffer-vars) mmm-buffer-saved-locals))
+ (if region-entry
+ (setcdr region-entry region-vars)
+ (push (cons mode region-vars)
+ mmm-region-saved-locals-defaults)))))
+
+;;}}}
+;;{{{ Updating Hooks
+
+(defun mmm-update-submode-region ()
+ "Update all MMM properties correctly for the current position.
+This function and those it calls do the actual work of setting the
+different keymaps, syntax tables, local variables, etc. for submodes."
+ (when (mmm-update-current-submode)
+ (mmm-save-changed-local-variables mmm-previous-submode
+ mmm-previous-overlay)
+ (let ((mode (or mmm-current-submode mmm-primary-mode)))
+ (mmm-update-mode-info mode)
+ (mmm-set-local-variables mode mmm-current-overlay)
+ (mmm-enable-font-lock mode))
+ (mmm-set-mode-line)
+ (dolist (func (if mmm-current-overlay
+ (overlay-get mmm-current-overlay 'entry-hook)
+ mmm-primary-mode-entry-hook))
+ (ignore-errors (funcall func)))))
+
+(defun mmm-add-hooks ()
+ (if (featurep 'xemacs)
+ (make-local-hook 'post-command-hook))
+ (add-hook 'post-command-hook 'mmm-update-submode-region nil t)
+ (when mmm-parse-when-idle
+ (add-hook 'pre-command-hook 'mmm-mode-reset-timer nil t)
+ (add-hook 'after-change-functions 'mmm-mode-edit nil t)))
+
+(defun mmm-remove-hooks ()
+ (remove-hook 'post-command-hook 'mmm-update-submode-region t)
+ (remove-hook 'pre-command-hook 'mmm-mode-reset-timer t)
+ (remove-hook 'after-change-functions 'mmm-mode-edit t))
+
+;;}}}
+;;{{{ Local Variables
+
+(defun mmm-get-local-variables-list (type mode)
+ "Filter `mmm-save-local-variables' to match TYPE and MODE.
+Return a list \(VAR ...). In some cases, VAR will be a cons cell
+\(GETTER . SETTER) -- see `mmm-save-local-variables'."
+ (mapcan #'(lambda (element)
+ (and (if (and (consp element)
+ (cdr element)
+ (cadr element))
+ (eq (cadr element) type)
+ (eq type 'global))
+ (if (and (consp element)
+ (cddr element)
+ (not (eq (caddr element) t)))
+ (if (functionp (caddr element))
+ (funcall (caddr element))
+ (member mode (caddr element)))
+ t)
+ (list (if (consp element) (car element) element))))
+ mmm-save-local-variables))
+
+(defun mmm-get-locals (type)
+ "Get the local variables and values for TYPE from this buffer.
+Return \((VAR VALUE) ...). In some cases, VAR will be of the form
+\(GETTER . SETTER) -- see `mmm-save-local-variables'."
+ (mapcan #'(lambda (var)
+ (if (consp var)
+ `((,var ,(funcall (car var))))
+ (and (boundp var)
+ ;; This seems logical, but screws things up.
+ ;;(local-variable-p var)
+ `((,var ,(symbol-value var))))))
+ (mmm-get-local-variables-list type major-mode)))
+
+;; FIXME: Has no callers. Used for debugging?
+(defun mmm-get-saved-local (mode ovl var)
+ "Get the value of the local variable VAR saved for MODE and OVL, if any."
+ (cadr (assq var (mmm-get-saved-local-variables ovl mode))))
+
+;; FIXME: It's too easy to accidentally pass nil as MODE here.
+;; We probably should call this from `mmm-set-current-pair', and not
+;; rely on its callers to default to the primary mode when appropriate.
+;; Also, incorporate the opmimization from `mmm-fontify-region-list'.
+(defun mmm-set-local-variables (mode ovl)
+ "Set all the local variables saved for MODE and OVL.
+Looks up global, buffer and region saves. When MODE is nil, just
+the region ones."
+ (mapcar #'(lambda (var)
+ ;; (car VAR) may be (GETTER . SETTER)
+ (if (consp (car var))
+ (funcall (cdar var) (cadr var))
+ (make-local-variable (car var))
+ (set (car var) (cadr var))))
+ (mmm-get-saved-local-variables mode ovl)))
+
+;; Used for debugging.
+(defun mmm-diff-local-variables (mode ovl)
+ (let (res)
+ (mapc (lambda (var)
+ (let ((current-value (if (consp (car var))
+ (funcall (caar var))
+ (symbol-value (car var)))))
+ (unless (equal current-value (cadr var))
+ (push
+ (message "var: %s, current: %s, saved: %s" (car var)
+ current-value (cadr var))
+ res))))
+ (mmm-get-saved-local-variables mode ovl))
+ res))
+
+(defun mmm-get-saved-local-variables (mode ovl)
+ (append (get mode 'mmm-local-variables)
+ (cdr (assq mode mmm-buffer-saved-locals))
+ (if ovl
+ (overlay-get ovl 'mmm-local-variables)
+ mmm-region-saved-locals-for-dominant)))
+
+(defun mmm-save-changed-local-variables (mode ovl)
+ "Save by-buffer and by-region variables for MODE and OVL.
+Called when we move to a new submode region, with MODE and OVL the
+region and mode for the previous position."
+ (let ((buffer-vars (cdr (assq (or mode mmm-primary-mode)
+ mmm-buffer-saved-locals)))
+ (region-vars (if ovl
+ (overlay-get ovl 'mmm-local-variables)
+ mmm-region-saved-locals-for-dominant))
+ (set-local-value
+ #'(lambda (var)
+ (setcar (cdr var)
+ ;; (car VAR) may be (GETTER . SETTER)
+ (if (consp (car var))
+ (funcall (caar var))
+ (symbol-value (car var)))))))
+ (mapc set-local-value buffer-vars)
+ (mapc set-local-value region-vars)))
+
+(defun mmm-clear-local-variables ()
+ "Clear all buffer- and region-saved variables for current buffer."
+ (setq mmm-buffer-saved-locals ()
+ mmm-region-saved-locals-defaults ()
+ mmm-region-saved-locals-for-dominant ()))
+
+;;}}}
+
+;; FONT LOCK
+;;{{{ Enable Font Lock
+
+(defun mmm-enable-font-lock (mode)
+ "Turn on font lock if it is not already on and MODE enables it."
+ (mmm-update-mode-info mode)
+ (and (not font-lock-mode)
+ (get mode 'mmm-font-lock-mode)
+ (font-lock-mode 1)))
+
+(defun mmm-update-font-lock-buffer ()
+ "Turn on font lock if any mode in the buffer enables it."
+ (if (some #'(lambda (mode)
+ (get mode 'mmm-font-lock-mode))
+ (cons mmm-primary-mode
+ (mapcar #'(lambda (ovl)
+ (overlay-get ovl 'mmm-mode))
+ (mmm-overlays-overlapping
+ (point-min) (point-max)))))
+ (font-lock-mode 1)
+ (font-lock-mode 0)))
+
+(defun mmm-refontify-maybe (&optional start stop)
+ "Re-fontify from START to STOP, or entire buffer, if enabled."
+ (and font-lock-mode
+ (if (or start stop)
+ (font-lock-fontify-region (or start (point-min))
+ (or stop (point-max)))
+ (font-lock-fontify-buffer))))
+
+;;}}}
+;;{{{ Get Submode Regions
+
+;;; In theory, these are general functions that have nothing to do
+;;; with font-lock, but they aren't used anywhere else, so we might as
+;;; well have them close.
+
+(defun mmm-submode-changes-in (start stop)
+ "Return a list of all submode-change positions from START to STOP.
+The list is sorted in order of increasing buffer position."
+ (let ((changes (sort (remove-duplicates
+ (mapcan #'(lambda (ovl)
+ `(,(overlay-start ovl)
+ ,(overlay-end ovl)))
+ (mmm-overlays-overlapping start stop)))
+ #'<)))
+ (when (or (not changes) (< start (car changes)))
+ (push start changes))
+ (let ((last (last changes)))
+ (when (> stop (car last))
+ (setcdr last (list stop))))
+ changes))
+
+(defun mmm-regions-in (start stop)
+ "Return a list of regions of the form (MODE BEG END OVL) whose disjoint
+union covers the region from START to STOP, including delimiters."
+ (let ((regions
+ (maplist #'(lambda (pos-list)
+ (when (cdr pos-list)
+ (let ((ovl (mmm-overlay-at (car pos-list) 'beg)))
+ (list (if ovl
+ (overlay-get ovl 'mmm-mode)
+ mmm-primary-mode)
+ (car pos-list) (cadr pos-list)
+ ovl))))
+ (mmm-submode-changes-in start stop))))
+ (setcdr (last regions 2) nil)
+ regions))
+
+(defun mmm-regions-alist (start stop)
+ "Return a list of lists of the form \(MODE . REGIONS) where REGIONS
+is a list of elements of the form \(BEG END OVL). The disjoint union all
+of the REGIONS covers START to STOP."
+ (let ((regions (mmm-regions-in start stop))
+ alist)
+ (mapc (lambda (region)
+ (let* ((mode (car region))
+ (elem (cdr region))
+ (kv (assoc mode alist)))
+ (if kv
+ (push elem (cdr kv))
+ (push (cons mode (list elem)) alist))))
+ regions)
+ (mapcar (lambda (kv)
+ (cons (car kv) (nreverse (cdr kv))))
+ alist)))
+
+;;}}}
+;;{{{ Fontify Regions
+
+(defun mmm-fontify-region (start stop &optional loudly)
+ "Fontify from START to STOP keeping track of submodes correctly."
+ (let ((saved-mode mmm-current-submode)
+ (saved-ovl mmm-current-overlay))
+ (unwind-protect
+ (progn
+ (when loudly
+ (message "Fontifying %s with submode regions..." (buffer-name)))
+ ;; Necessary to catch changes in font-lock cache state and position.
+ (mmm-save-changed-local-variables
+ mmm-current-submode mmm-current-overlay)
+ ;; For some reason `font-lock-fontify-block' binds this to nil, thus
+ ;; preventing `mmm-beginning-of-syntax' from doing The Right Thing.
+ ;; I don't know why it does this, but let's undo it here.
+ (let ((font-lock-beginning-of-syntax-function 'mmm-beginning-of-syntax))
+ (mapc #'(lambda (elt)
+ (when (get (car elt) 'mmm-font-lock-mode)
+ (mmm-fontify-region-list (car elt) (cdr elt))))
+ (mmm-regions-alist start stop))))
+ ;; `post-command-hook' contains `mmm-update-submode-region',
+ ;; but jit-lock runs later, so we need to restore local vars now.
+ (mmm-set-current-pair saved-mode saved-ovl)
+ (mmm-set-local-variables (or saved-mode mmm-primary-mode) saved-ovl)))
+ (when loudly (message nil)))
+
+(defun mmm-fontify-region-list (mode regions)
+ "Fontify REGIONS, each like \(BEG END), in mode MODE."
+ (save-excursion
+ (let ((func (get mode 'mmm-fontify-region-function))
+ font-lock-extend-region-functions)
+ (mapc #'(lambda (reg)
+ (goto-char (car reg))
+ ;; Here we do the same sort of thing that
+ ;; `mmm-update-submode-region' does, but we force it
+ ;; to use a specific mode, and don't save anything,
+ ;; fontify, or change the mode line.
+ (mmm-set-current-pair mode (caddr reg))
+ (mmm-set-local-variables (unless (eq mmm-previous-submode mode)
+ mode)
+ mmm-current-overlay)
+ (funcall func (car reg) (cadr reg) nil)
+ ;; Catch changes in font-lock cache.
+ (mmm-save-changed-local-variables
+ mmm-current-submode mmm-current-overlay))
+ regions))))
+
+;;}}}
+;;{{{ Syntax
+
+(defun mmm-beginning-of-syntax ()
+ (goto-char
+ (let ((ovl (mmm-overlay-at (point) 'beg))
+ (func (get (or mmm-current-submode mmm-primary-mode)
+ 'mmm-beginning-of-syntax-function)))
+ (max (if ovl (overlay-start ovl) (point-min))
+ (if func (progn (funcall func) (point)) (point-min))
+ (point-min)))))
+
+(defvar mmm-after-syntax-propertize-functions nil
+ "List of functions to call after applying `syntax-table' text
+properties to a submode region. It is passed four arguments: the
+region overlay, the submode and the bounds of the region.")
+
+(defun mmm-syntax-propertize-function (start stop)
+ "Composite function that applies `syntax-table' text properties.
+It iterates over all submode regions between START and STOP and
+calls each respective submode's `syntax-propertize-function'."
+ (let ((saved-mode mmm-current-submode)
+ (saved-ovl mmm-current-overlay))
+ (mmm-save-changed-local-variables
+ mmm-current-submode mmm-current-overlay)
+ (unwind-protect
+ (mapc #'(lambda (elt)
+ (let* ((mode (car elt))
+ (func (get mode 'mmm-syntax-propertize-function))
+ (beg (cadr elt)) (end (caddr elt))
+ (ovl (cadddr elt))
+ syntax-ppss-cache
+ syntax-ppss-last)
+ (goto-char beg)
+ (mmm-set-current-pair mode ovl)
+ (mmm-set-local-variables mode mmm-current-overlay)
+ (save-restriction
+ (when mmm-current-overlay
+ (narrow-to-region (overlay-start mmm-current-overlay)
+ (overlay-end mmm-current-overlay)))
+ (cond
+ (func
+ (funcall func beg end))
+ (font-lock-syntactic-keywords
+ (let ((syntax-propertize-function nil))
+ (font-lock-fontify-syntactic-keywords-region beg end))))
+ (run-hook-with-args 'mmm-after-syntax-propertize-functions
+ mmm-current-overlay mode beg end))))
+ (mmm-regions-in start stop))
+ (mmm-set-current-pair saved-mode saved-ovl)
+ (mmm-set-local-variables (or saved-mode mmm-primary-mode) saved-ovl))))
+
+;;}}}
+;;{{{ Indentation
+
+(defvar mmm-indent-line-function 'mmm-indent-line
+ "The function to call to indent inside a primary mode region.
+This will be the value of `indent-line-function' for the whole
+buffer. It's supposed to delegate to the appropriate submode's
+indentation function. See `mmm-indent-line' as the starting point.")
+
+(defun mmm-indent-line ()
+ (interactive)
+ (funcall
+ (save-excursion
+ (back-to-indentation)
+ (mmm-update-submode-region)
+ (get (or mmm-current-submode mmm-primary-mode)
+ 'mmm-indent-line-function))))
+
+;;}}}
+(provide 'mmm-region)
+
+;;; mmm-region.el ends here
--- /dev/null
+;;; mmm-rpm.el --- MMM submode class for RPM spec files
+
+;; Copyright (C) 2000 by Marcus Harnisch <Marcus.Harnisch@gmx.net>
+
+;; Author: Marcus Harnisch <Marcus.Harnisch@gmx.net>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file contains the definition of an MMM Mode submode class for
+;; editing shell script sections within RPM (Redhat Package Manager)
+;; spec files. I recommend to use it in combination with
+;; rpm-spec-mode.el by Stig Bjørlykke <stigb@tihlde.hist.no> and Steve
+;; Sanbeg <sanbeg@dset.com> (http://www.xemacs.org/~stigb/rpm-spec-mode.el)
+
+;;; Installation:
+
+;; 1. Copy this file where Emacs can find it.
+;;
+;; 2. Add the following lines to one of your startup files (e.g. ~/.emacs):
+;;
+;; (add-to-list 'mmm-mode-ext-classes-alist
+;; '(rpm-spec-mode "\\.spec\\'" rpm-sh))
+
+;;; Code:
+
+(require 'mmm-auto)
+
+(defconst mmm-rpm-sh-start-tags
+ '("prep" "build" "install" "clean" "preun" "postun" "pre"
+ "post" "triggerin" "triggerun" "triggerpostun")
+ "List containing RPM tags that start a shell-script section in a spec file")
+
+(defvar mmm-rpm-sh-end-tags
+ (append '("files" "description" "package") mmm-rpm-sh-start-tags)
+ "List containing RPM tags that end a shell-script section in a spec file")
+
+(defvar mmm-rpm-sh-start-regexp
+ (concat "^%" (mmm-regexp-opt mmm-rpm-sh-start-tags t) "\\b.*$")
+ "Regexp matching RPM tags that start a shell-script section in a spec file")
+
+(defvar mmm-rpm-sh-end-regexp
+ (concat "\\'\\|^%" (mmm-regexp-opt mmm-rpm-sh-end-tags t) "\\b.*$")
+ "Regexp matching RPM tags that end a shell-script section in a spec file")
+
+(mmm-add-group
+ 'rpm
+ `((rpm-sh
+ :submode sh-mode
+ :face mmm-code-submode-face
+ ;; match tags that starts sh-script region
+ :front ,mmm-rpm-sh-start-regexp
+ ;; match end of buffer or next tag that ends sh-script region
+ :back ,mmm-rpm-sh-end-regexp
+ :front-offset 1
+ :back-offset 0
+ :save-matches 0
+ )))
+
+(provide 'mmm-rpm)
+
+;;; mmm-rpm.el ends here
--- /dev/null
+;;; mmm-sample.el --- Sample MMM submode classes
+
+;; Copyright (C) 2003, 2004 by Michael Abraham Shulman
+
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file contains several sample submode classes for use with MMM
+;; Mode. For a more detailed, advanced example, see `mmm-mason.el'.
+
+;; In order to use any of classes defined here, just require `mmm-auto' and
+;; add the respective (major mode -> class <- file extension) associations
+;; with `mmm-add-mode-ext-class'.
+
+;;; Code:
+
+(require 'cl)
+(require 'mmm-auto)
+(require 'mmm-vars)
+
+;;{{{ <Perl> in httpd.conf
+
+;; This is the simplest example. Many applications will need no more
+;; than a simple regexp.
+;;
+;; Usage: (mmm-add-mode-ext-class 'apache-generic-mode nil 'httpd-conf-perl)
+
+(mmm-add-classes
+ '((httpd-conf-perl
+ :submode perl
+ :delimiter-mode nil
+ :front "<Perl>"
+ :back "</Perl>")))
+
+;;}}}
+;;{{{ JavaScript in HTML
+
+;; We use two classes here, both for code in a <script> tag, one wrapped in
+;; CDATA, another not. And another class to group them together.
+;;
+;; Usage: (mmm-add-mode-ext-class 'html-mode nil 'html-js)
+
+(mmm-add-group
+ 'html-js
+ '((js-script-cdata
+ :submode js-mode
+ :face mmm-code-submode-face
+ :front "<script[^>]*>[ \t\n]*\\(//\\)?<!\\[CDATA\\[[ \t]*\n?"
+ :back "[ \t]*\\(//\\)?]]>[ \t\n]*</script>")
+ (js-script
+ :submode js-mode
+ :face mmm-code-submode-face
+ :front "<script[^>]*>[ \t]*\n?"
+ :back "[ \t]*</script>"
+ :insert ((?j js-tag nil @ "<script type=\"text/javascript\">\n"
+ @ "" _ "" @ "\n</script>" @)))))
+
+;;}}}
+;;{{{ CSS in HTML
+
+(mmm-add-group
+ 'html-css
+ '((css-cdata
+ :submode css-mode
+ :face mmm-code-submode-face
+ :front "<style[^>]*>[ \t\n]*\\(//\\)?<!\\[CDATA\\[[ \t]*\n?"
+ :back "[ \t]*\\(//\\)?]]>[ \t\n]*</style>")
+ (css
+ :submode css-mode
+ :face mmm-code-submode-face
+ :front "<style[^>]*>[ \t]*\n?"
+ :back "[ \t]*</style>"
+ :insert ((?c css-tag nil @ "<style type=\"text/css\">\n"
+ @ "" _ "" @ "\n</style>" @)))))
+
+;;}}}
+;;{{{ Here-documents
+
+;; Here we match the here-document syntax used by Perl and shell
+;; scripts. We try to be automagic about recognizing what mode the
+;; here-document should be in. To make sure that it is recognized
+;; correctly, the name of the mode, perhaps minus `-mode', in upper
+;; case, and/or with hyphens converted to underscores, should be
+;; separated from the rest of the here-document name by hyphens or
+;; underscores.
+
+(defvar mmm-here-doc-mode-alist '()
+ "Alist associating here-document name regexps to submodes.
+Normally, this variable is unnecessary, as the `here-doc' submode
+class tries to automagically recognize the right submode. If you use
+here-document names that it doesn't recognize, however, then you can
+add elements to this alist. Each element is \(REGEXP . MODE) where
+REGEXP is a regular expression matched against the here-document name
+and MODE is a major mode function symbol.")
+
+(defun mmm-here-doc-get-mode (string)
+ (string-match "[a-zA-Z_-]+" string)
+ (setq string (match-string 0 string))
+ (or (mmm-ensure-modename
+ ;; First try the user override variable.
+ (some #'(lambda (pair)
+ (if (string-match (car pair) string) (cdr pair) nil))
+ mmm-here-doc-mode-alist))
+ (let ((words (split-string (downcase string) "[_-]+")))
+ (or (mmm-ensure-modename
+ ;; Try the whole name, stopping at "mode" if present.
+ (intern
+ (mapconcat #'identity
+ (nconc (ldiff words (member "mode" words))
+ (list "mode"))
+ "-")))
+ ;; Try each word by itself (preference list)
+ (some #'(lambda (word)
+ (mmm-ensure-modename (intern word)))
+ words)
+ ;; Try each word with -mode tacked on
+ (some #'(lambda (word)
+ (mmm-ensure-modename
+ (intern (concat word "-mode"))))
+ words)
+ ;; Try each pair of words with -mode tacked on
+ (loop for (one two) on words
+ if (mmm-ensure-modename
+ (intern (concat one two "-mode")))
+ return it)
+ ;; I'm unaware of any modes whose names, minus `-mode',
+ ;; are more than two words long, and if the entire mode
+ ;; name (perhaps minus `-mode') doesn't occur in the
+ ;; here-document name, we can give up.
+ (signal 'mmm-no-matching-submode nil)))))
+
+(mmm-add-classes
+ '((here-doc
+ :front "<<[\"\'\`]?\\([a-zA-Z0-9_-]+\\)"
+ :front-offset (end-of-line 1)
+ :back "^~1$"
+ :save-matches 1
+ :delimiter-mode nil
+ :match-submode mmm-here-doc-get-mode
+ :insert ((?d here-doc "Here-document Name: " @ "<<" str _ "\n"
+ @ "\n" @ str "\n" @))
+ )))
+
+;;}}}
+;;{{{ Embperl
+
+(mmm-add-group
+ 'embperl
+ '((embperl-perl
+ :submode perl
+ :front "\\[\\([-\\+!\\*\\$]\\)"
+ :back "~1\\]"
+ :save-matches 1
+ :match-name "embperl"
+ :match-face (("[+" . mmm-output-submode-face)
+ ("[-" . mmm-code-submode-face)
+ ("[!" . mmm-init-submode-face)
+ ("[*" . mmm-code-submode-face)
+ ("[$" . mmm-special-submode-face))
+ :insert ((?p embperl "Region Type (Character): " @ "[" str
+ @ " " _ " " @ str "]" @)
+ (?+ embperl+ ?p . "+")
+ (?- embperl- ?p . "-")
+ (?! embperl! ?p . "!")
+ (?* embperl* ?p . "*")
+ (?$ embperl$ ?p . "$")
+ )
+ )
+ (embperl-comment
+ :submode text-mode
+ :face mmm-comment-submode-face
+ :front "\\[#"
+ :back "#\\]"
+ :insert ((?# embperl-comment nil @ "[#" @ " " _ " " @ "#]" @))
+ )))
+
+;;}}}
+;;{{{ ePerl
+
+(mmm-add-group
+ 'eperl
+ '((eperl-expr
+ :submode perl
+ :face mmm-output-submode-face
+ :front "<:="
+ :back ":>"
+ :insert ((?= eperl-expr nil @ "<:=" @ " " _ " " @ ":>" @)))
+ (eperl-code
+ :submode perl
+ :face mmm-code-submode-face
+ :front "<:"
+ :back "_?:>"
+ :match-name "eperl"
+ :insert ((?p eperl-code nil @ "<:" @ " " _ " " @ ":>" @)
+ (?: eperl-code ?p . nil)
+ (?_ eperl-code_ nil @ "<:" @ " " _ " " @ "_:>" @)))
+ (eperl-comment
+ :submode text
+ :face mmm-comment-submode-face
+ :front ":>//"
+ :back "\n")
+ ))
+
+;;}}}
+;;{{{ File Variables
+
+;; This submode class puts file local variable values, specified with
+;; a `Local Variables:' line as in (emacs)File Variables, into Emacs
+;; Lisp Mode. It is a good candidate to put in `mmm-global-classes'.
+
+(defun mmm-file-variables-verify ()
+ ;; It would be nice to cache this somehow, which could be done in a
+ ;; buffer-local variable with markers for positions, but the trick
+ ;; is knowing when to expire the cache.
+ (let ((bounds
+ (save-excursion
+ (save-match-data
+ (goto-char (point-max))
+ (backward-page)
+ (and (re-search-forward "^\\(.*\\)Local Variables:" nil t)
+ (list (match-string 1)
+ (progn (end-of-line) (point))
+ (and (search-forward
+ (format "%sEnd:" (match-string 1))
+ nil t)
+ (progn (beginning-of-line)
+ (point)))))))))
+ (and bounds (caddr bounds)
+ (save-match-data
+ (string-match (format "^%s" (regexp-quote (car bounds)))
+ (match-string 0)))
+ (> (match-beginning 0) (cadr bounds))
+ (< (match-end 0) (caddr bounds)))))
+
+(defun mmm-file-variables-find-back (bound)
+ (forward-sexp)
+ (if (> (point) bound)
+ nil
+ (looking-at "")))
+
+(mmm-add-classes
+ '((file-variables
+ :front ".+:"
+ :front-verify mmm-file-variables-verify
+ :back mmm-file-variables-find-back
+ :submode emacs-lisp-mode
+ :delimiter-mode nil
+ )))
+
+;;}}}
+;;{{{ JSP Pages
+
+(mmm-add-group 'jsp
+ `((jsp-comment
+ :submode text-mode
+ :face mmm-comment-submode-face
+ :front "<%--"
+ :back "--%>"
+ :insert ((?- jsp-comment nil @ "<%--" @ " " _ " " @ "--%>" @))
+ )
+ (jsp-code
+ :submode java
+ :match-face (("<%!" . mmm-declaration-submode-face)
+ ("<%=" . mmm-output-submode-face)
+ ("<%" . mmm-code-submode-face))
+ :front "<%[!=]?"
+ :back "%>"
+ :match-name "jsp"
+ :insert ((?% jsp-code nil @ "<%" @ " " _ " " @ "%>" @)
+ (?! jsp-declaration nil @ "<%!" @ " " _ " " @ "%>" @)
+ (?= jsp-expression nil @ "<%=" @ " " _ " " @ "%>" @))
+ )
+ (jsp-directive
+ :submode text-mode
+ :face mmm-special-submode-face
+ :front "<%@"
+ :back "%>"
+ :insert ((?@ jsp-directive nil @ "<%@" @ " " _ " " @ "%>" @))
+ )))
+
+;;}}}
+;;{{{ SGML DTD
+
+;; Thanks to Yann Dirson <ydirson@fr.alcove.com> for writing and
+;; contributing this submode class.
+
+(mmm-add-classes
+ '((sgml-dtd
+ :submode dtd-mode
+ :face mmm-declaration-submode-face
+ :delimiter-mode nil
+ :front "<! *doctype[^>[]*\\["
+ :back "]>")))
+
+;;}}}
+;;{{{ PHP in HTML
+
+(mmm-add-group 'html-php
+ '((html-php-output
+ :submode php-mode
+ :face mmm-output-submode-face
+ :front "<\\?php *echo "
+ :back "\\?>"
+ :include-front t
+ :front-offset 5
+ :insert ((?e php-echo nil @ "<?php" @ " echo " _ " " @ "?>" @))
+ )
+ (html-php-code
+ :submode php-mode
+ :face mmm-code-submode-face
+ :front "<\\?\\(php\\)?"
+ :back "\\?>"
+ :insert ((?p php-section nil @ "<?php" @ " " _ " " @ "?>" @)
+ (?b php-block nil @ "<?php" @ "\n" _ "\n" @ "?>" @))
+ )))
+
+;;}}}
+
+;; NOT YET UPDATED
+;;{{{ HTML in PL/SQL;-COM-
+;-COM-
+;-COM-;; This one is the most complex example. In PL/SQL, HTML is generally
+;-COM-;; output as a (single quote delimited) string inside a call to htp.p or
+;-COM-;; its brethren. The problem is that there may be strings outside of
+;-COM-;; htp.p calls that should not be HTML, so we need to only look inside
+;-COM-;; these calls. The situation is complicated by PL/SQL's rule that two
+;-COM-;; sequential single quotes in a string mean to put a single quote
+;-COM-;; inside the string.
+;-COM-
+;-COM-;; These functions have not been thoroughly tested, and always search
+;-COM-;; the entire buffer, ignoring START and END.
+;-COM-
+;-COM-(defun mmm-html-in-plsql (start end)
+;-COM- (save-match-data
+;-COM- (let ((case-fold-search t))
+;-COM- (and (re-search-forward "htp.p\\(\\|rn\\|rint\\)1?(" nil t)
+;-COM- (mmm-html-in-plsql-in-htp
+;-COM- ;; Find the end of the procedure call
+;-COM- (save-excursion (forward-char -1) (forward-sexp) (point))
+;-COM- start end)))))
+;-COM-
+;-COM-(defun mmm-html-in-plsql-in-htp (htp-end start end)
+;-COM- (let (beg end)
+;-COM- (or (and (re-search-forward "'" htp-end 'limit)
+;-COM- (setf beg (match-end 0))
+;-COM- ;; Find an odd number of 's to end the string.
+;-COM- (do ((lgth 0 (length (match-string 0))))
+;-COM- ((oddp lgth) t)
+;-COM- (re-search-forward "'+" nil t))
+;-COM- (setf end (1- (match-end 0)))
+;-COM- (cons (cons beg end)
+;-COM- (mmm-html-in-plsql-in-htp htp-end start end)))
+;-COM- ;; No more strings in the procedure call; look for another.
+;-COM- (and (eql (point) htp-end)
+;-COM- (mmm-html-in-plsql start end)))))
+;-COM-
+;-COM-(add-to-list 'mmm-classes-alist
+;-COM- '(htp-p (:function html-mode mmm-html-in-plsql)))
+;-COM-
+;;}}}
+
+(provide 'mmm-sample)
+
+;;; mmm-sample.el ends here
--- /dev/null
+;;; mmm-univ.el --- The "Universal" Submode Class
+
+;; Copyright (C) 2000 by Free Software Foundation, Inc.
+
+;; Author: Michael Abraham Shulman <mas@kurukshetra.cjb.net>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file defines the "universal" submode class, the default value
+;; of `mmm-global-classes', which specifies a standard way to indicate
+;; that part of a buffer should be in a different mode--for example,
+;; in an email message.
+
+;;; Code:
+
+(require 'mmm-auto)
+(require 'mmm-vars)
+
+(defun mmm-univ-get-mode (string)
+ (string-match "[a-zA-Z-]+" string)
+ (setq string (match-string 0 string))
+ (let ((modestr (intern (if (string-match "mode\\'" string)
+ string
+ (concat string "-mode")))))
+ (or (mmm-ensure-modename modestr)
+ (signal 'mmm-no-matching-submode nil))))
+
+(mmm-add-classes
+ `((universal
+ :front "{%\\([a-zA-Z-]+\\)%}"
+ :back "{%/~1%}"
+ :insert ((?/ universal "Submode: " @ "{%" str "%}" @ "\n" _ "\n"
+ @ "{%/" str "%}" @))
+ :match-submode mmm-univ-get-mode
+ :save-matches 1
+ )))
+
+(provide 'mmm-univ)
+
+\f
+;;; Local Variables:
+;;; mmm-global-classes: nil
+;;; End:
+
+;;; mmm-univ.el ends here
--- /dev/null
+;;; mmm-utils.el --- Coding Utilities for MMM Mode
+
+;; Copyright (C) 2000 by Michael Abraham Shulman
+
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file provides a number of macros and other coding utilities
+;; for MMM Mode.
+
+;;; Code:
+
+(require 'cl)
+
+;;{{{ Valid Buffer
+
+;; We used to wrap almost everything in this, but I realized that
+;; only `mmm-mode-on' really needs it. Kept it as a macro, though,
+;; for modularity and in case we need it somewhere else.
+(defmacro mmm-valid-buffer (&rest body)
+ "Execute BODY if in a valid buffer for MMM Mode to be enabled. This
+means not hidden, not a minibuffer, not in batch mode, and not in of
+`mmm-never-modes'."
+ `(unless (or (eq (aref (buffer-name) 0) ?\ )
+ (window-minibuffer-p (selected-window))
+ (memq major-mode mmm-never-modes)
+ noninteractive
+ mmm-in-temp-buffer)
+ ,@body))
+
+;;;(def-edebug-spec mmm-valid-buffer t)
+
+;;}}}
+;;{{{ Save Everything
+
+;; Never trust callback functions to preserve anything.
+(defmacro mmm-save-all (&rest body)
+ "Execute BODY forms, then restoring point, mark, current buffer,
+restrictions, and match data."
+ `(save-excursion
+ (save-restriction
+ (save-match-data
+ ,@body))))
+
+;;;(def-edebug-spec mmm-save-all t)
+
+;;}}}
+;;{{{ String Formatting
+
+(defun mmm-format-string (string arg-pairs)
+ "Format STRING by replacing arguments as specified by ARG-PAIRS.
+Each element of ARG-PAIRS is \(REGEXP . STR) where each STR is to be
+substituted for the corresponding REGEXP wherever it matches."
+ (let ((case-fold-search nil))
+ (save-match-data
+ (dolist (pair arg-pairs)
+ (while (string-match (car pair) string)
+ (setq string (replace-match
+ (if (fboundp 'format-mode-line)
+ (format-mode-line (cdr pair))
+ (cdr pair))
+ t t string))))))
+ string)
+
+(defun mmm-format-matches (string &optional on-string)
+ "Format STRING by matches from the current match data.
+Strings like ~N are replaced by the Nth subexpression from the last
+global match. Does nothing if STRING is not a string.
+
+ON-STRING, if supplied, means to use the match data from a
+`string-match' on that string, rather than the global match data."
+ (when (stringp string)
+ (let ((old-data (match-data))
+ subexp)
+ (save-match-data
+ (while (string-match "~\\([0-9]\\)" string)
+ (setq subexp (string-to-number (match-string-no-properties 1 string))
+ string (replace-match
+ (save-match-data
+ (set-match-data old-data)
+ (match-string-no-properties subexp on-string))
+ t t string))))))
+ string)
+
+;;}}}
+;;{{{ Save Keywords
+
+(defmacro mmm-save-keyword (param)
+ "If the value of PARAM as a variable is non-nil, return the list
+\(:PARAM (symbol-value PARAM)), otherwise NIL. Best used only when it
+is important that nil values disappear."
+ `(if (and (boundp ',param) ,param)
+ (list (intern (concat ":" (symbol-name ',param))) ,param)
+ nil))
+
+(defmacro mmm-save-keywords (&rest params)
+ "Return a list saving the non-nil elements of PARAMS. E.g.
+\(let \(\(a 1) \(c 2)) \(mmm-save-keywords a b c)) ==> \(:a 1 :c 2)
+Use of this macro can make code more readable when there are a lot of
+PARAMS, but less readable when there are only a few. Also best used
+only when it is important that nil values disappear."
+ `(append ,@(mapcar #'(lambda (param)
+ (macroexpand `(mmm-save-keyword ,param)))
+ params)))
+
+;;}}}
+;;{{{ Looking Back At
+
+(defun mmm-looking-back-at (regexp &optional bound)
+ "Return t if text before point matches REGEXP.
+Modifies the match data. If supplied, BOUND means not to look farther
+back that that many characters before point. Otherwise, it defaults to
+\(length REGEXP), which is good enough when REGEXP is a simple
+string."
+ (eq (point)
+ (save-excursion
+ (and (re-search-backward regexp
+ (- (point) (or bound (length regexp)))
+ t)
+ (match-end 0)))))
+
+;;}}}
+;;{{{ Markers
+
+;; Mostly for remembering interactively made regions
+(defun mmm-make-marker (pos beg-p sticky-p)
+ "Make, and return, a marker at POS that is or isn't sticky.
+BEG-P represents whether the marker delimits the beginning of a
+region \(or the end of it). STICKY-P is whether it should be sticky,
+i.e. whether text inserted at the marker should be inside the region."
+ (let ((mkr (set-marker (make-marker) pos)))
+ (set-marker-insertion-type mkr (if beg-p (not sticky-p) sticky-p))
+ mkr))
+
+;;}}}
+
+(provide 'mmm-utils)
+
+;;; mmm-utils.el ends here
--- /dev/null
+;;; mmm-vars.el --- Variables for MMM Mode
+
+;; Copyright (C) 2000, 2004 by Michael Abraham Shulman
+;; Copyright (C) 2012, 2013 by Dmitry Gutov
+
+;; Author: Michael Abraham Shulman <viritrilbia@users.sourceforge.net>
+
+;;{{{ GPL
+
+;; 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.
+
+;; 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., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;}}}
+
+;;; Commentary:
+
+;; This file provides the definitions for the variables used by MMM
+;; Mode, as well as several functions to manipulate them. It also
+;; defines the errors that MMM Mode can signal.
+
+;;; Code:
+
+(require 'mmm-compat)
+(require 'cl)
+
+;; MISCELLANEOUS
+;;{{{ Shut up the Byte Compiler
+
+;; Otherwise it complains about undefined variables.
+(eval-when-compile
+ (defvar mmm-current-submode)
+ (defvar mmm-save-local-variables)
+ (defvar mmm-mode-string)
+ (defvar mmm-submode-mode-line-format)
+ (defvar mmm-mode-ext-classes-alist)
+ (defvar mmm-mode-prefix-key)
+ (defvar mmm-global-mode)
+ (defvar mmm-primary-mode)
+ (defvar mmm-classes-alist))
+
+;;}}}
+;;{{{ Error Conditions
+
+;; Most of these should be caught internally and never seen by the
+;; user, except when the user is creating submode regions manually.
+
+;; Signalled when we try to put a submode region inside one where it
+;; isn't meant to go.
+(put 'mmm-subregion-invalid-parent
+ 'error-conditions
+ '(mmm-subregion-invalid-parent mmm-error error))
+(put 'mmm-subregion-invalid-parent
+ 'error-message
+ "Invalid submode region parent")
+
+;; Signalled when we try to put a submode region overlapping others in
+;; an invalid way.
+(put 'mmm-subregion-invalid-placement
+ 'error-conditions
+ '(mmm-subregion-invalid-placement mmm-error error))
+(put 'mmm-subregion-invalid-placement
+ 'error-message
+ "Submode region placement invalid")
+
+;; Signalled when we try to apply a submode class that doesn't exist.
+(put 'mmm-invalid-submode-class
+ 'error-conditions
+ '(mmm-invalid-submode-class mmm-error error))
+(put 'mmm-invalid-submode-class
+ 'error-message
+ "Invalid or undefined submode class")
+
+;; Signalled by :match-submode functions when they are unable to
+;; resolve a submode. This error should *always* be caught internally
+;; and never seen by the user.
+(put 'mmm-no-matching-submode
+ 'error-conditions
+ '(mmm-no-matching-submode mmm-error error))
+(put 'mmm-no-matching-submode
+ 'error-message
+ "Internal error: no matching submode.")
+
+;;}}}
+
+;; USER VARIABLES
+;;{{{ Customization Group
+
+(defgroup mmm nil
+ "Multiple Major Modes in one buffer."
+ :group 'tools)
+
+;;}}}
+;;{{{ Save Local Variables
+
+(defvar mmm-c-derived-modes
+ '(c-mode c++-mode objc-mode pike-mode java-mode jde-mode javascript-mode
+ php-mode))
+
+(defvar mmm-save-local-variables
+ `(;; Don't use `function' (#') here!! We're already inside `quote'!
+ major-mode
+ comment-start
+ comment-end
+ (comment-line-start-skip buffer (fortran-mode))
+ comment-start-skip
+ (comment-column buffer)
+ comment-indent-function
+ comment-line-break-function
+ sentence-end
+ ,@(when mmm-xemacs
+ '(mode-popup-menu
+ (((lambda () current-menubar) . set-buffer-menubar))
+ ))
+ (font-lock-keywords buffer)
+ font-lock-set-defaults
+ font-lock-major-mode
+ font-lock-keywords-only
+ font-lock-keywords-case-fold-search
+ font-lock-syntax-table
+ font-lock-mark-block-function ; Override this?
+ font-lock-syntactic-keywords
+ parse-sexp-ignore-comments ; Fixes indentation in PHP-mode?
+ ;; Can be different in different buffers
+ (c-basic-offset
+ buffer (c-mode c++-mode objc-mode pike-mode java-mode jde-mode))
+ ;; These are necessary for C syntax parsing
+ (c-class-key nil ,mmm-c-derived-modes)
+ (c-extra-toplevel-key nil ,mmm-c-derived-modes)
+ (c-inexpr-class-key nil ,mmm-c-derived-modes)
+ (c-conditional-key nil ,mmm-c-derived-modes)
+ semantic-bovinate-toplevel-override
+ semantic-toplevel-bovine-table
+ ;; Indentation style control variables.
+ ;; These have to be localized in Emacs: see `mmm-mode-on'.
+ ,@(mapcar
+ #'(lambda (var) (list var nil mmm-c-derived-modes))
+ '(c++-template-syntax-table
+ c-<-op-cont-regexp
+ c->-op-cont-regexp
+ c-after-suffixed-type-decl-key
+ c-after-suffixed-type-maybe-decl-key
+ c-any-class-key
+ c-asm-stmt-kwds
+ c-assignment-op-regexp
+ c-backslash-column
+ c-basic-offset
+ c-bitfield-kwds
+ c-block-comment-prefix
+ c-block-decls-with-vars
+ c-block-prefix-charset
+ c-block-stmt-1-key
+ c-block-stmt-1-kwds
+ c-block-stmt-2-key
+ c-block-stmt-2-kwds
+ c-brace-list-key
+ c-cast-parens
+ c-class-key
+ c-class-kwds
+ c-cleanup-list
+ c-colon-type-list-re
+ c-comment-only-line-offset
+ c-comment-prefix-regexp
+ c-comment-start-regexp
+ c-cpp-defined-fns
+ c-current-comment-prefix
+ c-decl-block-key
+ c-decl-hangon-key
+ c-decl-prefix-or-start-re
+ c-decl-prefix-re
+ c-decl-spec-kwds
+ c-decl-start-kwds
+ c-decl-start-re
+ c-doc-comment-start-regexp
+ c-expr-kwds
+ c-file-offsets
+ c-file-style
+ c-hanging-braces-alist
+ c-hanging-colons-alist
+ c-hanging-comment-ender-p
+ c-hanging-comment-starter-p
+ c-hanging-semi\&comma-criteria
+ c-identifier-key
+ c-identifier-last-sym-match
+ c-identifier-start
+ c-identifier-syntax-modifications
+ c-identifier-syntax-table
+ c-in-comment-lc-prefix
+ c-indent-comment-alist
+ c-indent-comments-syntactically-p
+ c-indentation-style
+ c-inexpr-block-kwds
+ c-inexpr-class-kwds
+ c-keywords
+ c-keywords-obarray
+ c-keywords-regexp
+ c-known-type-key
+ c-label-key
+ c-label-kwds
+ c-label-kwds-regexp
+ c-label-minimum-indentation
+ c-lambda-kwds
+ c-literal-start-regexp
+ c-macro-with-semi-re
+ c-nonlabel-token-key
+ c-nonsymbol-chars
+ c-nonsymbol-token-regexp
+ c-not-decl-init-keywords
+ c-offsets-alist
+ c-opt-<>-arglist-start
+ c-opt-<>-arglist-start-in-paren
+ c-opt-<>-sexp-key
+ c-opt-access-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-prefix
+ c-opt-cpp-start
+ c-opt-decl-spec-key
+ c-opt-friend-key
+ c-opt-identifier-concat-key
+ c-opt-inexpr-block-key
+ c-opt-inexpr-brace-list-key
+ c-opt-inexpr-class-key
+ c-opt-lambda-key
+ c-opt-method-key
+ 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-kwds
+ c-other-decl-kwds
+ c-overloadable-operators-regexp
+ c-paragraph-separate
+ c-paragraph-start
+ c-paren-stmt-key
+ c-primary-expr-regexp
+ c-primitive-type-key
+ c-primitive-type-kwds
+ c-protection-kwds
+ c-recognize-<>-arglists
+ c-recognize-knr-p
+ c-recognize-paren-inits
+ c-recognize-typeless-decls
+ c-regular-keywords-regexp
+ c-simple-stmt-key
+ c-simple-stmt-kwds
+ c-special-brace-lists
+ c-specifier-key
+ c-specifier-kwds
+ c-stmt-delim-chars
+ c-stmt-delim-chars-with-comma
+ c-symbol-key
+ c-symbol-start
+ c-syntactic-eol
+ c-syntactic-ws-end
+ c-syntactic-ws-start
+ c-type-decl-prefix-key
+ c-type-decl-suffix-key
+ c-type-prefix-key
+ c-prefix-spec-kwds-re
+ c-typedef-key
+ c-typedef-decl-key
+ comment-end
+ comment-start
+ comment-start-skip))
+ ,@(mapcar
+ (lambda (var) (list var nil '(js-mode)))
+ '(js--quick-match-re
+ js--quick-match-re-func))
+ ;; Skeleton insertion
+ skeleton-transformation
+ ;; Abbrev mode
+ abbrev-mode
+ local-abbrev-table
+ ;; And finally the syntax table and local map.
+ ((syntax-table . set-syntax-table) buffer)
+ ((current-local-map . use-local-map) buffer)
+ paragraph-separate
+ paragraph-start
+ (whitespace-active-style buffer)
+ (whitespace-display-table buffer)
+ (whitespace-display-table-was-local buffer)
+ (whitespace-font-lock buffer)
+ (whitespace-font-lock-mode buffer)
+ (whitespace-font-lock-keywords buffer)
+ (whitespace-mode buffer)
+ )
+ "Which local variables to save for major mode regions.
+Each element has the form \(VARIABLE [TYPE [MODES]]), causing VARIABLE
+to be saved for all major modes in the list MODES. If MODES is t or
+absent, the variable is saved for all major modes. MODES can also be
+a function of no arguments which returns non-nil whenever the variable
+should be saved.
+
+TYPE should be either the symbol `global', meaning to save the
+variable globally, the symbol `buffer', meaning to save it per buffer,
+or the symbol `region', meaning to save it for each submode region.
+If TYPE has any other value, such as nil, or is absent, the variable
+is saved globally. If all optional parameters are omitted, the
+element may be simply VARIABLE instead of \(VARIABLE).
+
+It is possible for VARIABLE to be not a symbol but a cons cell of the
+form \(GETTER . SETTER), thus specifying special functions to set and
+get the value of the \"variable\". This is used for objects like
+local maps, syntax tables, etc. which need to be installed in a
+special way. GETTER should be a function of no arguments, and SETTER
+a function of one. In this case, even if TYPE and MODES are omitted,
+the list cannot be flattened--it must be \((GETTER . SETTER)).
+\"Variables\" of this type cannot be seen with `mmm-get-saved-local'.
+
+A single variable may appear more than once in this list, with
+different modes and/or types. If the same mode appears more than once
+for the same variable with different types, the behavior is undefined.
+Changing the value of this variable after MMM Mode has been activated
+in some buffer may produce unpredictable results.
+
+Globally saved variables are saved in the mmm-local-variables property
+of the mode symbol. Buffer saved variables are saved in the alist
+`mmm-buffer-saved-locals'. Region saved variables are saved in the
+mmm-local-variables property of the overlay.")
+
+(defvar mmm-buffer-saved-locals ()
+ "Stores saved local variables for this buffer, by mode.
+Each element looks like \(MODE \(VAR VALUE) ...).")
+(make-variable-buffer-local 'mmm-buffer-saved-locals)
+
+(defvar mmm-region-saved-locals-defaults ()
+ "Stores saved defaults for region-saved locals, by mode.
+Each element looks like \(MODE \(VAR VALUE) ...). Used to initialize
+new submode regions.")
+(make-variable-buffer-local 'mmm-region-saved-locals-defaults)
+
+(defvar mmm-region-saved-locals-for-dominant ()
+ "Stores saved region locals for the dominant major mode.
+The dominant major mode is considered to be one region for purposes of
+saving region variables. Region-saved variables for submode regions
+are saved as overlay properties.")
+(make-variable-buffer-local 'mmm-region-saved-locals-for-dominant)
+
+;;}}}
+;;{{{ Submode Faces
+
+(defgroup mmm-faces nil
+ "Faces and coloring for submode regions.
+In general, only background colors should be set, to avoid interfering
+with font-lock."
+ :group 'mmm)
+
+(defcustom mmm-submode-decoration-level 1
+ "*Amount of coloring to use in submode regions.
+Should be either 0, 1, or 2, representing None, Low, and High amounts
+of coloring respectively.
+* None (0) means to use no coloring at all.
+* Low (1) means to use `mmm-default-submode-face' for all submode
+ regions \(except for \"non-submode\" regions, i.e. those that are of
+ the primary mode) and `mmm-delimiter-face' for region delimiters.
+* High (2) means to use different faces for different types of submode
+ regions and delimiters, such as initialization code, expressions that
+ are output, declarations, and so on, as specified by the submode
+ class. The default faces are still used for regions that do not
+ specify a face."
+ :group 'mmm-faces
+ :type '(choice (const :tag "None" 0)
+ (const :tag "Low" 1)
+ (const :tag "High" 2)))
+
+(defface mmm-init-submode-face '((((background light)) (:background "Pink"))
+ (((background dark)) (:background "MediumOrchid"))
+ (t (:background "Pink")))
+ "Face used for submodes containing initialization code."
+ :group 'mmm-faces)
+
+(defface mmm-cleanup-submode-face '((((background light)) (:background "Wheat"))
+ (((background dark)) (:background "peru"))
+ (t (:background "Wheat")))
+ "Face used for submodes containing cleanup code."
+ :group 'mmm-faces)
+
+(defface mmm-declaration-submode-face '((((background light)) (:background "Aquamarine"))
+ (((background dark)) (:background "DarkTurquoise"))
+ (t (:background "Aquamarine")))
+ "Face used for submodes containing declarations."
+ :group 'mmm-faces)
+
+(defface mmm-comment-submode-face '((((background light)) (:background "SkyBlue"))
+ (((background dark)) (:background "SteelBlue"))
+ (t (:background "SkyBlue")))
+ "Face used for submodes containing comments and documentation."
+ :group 'mmm-faces)
+
+(defface mmm-output-submode-face '((((background light)) (:background "Plum"))
+ (((background dark)) (:background "MediumVioletRed"))
+ (t (:background "Plum")))
+ "Face used for submodes containing expression that are output."
+ :group 'mmm-faces)
+
+(defface mmm-special-submode-face '((((background light)) (:background "MediumSpringGreen"))
+ (((background dark)) (:background "ForestGreen"))
+ (t (:background "MediumSpringGreen")))
+ "Face used for special submodes not fitting any other category."
+ :group 'mmm-faces)
+
+(defface mmm-code-submode-face '((((background light)) (:background "LightGray"))
+ (((background dark)) (:background "DimGray"))
+ (t (:background "LightGray")))
+ "Face used for submodes containing ordinary code."
+ :group 'mmm-faces)
+
+(defface mmm-default-submode-face '((((background light)) (:background "gray85"))
+ (((background dark)) (:background "gray20"))
+ (t (:background "gray85")))
+ "Face used for all submodes at decoration level 1.
+Also used at decoration level 2 for submodes not specifying a type."
+ :group 'mmm-faces)
+
+(defface mmm-delimiter-face nil
+ "Face used to mark submode delimiters."
+ :group 'mmm-faces)
+
+;;}}}
+;;{{{ Mode Line Format
+
+(defcustom mmm-mode-string " MMM"
+ "*String to display in mode line as MMM minor mode indicator."
+ :group 'mmm
+ :type 'string)
+
+(defcustom mmm-submode-mode-line-format "~M[~m]"
+ "*Format of the mode-line display when point is in a submode region.
+
+~M is replaced by the name of the primary major mode \(which may be
+replaced by a combined-mode function, see the info documentation).
+
+~m is replaced by the submode region overlay's `display-name'
+property, if it has one. Otherwise it is replaced by the mode name of
+the submode region.
+
+If `mmm-primary-mode-display-name' is non-nil, then this variable is
+used even when point is not in a submode region \(i.e. it is in a
+primary mode region), with ~m being replaced by the value of that
+variable."
+ :group 'mmm
+ :type 'string)
+
+(defvar mmm-primary-mode-display-name nil
+ "If non-nil, displayed as the primary mode name in the mode line.
+See also `mmm-buffer-mode-display-name'.")
+(make-variable-buffer-local 'mmm-primary-mode-display-name)
+
+(defvar mmm-buffer-mode-display-name nil
+ "If non-nil, displayed in the mode line instead of the primary mode
+name, which is then shown next to it as if it were a submode when in a
+primary mode region, i.e. outside all submode regions.")
+(make-variable-buffer-local 'mmm-buffer-mode-display-name)
+
+(defun mmm-set-mode-line ()
+ "Set the mode line display correctly for the current submode,
+according to `mmm-submode-mode-line-format'."
+ (let ((primary (or mmm-primary-mode-display-name
+ (get mmm-primary-mode 'mmm-mode-name)))
+ (submode (and mmm-current-overlay
+ (or (overlay-get mmm-current-overlay 'display-name)
+ (get mmm-current-submode 'mmm-mode-name)))))
+ (if mmm-buffer-mode-display-name
+ (setq mode-name
+ (mmm-format-string mmm-submode-mode-line-format
+ `(("~M" . ,mmm-buffer-mode-display-name)
+ ("~m" . ,(or submode primary)))))
+ (if submode
+ (setq mode-name
+ (mmm-format-string mmm-submode-mode-line-format
+ `(("~M" . ,primary)
+ ("~m" . ,submode))))
+ (setq mode-name primary))))
+ (force-mode-line-update))
+
+;;}}}
+;;{{{ Submode Classes
+
+(defvar mmm-classes nil
+ "*List of submode classes that apply to a buffer.
+Generally set in a file local variables list. Can either be one
+symbol, or a list of symbols. Automatically buffer-local.")
+(make-variable-buffer-local 'mmm-classes)
+
+(defvar mmm-global-classes '(universal)
+ "*List of submode classes that apply to all buffers.
+Can be overridden in a file local variables list.")
+
+;;}}}
+;;{{{ Modes and Extensions
+
+(defcustom mmm-mode-ext-classes-alist nil
+ "Alist of submode classes for major modes and/or file extensions.
+This variable can now be directly modified.
+
+Elements look like \(MODE EXT CLASS), where MODE is a major mode, EXT
+is a regexp to match a filename such as in `auto-mode-alist', and
+CLASS is a submode class. CLASS is activated in all buffers in mode
+MODE \(if non-nil) and whose filenames match EXT \(if non-nil). If
+both MODE and EXT are nil, CLASS is activated in all buffers. If CLASS
+is the symbol t, MMM Mode is turned on in all buffers matching MODE
+and EXT, but no classes are activated.
+
+See `mmm-global-mode'