summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--cache/.gitignore2
-rw-r--r--init.d/.gitignore1
-rw-r--r--init.d/main.org2715
-rw-r--r--init.el5
-rw-r--r--lisp/filladapt.el981
-rw-r--r--lisp/promela-mode.el985
-rw-r--r--lisp/template.el2609
-rw-r--r--lisp/themes/color-themes-alex.el48
-rw-r--r--lisp/themes/color-themes-monokai-alex.el33
-rw-r--r--lisp/winring.el597
-rw-r--r--templates/TEMPLATE.py.tpl3
12 files changed, 7982 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e8ad6bb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.elc
+#*#
+emacs-custom.el
diff --git a/cache/.gitignore b/cache/.gitignore
new file mode 100644
index 0000000..d6b7ef3
--- /dev/null
+++ b/cache/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/init.d/.gitignore b/init.d/.gitignore
new file mode 100644
index 0000000..abf136d
--- /dev/null
+++ b/init.d/.gitignore
@@ -0,0 +1 @@
+*.el
diff --git a/init.d/main.org b/init.d/main.org
new file mode 100644
index 0000000..db999ab
--- /dev/null
+++ b/init.d/main.org
@@ -0,0 +1,2715 @@
+#+PROPERTY: header-args :comments link :tangle yes :noweb no-export :results silent
+#+STARTUP: overview
+
+* About this file
+
+This is my main emacs init file. It can be loaded by the init.el with
+org-babel or can be tangled and compiled to =main.elc= and loaded
+directly.
+
+If you're viewing this file in an org-mode buffer, you can open source
+code blocks (those are the ones in begin_src) in a separate buffer by
+moving your point inside them and typing C-c '
+(org-edit-special). This opens another buffer in emacs-lisp-mode, so
+you can use M-x eval-buffer to load the changes.
+
+* Personal information
+
+#+begin_src emacs-lisp
+ (setq user-full-name "Alexander Sulfrian"
+ user-mail-address "alexander@sulfrian.net")
+#+end_src
+
+* Initialization
+** packages
+
+Add some more package repositories.
+
+#+begin_src emacs-lisp
+ (nconc package-archives
+ '(("melpa-stable" . "http://stable.melpa.org/packages/")
+ ("melpa" . "http://melpa.org/packages/")
+ ("org" . "http://orgmode.org/elpa/")
+ ("marmalade" . "http://marmalade-repo.org/packages/")))
+#+end_src
+
+By default the package system is initialized after evaluating the
+user-init-file (this file) and I could not customize packages in this
+file. So I initialize the package system right here and disable the
+automatic initialization.
+
+#+begin_src emacs-lisp
+ (setq package-enable-at-startup nil
+ package-user-dir (locate-user-emacs-file "cache/elpa/"))
+ (package-initialize nil)
+#+end_src
+
+** use-package
+
+I require use-package to simplify the configuration. This is a
+requirement for this configuration, so I install it here.
+
+#+begin_src emacs-lisp
+ (eval-when-compile
+ (unless (package-installed-p 'use-package)
+ (package-install 'use-package))
+ (setq use-package-verbose t)
+ (require 'use-package))
+#+end_src
+
+** auto-compile
+
+For faster start-up times, this init file should be compiled into
+byte code. I use auto-compile mode for this. It will recompile files
+on load if the byte compiled file exists but is outdated.
+
+#+begin_src emacs-lisp
+ (use-package auto-compile
+ :ensure t
+ :config (auto-compile-on-load-mode))
+#+end_src
+
+For safety reasons emacs should prefer the newer file, if the =*.el=
+and =*.elc= file exists.
+
+#+begin_src emacs-lisp
+ (setq load-prefer-newer t)
+#+end_src
+
+** dash
+
+#+begin_src emacs-lisp
+(use-package dash
+ :demand t
+ :ensure t)
+#+end_src emacs-lisp
+
+* General Setup
+** Encoding
+
+Set all the encoding stuff to utf-8 (but to latin-1 on ZEDAT hosts).
+
+#+begin_src emacs-lisp
+ (let ((encoding
+ (if (string-match "\\.zedat.fu-berlin.de\\'" system-name)
+ 'latin-1
+ 'utf-8)))
+ (setq locale-coding-system encoding)
+ (set-terminal-coding-system encoding)
+ (set-keyboard-coding-system encoding)
+ (set-selection-coding-system encoding)
+ (prefer-coding-system encoding))
+#+end_src
+
+** Customizing
+
+Emacs should not edit the init.el file when saving stuff from
+customize. So I set a separate custom-file and load it.
+
+#+begin_src emacs-lisp
+ (setq custom-file "~/.emacs.d/emacs-custom.el")
+ (load custom-file)
+#+end_src
+
+** Helper for configuration
+
+I need some functions to simplify the configuration below. They are
+defined here.
+
+*** Get buffers with specific minor-mode
+
+Simply get a list of all buffers, where the specified minor-mode is
+active.
+
+#+begin_src emacs-lisp
+ (defun alex/get-buffers-with (mode)
+ "Get a list of buffers where the given MODE is active. It is done by
+ evaluating the given symbol in all buffers and return a list with
+ all buffers where it evaluates to t. So actually MODE could be any
+ buffer-local variable."
+ (let ((state (mapcar (lambda (buf)
+ (with-current-buffer buf
+ (when (and (boundp mode)
+ (symbol-value mode))
+ buf)))
+ (buffer-list))))
+ (delq nil state)))
+#+end_src
+
+*** Ignore errors of a function
+
+This macro first tries to execute the given fun and evaluate the body
+afterwards, even if fun raised an error. After evaluation of body the
+original return value (or error) of fun is returned.
+
+This is useful for around advices, that should be reset something
+after calling the adviced function, even if it raises an error.
+
+#+begin_src emacs-lisp
+ (defmacro alex/safe-call (fun &rest body)
+ "Evaluate FUN and catch all errors, evaluates BODY afterwards
+ (regardless whether an error was raised or not) and finally returns
+ the result of FUN captured earlier or re-throw the error."
+ `(let* ((tmp (condition-case err
+ (list (,@fun) nil)
+ (error (list nil err))))
+ (err (cadr tmp))
+ (result (car tmp)))
+ ,@body
+ (when err
+ (signal (car err) (cdr err)))
+ result))
+#+end_src
+
+*** Get next element from list
+
+This lisp function returns the next element from a list. It is useful
+if you want to switch a setting between multiple values.
+
+#+begin_src emacs-lisp
+ (defun alex/get-next (old list)
+ "Returns the element after OLD in LIST or the first element if OLD
+ is the last element or is not in LIST."
+ (let ((index (or (cl-position old list) -1))
+ (len (length list)))
+ (nth (% (+ 1 index) len) list)))
+#+end_src
+
+*** Exclude list for globalized minor-modes
+
+I want to define some global-minor-modes, but keep them disabled in
+certain modes, buffers or in the minibuffer. So I declare some helper
+to define exclude lists for custom global-minor-modes.
+
+#+begin_src emacs-lisp
+ (defun alex/parse-exclude-list (exclude-list)
+ "Convert a free from exlude list (with multiple keywords) in a
+ propper assoc list with the keywords as key and the values in
+ between as values."
+ (let ((keyword nil)
+ (res '())
+ (args '()))
+ (dolist (elem exclude-list)
+ (if (keywordp elem)
+ (progn
+ (when keyword (setq res (nconc res (list keyword (or args 'empty)))))
+ (setq keyword elem
+ args '()))
+ (setq args (nconc args (list elem)))))
+ (nconc res (list keyword (or args 'empty)))))
+
+ (defmacro alex/check-list (list var &rest body)
+ "Simple macro to check if body returns non-nil for any element in
+ the list."
+ `(if (eq ,list 'empty)
+ nil
+ (delq nil (mapcar
+ (lambda (,var)
+ ,@body)
+ ,list))))
+
+ (defun alex/safe-get-value (var)
+ "Get the value of the variable of nil if the given variable does not exists."
+ (if (boundp var)
+ (symbol-value var)
+ nil))
+
+ (defun alex/minor-mode-exclude (mode)
+ "Check the exclude list for the given mode. Returns t if the mode
+ should be excluded, else nil."
+ (let* ((exclude-list (intern (concat (symbol-name mode) "-exclude-list")))
+ (excludes (alex/parse-exclude-list (symbol-value exclude-list))))
+ (cond
+ ((and (plist-get excludes :minibuffer) (minibufferp))
+ t)
+ ((alex/check-list (plist-get excludes :mode) mode
+ (cond ((derived-mode-p mode) t)
+ ((alex/safe-get-value mode) t)))
+ t)
+ ((alex/check-list (plist-get excludes :buffer) buf
+ (cond
+ ((and (symbolp buf) (eq (current-buffer)
+ (alex/safe-get-value buf)))
+ t)
+ ((and buf (eq (current-buffer) buf))
+ t)))
+ t)
+ (t nil))))
+#+end_src
+
+Last I define a macro for defining a globalized minor-mode with the
+exclude list feature.
+
+#+begin_src emacs-lisp
+ (defmacro alex/global-excluding-minor-mode (global mode &rest body)
+ "Define a global-minor-mode that can be disabled on some modes or
+ buffers. BODY is executed each time when the mode should be
+ activated (it passed the exclude list at this position). If BODY
+ is empty the mode will be simply activated."
+ (if `(not ,body)
+ `(define-globalized-minor-mode ,global ,mode
+ (lambda ()
+ (unless (alex/minor-mode-exclude ',mode)
+ (,mode 1))))
+ `(define-globalized-minor-mode ,global ,mode
+ (lambda ()
+ (unless (alex/minor-mode-exclude ',mode)
+ ,@body)))))
+
+ (defmacro alex/minor-mode-exclude-list (mode)
+ `(defvar ,(intern (concat (symbol-name mode) "-exclude-list"))
+ ()
+ (concat "Exclude list for " (symbol-name ',mode) ". "
+ "Can contain :minibuffer, :modeq and :buffer.")))
+
+ (defun alex/build-global-name (mode)
+ "Build the symbol for the global mode by inserting 'global-' after
+ 'alex/' or prepending 'alex/gloabl-' if MODE does not start with the
+ personal prefix."
+ (let ((name (symbol-name mode)))
+ (intern
+ (if (string-match "^alex/" name)
+ (replace-regexp-in-string "^alex/" "\\&global-" name)
+ (concat "alex/global-" name)))))
+
+ (defun alex/define-global-excluding-minor-mode (mode &rest body)
+ (let ((global (alex/build-global-name mode)))
+ (eval `(alex/global-excluding-minor-mode ,global ,mode ,body))
+ (eval `(alex/minor-mode-exclude-list ,mode))))
+#+end_src
+
+** Cache directory
+
+I want to keep all the changing files in one place, so I create
+=~/.emacs.d/cache/= for this purpose.
+
+#+begin_src emacs-lisp
+ (let ((cache (locate-user-emacs-file "cache/")))
+ (unless (file-directory-p cache)
+ (make-directory cache)))
+#+end_src
+
+Additionally I define a helper function to create a file name inside
+this cache directory.
+
+#+begin_src emacs-lisp
+ (defun alex/cache-file (filename)
+ (locate-user-emacs-file (concat "cache/" filename)))
+#+end_src
+
+*** recentf
+
+Save the history of the last 1000 visited files.
+
+#+begin_src emacs-lisp
+ (setq recentf-save-file (alex/cache-file "recentf")
+ recentf-max-saved-items 1000)
+ (recentf-mode 1)
+#+end_src
+
+*** save-place
+
+Save the last position in a file and raise the limit to 10k elements.
+
+#+begin_src emacs-lisp
+ (use-package saveplace
+ :config
+ (setq save-place-file (alex/cache-file "saveplace")
+ save-place-limit 10000)
+ (setq-default save-place t))
+#+end_src
+
+*** savehist
+
+Save a lot of history between emacs restarts. Save everything, but do
+not keep duplicates.
+
+#+begin_src emacs-lisp
+ (setq savehist-file (alex/cache-file "savehist")
+
+ history-length t
+ history-delete-duplicates t
+
+ savehist-save-minibuffer-history t
+ savehist-additional-variables '(kill-ring
+ search-ring
+ regexp-search-ring))
+#+end_src
+
+Enable the =savehist-mode=. This has to be below the configuration,
+because the history is loaded when this mode is activated the first
+time. So the =savehist-file= has to be configured when activating.
+
+#+begin_src emacs-lisp
+ (savehist-mode 1)
+#+end_src
+
+*** bookmarks
+
+Bookmarks are great to remember various positions in files. Save the
+bookmark file every time I make a modification (so that I do not loose
+a change, even if emacs or my laptop crashes).
+
+#+begin_src emacs-lisp
+ (setq bookmark-default-file (alex/cache-file "bookmarks")
+ bookmark-save-flag 1)
+#+end_src
+
+*** backups
+
+Do not save backup files into the directory of the original file.
+
+#+begin_src emacs-lisp
+ (setq backup-directory-alist '(("." . "~/.emacs.d/backups")))
+#+end_src
+
+Do not delete old backup files.
+
+#+begin_src emacs-lisp
+ (setq delete-old-versions -1
+ version-control t)
+#+end_src
+
+Make backups even for files under version control.
+
+#+begin_src emacs-lisp
+ (setq vc-make-backup-files t)
+#+end_src
+
+*** auto-save
+
+Do not save auto-save files into the directory of the original
+file (especially important for editing files via tramp).
+
+#+begin_src emacs-lisp
+ (setq auto-save-file-name-transforms
+ `((".*" ,(alex/cache-file "auto-save-list/") t)))
+#+end_src
+
+** Remove some annoyances
+*** No startup message
+
+#+begin_src emacs-lisp
+ (setq inhibit-startup-message t)
+#+end_src
+
+*** Newline at end of file
+
+Require a newline at end of file, but do not insert newlines
+automatically just by moving the cursor down.
+
+#+begin_src emacs-lisp
+ (setq require-final-newline t
+ next-line-add-newlines nil)
+#+end_src
+
+*** Yes or No
+
+I do not want to have to type =yes= and =no=. =y= or =n= should be
+sufficient.
+
+#+begin_src emacs-lisp
+ (fset 'yes-or-no-p 'y-or-n-p)
+#+end_src
+
+*** Symbolic links and version control
+
+Visit the real file (without question), if editing a symbolic links
+that points to a file under version control.
+
+#+begin_src emacs-lisp
+ (setq vc-follow-symlinks t)
+#+end_src
+
+** Visual
+*** Window configuration
+
+Clean up the UI. No toolbar, but use scrollbars and tooltips to keep
+the minibuffer clean.
+
+#+begin_src emacs-lisp
+ (tool-bar-mode -1)
+ (tooltip-mode 1)
+ (scroll-bar-mode 1)
+#+end_src
+
+Use extremely small scroll-bars on the right.
+
+#+begin_src emacs-lisp
+ (set-scroll-bar-mode 'right)
+ (set-frame-parameter nil 'scroll-bar-width 10)
+ (nconc default-frame-alist '((scroll-bar-width . 10)))
+#+end_src
+
+The menu-bar is helpful in the terminal (under X you can get a menu on
+demand with <F10>). So I enable the menu-bar if no window-system is
+available. To show the menu also in an emacsclient in the terminal, I
+have to add a hook in the =after-make-frame-function=.
+
+#+begin_src emacs-lisp
+ (defun alex/update-menu-bar (&optional frame)
+ "This displays the menu bar if the given FRAME (default: selected
+ frame) is in a terminal"
+ (let ((status (if (display-graphic-p frame) 0 1)))
+ (set-frame-parameter frame 'menu-bar-lines status)))
+
+ (alex/update-menu-bar)
+ (add-hook 'after-make-frame-functions 'alex/update-menu-bar)
+#+end_src
+
+*** Color-theme
+
+Use own color theme and switch it depending whether the frame is on
+terminal or under X11.
+
+#+begin_src emacs-lisp
+ (use-package color-theme
+ :demand t
+ :config
+ (setq color-theme-directory "~/.emacs.d/lisp/themes/"
+ color-theme-load-all-themes nil)
+
+ (color-theme-initialize)
+ (color-theme-monokai-alex)
+
+ (defun alex/update-color-theme (&optional frame)
+ (let ((color-theme-is-global nil))
+ (if (display-graphic-p frame)
+ (color-theme-monokai-alex)
+ (color-theme-alex-console))))
+ (add-hook 'after-make-frame-functions 'alex/update-color-theme))
+#+end_src
+
+I always want to have as much as possible syntax highlighting.
+
+#+begin_src emacs-lisp
+ (global-font-lock-mode t)
+ (setq font-lock-maximum-decoration t)
+#+end_src
+
+*** Cleanup minor-modes in modeline
+
+I want to hide some minor-modes, if they are activated in nearly all
+buffers or it is irrelevant if they are activated.
+
+To be compatible with powerline I use rich-minority, but I add some
+custom stuff to fake the interface of diminish so that I can use the
+diminish feature of use-package.
+
+I can use :diminish in use-package with either a mode name or e regexp
+to hide matching modes.
+
+#+begin_src emacs-lisp
+ (use-package rich-minority
+ :ensure t
+ :config
+ (defvar alex/minor-mode-blacklist ()
+ "List of regexp that is matched against the lighter of all
+ minor-modes. All matching minor-modes are hidden in the mode line.")
+
+ (defun alex/rm-add-blacklist (regexp)
+ "Add the given REGEXP to alex/minor-modes-blacklist and updates the
+ combined regexp in rm-blacklist afterwards."
+ (unless (member regexp alex/minor-mode-blacklist)
+ (setq alex/minor-mode-blacklist
+ (nconc alex/minor-mode-blacklist (list regexp)))
+ (alex/update-rm-blacklist))
+ alex/minor-mode-blacklist)
+
+ (defun alex/update-rm-blacklist ()
+ "Update rm-blacklist and build a regexp from the multiple values in
+ alex/minor-modes-blacklist."
+ (setq rm-blacklist
+ (format "^\\(%s\\)$"
+ (mapconcat #'identity alex/minor-mode-blacklist "\\|"))))
+
+ (defun alex/get-lighter (mode)
+ "Get the lighter for the given minor-mode."
+ (let ((value (assoc mode minor-mode-alist)))
+ (if value
+ (let ((lighter (cadr value)))
+ (if (symbolp lighter)
+ (when (boundp lighter)
+ (eval lighter))
+ lighter))
+ nil)))
+
+ (defun diminish (mode &optional regexp)
+ "This is a fake diminish with rich-minority-mode. It accepts uses
+ either the MODE or if given the REGEXP to hide the mode."
+ (if (and regexp (> (length regexp) 0))
+ (alex/rm-add-blacklist regexp)
+ (let ((lighter (alex/get-lighter mode)))
+ (when lighter
+ (alex/rm-add-blacklist lighter)))))
+
+ (rich-minority-mode 1))
+#+end_src
+
+*** Trailing whitespaces
+
+I generally want to show trailing whitespaces, but there are several
+exceptions. Per default there is only a buffer local variable to
+control this feature. I create a simple minor-mode, so that I could
+simply activate or deactivate this feature.
+
+#+begin_src emacs-lisp
+ (define-minor-mode alex/tw-mode
+ "trailing-whitespace-mode"
+ :lighter " TW"
+ (setq show-trailing-whitespace alex/tw-mode))
+
+ (alex/define-global-excluding-minor-mode 'alex/tw-mode)
+#+end_src
+
+I want to disable trailing whitespaces in the minibuffer, in weechat,
+helm and term-mode and in the which-key buffer. So I define here the
+exclude list.
+
+#+begin_src emacs-lisp
+ (setq alex/tw-mode-exclude-list
+ '(:minibuffer
+ :mode
+ helm--remap-mouse-mode
+ weechat-mode
+ term-mode
+ Custom-mode
+ :buffer
+ which-key--buffer))
+#+end_src
+
+And now activate the new global mode and hide it from the mode line.
+
+#+begin_src emacs-lisp
+ (alex/global-tw-mode t)
+ (diminish 'alex/tw-mode)
+#+end_src
+
+*** Visual-wrap-column
+
+Sometimes I want to force =visual-line-wrap= at a specific column (in
+contrast to the window width). This is especially useful for emails,
+that are badly formatted with long lines. =visual-line-wrap= will
+split long lines at the word-break before the specified column.
+
+#+begin_src emacs-lisp
+ (defvar alex/visual-wrap-column nil
+ "Column to force visual line wrap. Use `alex/set-visual-wrap-column'
+ to change the value.")
+
+ (defun alex/set-visual-wrap-column (new-wrap-column &optional buffer)
+ "Force visual line wrap at NEW-WRAP-COLUMN in BUFFER (defaults to
+ current buffer) by setting the right-hand margin on every window that
+ displays BUFFER. A value of NIL or 0 for NEW-WRAP-COLUMN disables this
+ behavior."
+ (interactive (list (read-number "New visual wrap column, 0 to disable: "
+ (or alex/visual-wrap-column fill-column 0))))
+ (when (and (numberp new-wrap-column)
+ (zerop new-wrap-column))
+ (setq new-wrap-column nil))
+
+ (with-current-buffer (or buffer (current-buffer))
+ (visual-line-mode t)
+ (set (make-local-variable 'alex/visual-wrap-column) new-wrap-column)
+ (add-hook 'window-configuration-change-hook
+ 'alex/update-visual-wrap-column nil t)
+
+ (let ((windows (get-buffer-window-list)))
+ (dolist (win windows)
+ (when (window-live-p win)
+ (with-selected-window win
+ (alex/update-visual-wrap-column)))))))
+
+ (defun alex/update-visual-wrap-column ()
+ "Update the right margin of the current window, to match the
+ available space to `alex/visual-wrap-column'."
+ (if (not alex/visual-wrap-column)
+ (set-window-margins nil nil)
+ (let* ((current-margins (window-margins))
+ (right-margin (or (cdr current-margins) 0))
+ (current-width (window-width))
+ (current-available (+ current-width right-margin)))
+ (if (<= current-available alex/visual-wrap-column)
+ (set-window-margins nil (car current-margins))
+ (set-window-margins nil (car current-margins)
+ (- current-available alex/visual-wrap-column))))))
+#+end_src
+
+** Localization
+
+I want to use german names for month and weekdays.
+
+#+begin_src emacs-lisp
+ (setq calendar-week-start-day 1
+ calendar-day-name-array ["Sonntag" "Montag" "Dienstag" "Mittwoch"
+ "Donnerstag" "Freitag" "Samstag"]
+ calendar-month-name-array ["Januar" "Februar" "März" "April" "Mai"
+ "Juni" "Juli" "August" "September"
+ "Oktober" "November" "Dezember"])
+#+end_src
+
+** Browser
+
+I have a simple wrapper script to be able to easily switch to a
+different browser. So I only have to configure to use this wrapper
+script.
+
+#+begin_src emacs-lisp
+ (setq browse-url-browser-function 'browse-url-generic
+ browse-url-generic-program "browser")
+#+end_src
+
+** Movement
+
+The defaults for the cursor movement and scrolling are not very good,
+so I need to customize the settings to match the expectations.
+
+*** Scrolling
+
+If I move the cursor out of screen, I do not want to jump to recenter
+the cursor, but scroll just as far to display the cursor again.
+
+#+begin_src emacs-lisp
+ (setq scroll-conservatively 10000
+ auto-window-vscroll nil)
+#+end_src
+
+Do not accelerate mouse scrolling.
+
+#+begin_src emacs-lisp
+ (setq mouse-wheel-progressive-speed nil)
+#+end_src
+
+Automatic scroll the compilation output to the bottom (or the first
+error).
+
+#+begin_src emacs-lisp
+ (setq compilation-scroll-output t)
+#+end_src
+
+*** Automatic indentation
+
+Automatic indent new lines.
+
+#+begin_src emacs-lisp
+ (bind-key "RET" 'newline-and-indent)
+#+end_src
+
+But clean whitespaces, if the indentation is abandoned.
+
+#+begin_src emacs-lisp
+ (use-package clean-aindent-mode
+ :config
+ (clean-aindent-mode t))
+#+end_src
+
+*** Back to indentation
+
+I want to have a better handling for the =<home>= key. Per default I
+want to move the cursor to the end of the indentation (first
+non-whitespace character). Only if the cursor is already at that
+position, I want to move to the beginning of the line.
+
+#+begin_src emacs-lisp
+ (defun alex/back-to-indentation-or-beginning ()
+ "Move the point to the first non-whitespace character on the line,
+ of if it is already there, to the beginning of the line."
+ (interactive)
+ (if (= (point) (save-excursion (back-to-indentation) (point)))
+ (beginning-of-line)
+ (back-to-indentation)))
+
+ (bind-key "<home>" 'alex/back-to-indentation-or-beginning)
+#+end_src
+
+*** Ungreedy kill-word
+
+The default =kill-word= (and =backward-kill-word=) is a bit greedy. I
+want to replace =forward-word= in the original definition with
+=forward-same-syntax=.
+
+This could not be done with an advice because =forward-word= is a byte
+code primitive and could not be replaced with =flet= or something like
+that. So I have to copy the original definition of kill-word here and
+simple do the replacement in the source.
+
+#+begin_src emacs-lisp
+ (defun kill-word (arg)
+ "Kill characters forward until encountering the end of a word.
+ With argument ARG, do this that many times."
+ (interactive "p")
+ (kill-region (point) (progn (forward-same-syntax arg) (point))))
+#+end_src
+
+** Selection
+
+The selection is the region between the mark and the point. But I want
+to see the active region, so I want to ensure, that
+transient-mark-mode is enabled globally.
+
+#+begin_src emacs-lisp
+(transient-mark-mode 1)
+#+end_src
+
+Additionally I have some enhancements to the default behaviour of some
+commands.
+
+*** Kill or copy whole line
+
+If no region is active, I want to kill/copy the current line.
+
+#+begin_src emacs-lisp
+ (defun alex/whole-line (func beg end &rest region)
+ (interactive (if mark-active
+ (list (region-beginning) (region-end))
+ (list (line-beginning-position)
+ (line-beginning-position 2))))
+ (apply func beg end region))
+
+ (advice-add 'kill-ring-save :around #'alex/whole-line)
+ (advice-add 'kill-region :around #'alex/whole-line)
+#+end_src
+
+*** Rectangle selection
+
+The rectangle selection of cua mode works very well, but I only want
+the rectangle selection mode and not the C-z/C-x/C-c/C-v bindings.
+
+#+begin_src emacs-lisp
+ (setq cua-rectangle-mark-key (kbd "M-SPC")
+ cua-delete-selection nil)
+ (cua-selection-mode t)
+#+end_src
+
+*** X11 clipboard
+
+Use the X11 clipboard in addition to the primary selection, because
+some other X11 apps can only use the X11 clipboard.
+
+#+begin_src emacs-lisp
+ (setq x-select-enable-clipboard t)
+ (setq interprogram-paste-function 'x-selection-value)
+#+end_src
+
+** Custom commands
+
+Here I define some global custom commands. These commands are bind
+in the =global-map= and are not associated with any other package.
+
+*** Open terminal
+
+Open an external terminal in the default directory of the current
+buffer. In most cases this is the directory containing the file of the
+current buffer.
+
+#+begin_src emacs-lisp
+ (defun alex/open-buffer-shell ()
+ "Open a terminal in the default directory of the current buffer."
+ (interactive)
+ (if default-directory
+ (start-process-shell-command
+ "urxvt"
+ nil
+ (concat "DIR=" default-directory " urxvt"))
+ (message "Buffer does not contain a file.")))
+
+ (bind-key "<f12>" 'alex/open-buffer-shell)
+#+end_src
+
+** Bug fixes
+
+A few workarounds about some strange emacs behaviour.
+
+*** Key mapping
+
+Some versions of urxvt send some strange key codes for some key
+combinations. The following table contains the mappings from the
+key codes send by urxvt and the real keys.
+
+#+tblname: key-mappings
+| Keycode | Key |
+|-------------+-------------|
+| M-[ Z | <S-tab> |
+| <select> | <S-up> |
+| M-[ b | <S-down> |
+| M-[ c | <S-right> |
+| M-[ d | <S-left> |
+| M-O a | <C-up> |
+| M-O b | <C-down> |
+| M-O c | <C-right> |
+| M-O d | <C-left> |
+| ESC M-O a | <C-M-up> |
+| ESC M-O b | <C-M-down> |
+| ESC M-O c | <C-M-right> |
+| ESC M-O d | <C-M-left> |
+| ESC M-O A | <M-up> |
+| ESC M-O B | <M-down> |
+| ESC M-O C | <M-right> |
+| ESC M-O D | <M-left> |
+| ESC M-[ a | <M-S-up> |
+| ESC M-[ b | <M-S-down> |
+| ESC M-[ c | <M-S-right> |
+| ESC M-[ d | <M-S-left> |
+| <clearline> | <C-end> |
+
+The tables is converted into the real key mappings with the following
+function. It uses the org-babel stuff to convert the org-table into an
+emacs-lisp variable.
+
+#+begin_src emacs-lisp :var mappings=key-mappings
+ (if (not window-system)
+ (mapc (lambda (row)
+ (define-key function-key-map
+ (read-kbd-macro (car row))
+ (read-kbd-macro (cadr row))))
+ mappings))
+#+end_src
+
+*** Scroll speed
+
+The scroll speed of emacs (at least 24.1) was very slow (esp. in
+wanderlust summary buffers). The problem was, that for each line the
+paragraph direction was checked. Because I do not use right-to-left
+languages, I disable the auto detection
+
+#+begin_src emacs-lisp
+ (when (boundp 'bidi-paragraph-direction)
+ (setq-default bidi-paragraph-direction 'left-to-right))
+#+end_src
+
+*** Sit-for
+
+=sit-for= seems to modify the current-buffer and causes error message
+during find-file (if a backup file exists). This fixes the problem
+providing =sit-for= with a temporary buffer, that is destroyed
+afterwards.
+
+#+begin_src emacs-lisp
+ (defun alex/save-current-buffer (orig-fun &rest args)
+ "Do not allow the advised function to change the current-buffer."
+ (with-temp-buffer
+ (apply orig-fun args)))
+ (advice-add 'sit-for :around #'alex/save-current-buffer)
+#+end_src
+* Modes
+** Core modes
+
+These modes are part of the core and the auto-mode-alist is set up
+automatically. So the mode should not be required.
+
+*** cc-mode
+
+Here I only add a hook for the configuration and a key-binding for the
+mode key-map.
+
+#+begin_src emacs-lisp
+ (defun alex/c-mode-setup ()
+ ;; auto fill at column 80
+ (setq fill-column 80)
+ (turn-on-auto-fill)
+
+ ;; semantic as for auto-complete
+ (add-to-list 'ac-sources ac-source-semantic)
+
+ ;; now '_' is not considered a word-delimiter
+ (modify-syntax-entry ?_ "w")
+
+ ;; indentation style
+ (c-set-style "linux")
+ (setq indent-tabs-mode t
+ c-basic-offset 4
+ tab-width 4)
+
+ (bind-key "C-c o" 'ff-find-other-file 'c-mode-map))
+
+ (add-hook 'c-mode-common-hook 'alex/c-mode-setup)
+#+end_src
+
+*** text-mode
+
+I only activate =auto-fill-mode= for =text-mode= here. Additionally I
+activate =text-mode= automatically for all files called only with
+capital letters and without extension (like README or INSTALL).
+
+#+begin_src emacs-lisp
+(setq text-mode-hook 'turn-on-auto-fill)
+(add-to-list 'auto-mode-alist '("\\`[A-Z]+\\'" . text-mode))
+#+end_src
+
+** Additional modes
+
+Some additional modes for editing of special files types. Most of
+them do not requires special configuration only =:mode= or
+=:interpreter= from use-package to enable auto loading.
+
+*** apache-mode
+
+#+begin_src emacs-lisp
+ (use-package apache-mode
+ :mode ("\.htaccess$" "htpd\\.conf$" "srm\\.conf$" "access\\.conf$"
+ "apache[12]\?\\.conf$" "commonapache[12]\?\\.conf$"
+ "\/sites-enabled\/.*\.conf$"))
+#+end_src
+
+*** arduino-mode
+
+#+begin_src emacs-lisp
+ (use-package arduino-mode
+ :mode "\\.pde\\'")
+#+end_src
+
+*** auctex
+
+#+begin_src emacs-lisp
+ (use-package auctex
+ :mode ("\\.tex\\'" . latex-mode)
+ :commands (latex-mode LaTeX-mode plain-tex-mode)
+ :config
+ (setq TeX-view-program-list '(("Zathura" "zathura %o"))
+ TeX-view-program-selection '((output-pdf "Zathura"))))
+#+end_src
+
+*** autoconf-mode
+
+#+begin_src emacs-lisp
+ (use-package autoconf-mode
+ :mode ("\\.ac\\'" "configure\\.in\\'"
+ ("\\.at\\'" . autotest-mode)))
+#+end_src
+
+*** bibtex
+
+#+begin_src emacs-lisp
+ (use-package bibtex
+ :mode ("\\.bib" . bibtex-mode))
+#+end_src
+
+*** crontab-mode
+
+#+begin_src emacs-lisp
+ (use-package crontab-mode
+ :commands (crontab-mode))
+#+end_src
+
+*** css-mode
+
+The css-mode requires a few adjustments for the indentation style.
+
+#+begin_src emacs-lisp
+ (use-package css-mode
+ :mode "\\.css\\'"
+ :functions (cssm-c-style-indenter)
+ :config
+ (setq cssm-indent-level 4
+ cssm-newline-before-closing-bracket t
+ cssm-indent-function #'cssm-c-style-indenter))
+#+end_src
+
+*** csv-mode
+
+#+begin_src emacs-lisp
+ (use-package csv-mode
+ :mode "\\.[Cc][Ss][Vv]\\'")
+#+end_src
+
+*** ebuild-mode
+
+#+begin_src emacs-lisp
+ (use-package ebuild-mode
+ :mode ("\\.ebuild\\'" "\\.eclass\\'" "\\.eblit\\'"
+ ("/[0-9]\\{4\\}-[01][0-9]-[0-3][0-9]-.+\\.[a-z]\\{2\\}\\.txt\\'"
+ . gentoo-newsitem-mode))
+ :interpreter ("runscript" . sh-mode))
+#+end_src
+
+*** eselect-mode
+
+#+begin_src emacs-lisp
+ (use-package eselct-mode
+ :mode "\\.eselect\\'")
+#+end_src
+
+*** graphviz-dot-mode
+
+#+begin_src emacs-lisp
+ (use-package graphviz-dot-mode
+ :mode ("\\.dot\\'" "\\.gv\\'"))
+#+end_src
+
+*** haskell-mode
+
+I need haskell-mode and it is required to initialize the indentation
+scheme on activation (else a pop-up will ask you to do so, if you press
+=<TAB>= inside a haskell buffer).
+
+#+begin_src emacs-lisp
+ (use-package haskell-mode
+ :mode ("\\.hs\\'" "\\.gs\\'" "\\.hi\\'"
+ ("\\.l[gh]s\\'" . literate-haskell-mode)
+ ("\\.cabal\\'" . haskell-cabal-mode))
+ :interpreter ("runghc" "runhaskell")
+ :config
+ (add-hook 'haskell-mode-hook 'turn-on-haskell-indentation))
+#+end_src
+
+*** javascript
+
+#+begin_src emacs-lisp
+ (use-package javascript
+ :mode ("\\.js\\'" . javascript-mode))
+#+end_src
+
+*** lua-mode
+
+#+begin_src emacs-lisp
+ (use-package lua-mode
+ :mode "\\.lua\\'")
+#+end_src
+
+*** php-mode
+
+#+begin_src emacs-lisp
+ (use-package php-mode
+ :mode ("\\.php[s34]?\\'" "\\.phtml\\'" "\\.inc\\'"))
+#+end_src
+
+*** po-mode
+
+#+begin_src emacs-lisp
+ (use-package po-mode
+ :mode "\\.po\\'\\|\\.po\\.")
+#+end_src
+
+*** promela-mode
+
+Simple mode for promela files. The file extension is not standardized,
+so I add a few different extensions.
+
+#+begin_src emacs-lisp
+ (use-package promela-mode
+ :mode ("\\.promela\\'" "\\.spin\\'" "\\.pml\\'" "\\.prm\\'" "\\.porm\\'")
+ :config
+ (setq promela-block-indent 2
+ promela-selection-indent 0
+ promela-selection-option-indent 3))
+#+end_src
+
+*** protobuf-mode
+
+#+begin_src emacs-lisp
+ (use-package protobuf-mode
+ :mode "\\.proto\\'")
+#+end_src
+
+*** python
+
+#+begin_src emacs-lisp
+ (use-package python
+ :mode ("\\.py\\'" . python-mode)
+ :interpreter ("python" . python-mode)
+ :functions (python-continuation-line-p)
+ :config
+ <<python>>)
+#+end_src
+
+**** Fix indentation of closing brackets
+
+This fixes the indentation of the closing brackets for line
+continuations in python. The opening and closing brackets should be
+lined up in the same column.
+
+#+begin_src emacs-lisp :noweb-ref python :tangle no
+ (defun alex/python-indent-closing-brackets (func &rest args)
+ "Handle lines beginning with a closing bracket and indent them so that
+ they line up with the line containing the corresponding opening bracket."
+ (save-excursion
+ (beginning-of-line)
+ (let ((syntax (syntax-ppss)))
+ (if (and (not (eq 'string (syntax-ppss-context syntax)))
+ (python-continuation-line-p)
+ (cadr syntax)
+ (skip-syntax-forward "-")
+ (looking-at "\\s)"))
+ (progn
+ (forward-char 1)
+ (ignore-errors (backward-sexp))
+ (current-indentation))
+ (apply func args)))))
+
+ (advice-add 'python-calculate-indentation :around
+ #'alex/python-indent-closing-brackets)
+#+end_src
+
+*** xrdb-mode
+
+#+begin_src emacs-lisp
+ (use-package xrdb-mode
+ :mode ("\\.Xdefaults\\'" "\\.Xenvironment\\'" "\\.Xresources\'"
+ "\\.Xdefaults.d/"))
+#+end_src
+
+* Packages
+** ace-window
+
+ace-window is a replacement for =C-x o= that let you switch to a
+specific window. It displays a marker in all windows and switch to the
+select one. It is also possible execute some actions on the window
+(swap, split or delete) by pressing a dispatch key before selecting
+the window. It is not optimal, because it does not display the
+possibility. Maybe I will replace it with a custom hydra.
+
+#+begin_src emacs-lisp
+ (use-package ace-window
+ :bind (("C-x o" . ace-window)
+ ("C-x C-o" . aw-flip-window))
+ :config
+ (setq aw-scope 'frame
+ aw-dispatch-always t
+ aw-dispatch-alist '((?x aw-delete-window " Ace - Delete Window")
+ (?m aw-swap-window " Ace - Swap Window")
+ (?n aw-flip-window)
+ (?v aw-split-window-vert " Ace - Split Vert Window")
+ (?h aw-split-window-horz " Ace - Split Horz Window")
+ (?i delete-other-windows " Ace - Maximize Window")
+ (?o delete-other-windows))))
+#+end_src
+
+** auto-complete
+
+auto-complete uses a popup to display possible completions of the
+input. The popup is displayed automatically after some idle time or
+when pressing the shortcut (but the auto-complete-mode has to be
+enabled before).
+
+#+begin_src emacs-lisp
+ (use-package auto-complete
+ :bind ("M-<tab>" . auto-complete)
+ :demand t
+ :diminish auto-complete-mode
+ :config
+ (require 'auto-complete-config)
+ (ac-config-default)
+
+ (setq ac-comphist-file (alex/cache-file "ac-comphist.dat")
+ ac-quick-help-delay 1.0)
+
+ (global-auto-complete-mode t))
+#+end_src
+
+** TODO company-mode
+
+Should be better than auto-complete-mode and the code should be more
+modern.
+
+** cursor-chg
+
+I want to change the cursor if the buffer is readonly or if I enabled
+overwrite. =cursor-chg= can change the shape of the cursor. The color
+of the cursor could not be changed, because the cursor-color is a
+frame parameter and could be set for a single buffer.
+
+#+begin_src emacs-lisp
+ (use-package cursor-chg
+ :config
+ (toggle-cursor-type-when-idle 1)
+ (change-cursor-mode 1))
+#+end_src
+
+** deft
+
+#+begin_src emacs-lisp
+ (use-package deft
+ :bind ("<f9>" . deft)
+ :config
+ (setq deft-extension "org"
+ deft-directory "~/.org/deft/"
+ deft-text-mode 'org-mode))
+#+end_src
+
+** dired-x
+
+I use dired-x mostly for the features for omitting files. I customize
+the arguments for the listing to add a trailing slash for directories
+(that way I can omit files like =*.d= but keep directories matching
+the same regexp). I enable =dired-omit-mode= per default in all dired
+buffers.
+
+#+begin_src emacs-lisp
+ (use-package dired-x
+ :config
+ (setq dired-omit-files "^\\.?#\\|~$\\|^\\.svn/$\\|^\\.git\$"
+ dired-omit-extensions (append completion-ignored-extensions
+ dired-latex-unclean-extensions
+ dired-bibtex-unclean-extensions
+ dired-texinfo-unclean-extensions)
+ dired-listing-switches "-pal --group-directories-first")
+
+ (add-hook 'dired-mode-hook (lambda () (dired-omit-mode 1))))
+#+end_src
+** doxymacs
+
+Currently I use doxymacs only to add font-lock for doxymacs tags.
+
+#+begin_src emacs-lisp
+ (defun alex/doxymacs-font-lock ()
+ (when (member major-mode '(c-mode c++-mode))
+ (when (not (fboundp 'doxymacs-font-lock))
+ (use-package doxymacs
+ :load-path "/usr/share/emacs/site-lisp/doxymacs/")
+ (when (not (fboundp 'doxymacs-font-lock))
+ (fset 'doxymacs-font-lock 'ignore)))
+ (doxymacs-font-lock)))
+
+ (add-hook 'font-lock-mode-hook 'alex/doxymacs-font-lock)
+#+end_src
+
+** edit-server
+
+Allow to exit text areas from a browser with emacs. Open the buffers
+in a new frame in org-mode.
+
+#+begin_src emacs-lisp
+ (use-package edit-server
+ :config
+ (setq edit-server-new-frame t
+ edit-server-default-major-mode 'org-mode
+ edit-server-new-frame-alist '((name . "EDIT with Emacs")))
+
+ (edit-server-start))
+#+end_src
+
+** expand-region
+
+This will create a region around semantic elements and let you expand
+and contract it around larger/smaller semantic units.
+
+#+begin_src emacs-lisp
+ (use-package expand-region
+ :bind (("C-<return>" . er/expand-region)
+ ("M-<return>" . er/contract-region)))
+#+end_src
+
+** filladapt
+
+Indent a filled line (manual or with auto-fill-mode) according to some
+heuristics with spaces, comments or citation marks. This is not
+available on ELPA so we need to load it from the local =lisp/= folder
+in the =user-emacs-directory=.
+
+#+begin_src emacs-lisp
+ (use-package filladapt
+ :load-path "lisp/"
+ :diminish filladapt-mode
+ :config
+ (setq-default filladapt-mode t)
+ (add-hook 'org-mode-hook #'turn-off-filladapt-mode)
+ (add-hook 'compilation-mode-hook #'turn-off-filladapt-mode))
+#+end_src
+** flymake-jshint
+
+When entering a javascript buffer, try to load flymake-jshint and
+activate flymake-mode when it could be loaded successfully. This is a
+possibility to defer the loading of the flymake-jshint library until
+it is really required.
+
+#+begin_src emacs-lisp
+ (defun alex/jshint-init ()
+ "Try to load `flymake-jshint' if not already loaded and activate
+ flymake-mode if it could be loaded successfully."
+ (if (fboundp 'flymake-jshint-init)
+ (flymake-mode 1)
+ (use-package flymake-jshint)
+ (when (fboundp 'flymake-jshint-init)
+ (flymake-mode 1))))
+
+ (add-hook 'js-mode-hook 'alex/jshint-init)
+#+end_src
+
+** git-gutter-fringe
+
+If running under X11 I want to have little git marker on the right
+side in the fringe. Therefore I use git-gutter-fringe and I override
+the modification function from =fringe-helper= because it does
+something strange with the beg and end parameters.
+
+To make space for the git-gutter signs, I extend the width of the
+right fringe a bit (left side is kept at the default width).
+
+#+begin_src emacs-lisp
+ (use-package git-gutter-fringe
+ :if window-system
+ :config
+ (setq git-gutter-fr:side 'right-fringe)
+ (fringe-mode '(nil . 15))
+ (global-git-gutter-mode +1)
+
+ ;; fix the helper function (does something strange with beg and end)
+ (defun fringe-helper-modification-func (ov after-p beg end &optional len)
+ ;; Sometimes this hook is called with a deleted overlay.
+ (when (overlay-start ov)
+ (let ((ov-beg (overlay-start ov))
+ (ov-end (overlay-end ov)))
+ (if after-p
+ (if (eq beg end)
+ ;; evaporate overlay
+ (delete-overlay ov)
+ ;; if new lines are inserted, add new bitmaps
+ (let ((before-string (overlay-get ov 'before-string))
+ fringe-ov)
+ (save-excursion
+ (goto-char ov-beg)
+ (while (search-forward "\n" ov-end t)
+ (setq fringe-ov (make-overlay (point) (point)))
+ (overlay-put fringe-ov 'before-string before-string)
+ (overlay-put fringe-ov 'fringe-helper-parent ov)))))
+ ;; if a \n is removed, remove the fringe overlay
+ (save-excursion
+ (goto-char ov-beg)
+ (while (search-forward "\n" ov-end t)
+ (let ((overlays (overlays-in (point) (1+ (point)))))
+ (while overlays
+ (when (eq (overlay-get (car overlays) 'fringe-helper-parent) ov)
+ (delete-overlay (car overlays))
+ (setq overlays nil))
+ (pop overlays)))))))))
+ :diminish
+ git-gutter-mode)
+#+end_src
+** helm
+
+I use helm completion everywhere and I do /not/ autoload helm, because
+it would slow down the first completions and I am sure I will use helm
+every time I start emacs.
+
+#+begin_src emacs-lisp
+ (use-package helm
+ :bind (("M-x" . helm-M-x)
+ ("M-X" . execute-extended-command)
+ ("C-x f" . helm-mini)
+ ("C-x b" . helm-buffers-list)
+ ("C-x C-b" . helm-buffers-list)
+ ("M-y" . helm-show-kill-ring))
+ :demand t
+ :ensure t
+ :diminish helm-mode
+ :config
+ <<helm-config>>
+ (helm-mode 1))
+#+end_src
+
+The basic configuration for helm is provided by helm-config.
+
+#+begin_src emacs-lisp :noweb-ref helm-config :tangle no
+ (use-package helm-config)
+#+end_src
+
+Customize the prefix key and setup =<tab>= as convenient execute the
+persistent-action without quitting helm.
+
+#+begin_src emacs-lisp :noweb-ref helm-config :tangle no
+ (bind-key "<tab>" 'helm-execute-persistent-action helm-map)
+ (setq helm-command-prefix-key "C-c h")
+#+end_src
+
+*** configuration
+
+Now I customize the helm configuration:
+
+**** visual
+
+I want to split the current window to display the helm completion
+window and want to cycle through the results.
+
+#+begin_src emacs-lisp :noweb-ref helm-config :tangle no
+ (setq helm-split-window-in-side-p t
+ helm-move-to-line-cycle-in-source t)
+#+end_src
+
+**** scroll other window
+
+I do not want to scroll the other window by pages, but by 10
+lines. This is useful, if I preview a file or a buffer with the
+persistent action and want to scoll around a bit.
+
+#+begin_src emacs-lisp :noweb-ref helm-config :tangle no
+ (setq helm-scroll-amount 10)
+#+end_src
+
+**** history
+
+I want to use =recentf-list= instead of the normal =file-name-history=,
+because it is more configurable and more complete.
+
+I /always/ want to save the history for executed commands, even if the
+command has failed.
+
+#+begin_src emacs-lisp :noweb-ref helm-config :tangle no
+ (setq helm-ff-file-name-history-use-recentf t
+ helm-M-x-always-save-history t)
+#+end_src
+
+**** fuzzy matching
+
+Enable fuzzy matching on some helm modes. There is also
+=helm-mode-fuzzy-match= that would enable fuzzy match in every helm
+mode, that would also modify sorting.
+
+#+begin_src emacs-lisp :noweb-ref helm-config :tangle no
+ (setq helm-apropos-fuzzy-match t
+ helm-buffers-fuzzy-matching t
+ helm-ff-fuzzy-matching t
+ helm-projectile-fuzzy-match t
+ helm-recentf-fuzzy-match t
+ helm-M-x-fuzzy-match t)
+#+end_src
+
+**** recursive minibuffers
+
+Recursive minibuffers allow to execute a minibuffer command while
+currently in the minibuffer. With this enabled, I could use the
+/completion at point/ from the minibuffer (maybe from
+=eval-expression=).
+
+#+begin_src emacs-lisp :noweb-ref helm-config :tangle no
+ (setq enable-recursive-minibuffers t)
+#+end_src
+
+*** helm-projectile
+
+Enable helm support for projectile and replace many projectile
+commands with helm completion.
+
+#+begin_src emacs-lisp
+ (use-package helm-projectile
+ :ensure t
+ :after (helm)
+ :init
+ ; This needs to be set before loading helm-projectile
+ (setq helm-projectile-fuzzy-match t)
+ :config
+ (helm-projectile-on))
+#+end_src
+** hydra
+
+With hydra I can build easy groups of commands that (maybe) can
+repeated and share a common prefix. The advantage over other
+mechanisms is, that hydra will show a overview of the available keys
+after pressing the prefix. It is very flexible and maybe I should
+create more hydras.
+
+#+begin_src emacs-lisp
+ (use-package hydra
+ :bind (("C-M-s" . alex/hydra-splitter/body)
+ ("<f2>" . alex/hydra-zoom/body)
+ ("C-t" . alex/hydra-toggle/body))
+ :config
+ <<helm>>)
+#+end_src
+
+*** move splitter
+
+With this hydra I can move the splitter between frames using the
+cursor keys.
+
+#+begin_src emacs-lisp :noweb-ref helm :tangle no
+ (require 'hydra-examples)
+ (defhydra alex/hydra-splitter ()
+ "Move window spitter"
+ ("<left>" hydra-move-splitter-left)
+ ("<right>" hydra-move-splitter-right)
+ ("<up>" hydra-move-splitter-up)
+ ("<down>" hydra-move-splitter-down))
+#+end_src
+
+*** zoom
+
+With this hydra I can change font site on demand, by repeatedly
+pressing + or - until the desired font-size is reached.
+
+#+begin_src emacs-lisp :noweb-ref helm :tangle no
+ (defhydra alex/hydra-zoom ()
+ "Change font size"
+ ("+" text-scale-increase "zoom in")
+ ("-" text-scale-decrease "zoom out"))
+#+end_src
+
+*** toggle
+
+With this hydra I can toggle various common settings (or minor-modes)
+using some shortcuts.
+
+Because the keys are already documented in the docstring, hydra should
+not show all the keys again in the mode line and we globally set the
+hint to nil.
+
+#+begin_src emacs-lisp :noweb-ref helm :tangle no
+ (defhydra alex/hydra-toggle (:hint nil)
+ "
+
+ Toggle common settings/minor-modes:
+
+ \[_d_\] debug-on-error: %`debug-on-error
+ \[_f_\] auto-fill-mode: %`auto-fill-function
+ \[_l_\] truncate-lines: %`truncate-lines
+ \[_w_\] whitespace-mode: %`whitespace-mode
+ \[_t_\] trailing-whitespaces: %`alex/tw-mode
+ \[_s_\] flyspell-mode: %`flyspell-mode
+
+ \[_q_\] quit
+ "
+ ("d" toggle-debug-on-error)
+ ("f" auto-fill-mode)
+ ("l" toggle-truncate-lines)
+ ("w" whitespace-mode)
+ ("t" alex/tw-mode)
+ ("s" flyspell-mode)
+ ("q" nil))
+#+end_src
+
+** imenu
+
+=imenu= is part of core and does not need to be required.
+
+#+begin_src emacs-lisp
+ (bind-key [mouse-3] 'imenu)
+#+end_src
+
+** ispell
+
+I want to use aspell to check the spelling. It correctly supports
+Unicode and can have a very good quality of the suggestions.
+
+#+begin_src emacs-lisp
+ (setq ispell-program-name "aspell"
+ ispell-extra-args '("--sug-mode=slow"))
+#+end_src
+
+Normally I do not want to enable flyspell-mode automatically. I only
+want to enable it, if I specify a dictionary with =flyspell-dict= as
+file-local variable.
+
+Here I define a buffer-local variable and allow the setting of all
+strings as local variable without question.
+
+#+begin_src emacs-lisp
+ (defvar flyspell-dict nil
+ "Dictionary name, that should be set during `find-file' for
+ `flyspell-mode'. Set this as file-local or dir-local variable to
+ enable `flyspell-mode' automaticaly.")
+ (make-variable-buffer-local 'flyspell-dict)
+ (put 'flyspell-dict 'safe-local-variable #'stringp)
+#+end_src
+
+Enable ispell (if available) and iterate with =F8= over the list of
+preferred dictionaries.
+
+#+begin_src emacs-lisp
+ (use-package ispell
+ :config
+ (defvar alex/dictionaries '("english" "german")
+ "List of available dictionaries for ispell.")
+
+ (defun alex/switch-dictionary()
+ (interactive)
+ (let ((new (alex/get-next ispell-current-dictionary alex/dictionaries)))
+ (ispell-change-dictionary new)
+ (message "Dictionary switched to %s" new)))
+ (global-set-key (kbd "<f8>") 'switch-dictionary)
+
+ (use-package flyspell
+ :config
+ <<flyspell-config>>))
+#+end_src
+
+Update the flyspell status on various changes to the spell checking
+(selecting a different dictionary or adding a word to the personal
+dictionary).
+
+#+begin_src emacs-lisp :noweb-ref flyspell-config :tangle no
+ (defun alex/flyspell-update (&rest args)
+ (when flyspell-mode
+ (flyspell-buffer)))
+
+ (add-hook 'flyspell-mode-hook 'alex/flyspell-update)
+ (advice-add 'ispell-change-dictionary :after #'alex/flyspell-update)
+ (advice-add 'ispell-pdict-save :after #'alex/flyspell-update)
+#+end_src
+
+If =flyspell-dict= is set for the current buffer, set the value as
+current ispell dictionary and enable flyspell-mode. =flyspell-dict=
+should be set as local variable (file-local or dir-local).
+
+#+begin_src emacs-lisp :noweb-ref flyspell-config :tangle no
+ (defun alex/auto-flyspell-mode ()
+ "Automatically set `flyspell-dict' as dictionary for ispell and
+ enable `flyspell-mode'."
+ (when flyspell-dict
+ (ispell-change-dictionary flyspell-dict)
+ (flyspell-mode 1)))
+ (add-hook 'find-file-hook 'alex/auto-flyspell-mode)
+#+end_src
+
+This ignores all incorrect words in lines starting with
+=#include=. =flyspell-prog-mode= only checks strings and comments, but
+the include files could look like strings.
+
+#+begin_src emacs-lisp :noweb-ref flyspell-config :tangle no
+ (defun alex/flyspell-ignore-include (start end sug)
+ "Ignores all spelling errors in lines starting with #include."
+ (save-excursion
+ (goto-char start)
+ (beginning-of-line)
+ (if (looking-at "#include")
+ t
+ nil)))
+
+ (add-hook 'flyspell-incorrect-hook 'alex/flyspell-ignore-include)
+#+end_src
+
+** magit
+
+magit is a great mode for managing git repositories. I generally use
+=magit-status= as entry point for viewing repository status, staging
+and committing. For writing good commit messages, I activate
+=flyspell-mode= in the =magit-log-edit-mode=.
+
+#+begin_src emacs-lisp
+ (use-package magit
+ :bind ("<f5>" . magit-status)
+ :config
+ (add-hook 'magit-log-edit-mode-hook (lambda () (flyspell-mode 1))))
+#+end_src
+** multi-term
+
+multi-term supports much more terminal applications than similar modes
+and can automatically toggle a dedicated window. The only disadvantage
+is, that it does not work in combination with tramp.
+
+#+begin_src emacs-lisp
+ (use-package multi-term
+ :bind (("C-c t" . multi-term-dedicated-toggle)
+ ("C-c T" . multi-term))
+ :config
+ ;;(setq multi-term-dedicated-select-after-open-p t)
+ )
+#+end_src
+** neotree
+
+I rarely use a files browser in parallel to the main window. Usually I
+simply use =find-file= or a dired buffer. But if I really need it,
+neotree is a nice replacement for speedbar and simply work out of the
+box. I only added projectile support, so that the neotree open per
+default the project root (aka. the root of the git repository).
+
+#+begin_src emacs-lisp
+ (use-package neotree
+ :commands (neotree-dir neotree-find neotree-show)
+ :bind ("C-<tab>" . neotree-project-dir)
+ :init
+ (defun alex/neotree-find-file (dir file)
+ (neotree-dir dir)
+ (if file
+ (neotree-find (file-relative-name file dir))))
+
+ (defun neotree-project-dir ()
+ "Open NeoTree using the git root."
+ (interactive)
+ (if (and (fboundp 'neo-global--window-exists-p)
+ (neo-global--window-exists-p))
+ (neotree-hide)
+ (if (fboundp 'projectile-project-root)
+ (let ((projectile-require-project-root nil))
+ (let ((project-dir (projectile-project-root))
+ (file-name (projectile-file-truename (buffer-file-name))))
+ (if project-dir
+ (alex/neotree-find-file project-dir file-name)))))
+ (neotree-show))))
+#+end_src
+
+** nlinum
+
+I generally want to have line numbers. nlinum works best with folding,
+so I use that.
+
+#+begin_src emacs-lisp
+ (use-package nlinum
+ :config
+ <<nlinum-config>>)
+#+end_src
+
+*** global mode
+
+I use my global-excluding-minor-mode stuff an define some exceptions,
+where I do not want to have line numbers.
+
+#+begin_src emacs-lisp :noweb-ref nlinum-config :tangle no
+ (alex/define-global-excluding-minor-mode 'nlinum-mode)
+
+ (setq nlinum-mode-exclude-list
+ '(:minibuffer
+ :mode
+ Custom-mode
+ Man-mode
+ compilation-mode
+ dired-mode
+ doc-view-mode
+ eshell-mode
+ helm--mode
+ helm--remap-mouse-mode
+ image-mode
+ magit-mode
+ magit-status-mode
+ neotree-mode
+ term-mode
+ text-mode
+ weechat-mode
+ wl-folder-mode
+ wl-summary-mode))
+
+ (alex/global-nlinum-mode t)
+#+end_src
+
+*** number format
+
+I want to have some spacing around the numbers and calculate the
+width, so that the width does not change during scrolling.
+
+#+begin_src emacs-lisp :noweb-ref nlinum-config :tangle no
+ (setq nlinum-format " %d ")
+
+ (defun alex/nlinum-max-width ()
+ "Calculate maximum width of line numbers"
+ (setq nlinum--width
+ (length (format nlinum-format
+ (count-lines (point-min) (point-max)))))
+ (nlinum--flush))
+ (add-hook 'nlinum-mode-hook 'alex/nlinum-max-width)
+#+end_src
+
+*** fix make-frame
+
+linum/nlinum currently triggers a bug in emacs: [[https://lists.gnu.org/archive/html/emacs-devel/2014-09/msg00022.html][Trunk emacs infelicity
+with linum mode]] that make it impossible to create a new frame while
+linum mode is active in at least on buffer. To fix this I
+around-advice =make-frame= and deactivate nlinum before and reactivate
+it again after creating the frame.
+
+#+begin_src emacs-lisp :noweb-ref nlinum-config :tangle no
+ (defun alex/deactivate-nlinum (buffer)
+ "Deactivates nlinum in the given BUFFER"
+ (with-current-buffer buffer
+ (nlinum-mode 0)))
+
+ (defun alex/activate-nlinum (buffer)
+ "Activates nlinum in the given BUFFER"
+ (with-current-buffer buffer
+ (let ((res (nlinum-mode 1)))
+ (nlinum--flush)
+ res)))
+
+ (defun alex/fix-nlinum (func &rest args)
+ "nlinum currently (emacs-24) triggers a bug, that makes it
+ impossible to create new frames because the linum face is not
+ defined. This is a fix, that deactivates nlinum in all buffers and
+ activate it again after creating the new frame."
+ (let ((nlinum-buffers (alex/get-buffers-with 'nlinum-mode)))
+ (mapc 'alex/deactivate-nlinum nlinum-buffers)
+ (alex/safe-call
+ (apply func args)
+ (mapc 'alex/activate-nlinum nlinum-buffers))))
+ (advice-add 'make-frame :around #'alex/fix-nlinum)
+#+end_src
+
+** org
+
+I use org-mode for my emacs config, taking notes, scheduling tasks and
+maybe more.
+
+#+begin_src emacs-lisp
+ (use-package org
+ :mode ("\\.org\\'" . org-mode)
+ :demand t
+ :config
+ <<org>>)
+#+end_src
+
+*** visual
+
+I want to have a nice display.
+
+On opening a org file, I want to see the outline but not the content
+of all nodes. This is useful to get an overview.
+
+The nested org nodes should be intended, so that it is easy to see the
+level, but I do not want to see the repeated stars in front of the
+nodes. (The nodes may even got more fancy, if org-bullets is
+available. See below.)
+
+If some parts are hidden, I want to prevent editing. If an edit action
+is started the hidden region will be unfolded and the action has to be
+confirmed.
+
+#+begin_src emacs-lisp :noweb-ref org :tangle no
+ (setq org-startup-folded 'content
+ org-startup-indented t
+ org-catch-invisible-edits t)
+#+end_src
+
+Hide =org-indent-mode= from modeline.
+
+#+begin_src emacs-lisp
+ (alex/rm-add-blacklist " Ind")
+#+end_src
+
+*** modules
+
+Setup some default modules to load. Some other modules might get
+loaded on demand (see below).
+
+#+begin_src emacs-lisp :noweb-ref org :tangle no
+ (setq org-modules '(org-annotate-file org-bbdb
+ org-checklist org-collector org-eval org-expiry
+ org-habit org-info org-man org-mouse org-protocol
+ org-toc org-wl))
+
+ (org-load-modules-maybe t)
+#+end_src
+
+*** todo keywords
+
+Define some default TODO keywords and corresponding faces, that match
+my theme with a dark background.
+
+#+begin_src emacs-lisp :noweb-ref org :tangle no
+ (setq org-todo-keywords
+ '((sequence "TODO" "STARTED(s)" "WAITING(w)" "DELEGATED(l)" "|"
+ "DONE(d)" "DEFERRED(f)" "CANCELLED(x)"))
+
+ org-todo-keyword-faces
+ '(("TODO" . (:inherit org-warning))
+ ("STARTED" . (:foreground "yellow" :weight bold))
+ ("DELEGATED" . (:foreground "darkred" :weight bold))
+ ("DEFERRED" . (:foreground "gray" :weight bold))
+ ("CANCELLED" . (:foreground "gray" :weight normal))
+ ("DONE" . (:foreground "cyan" :weight bold))))
+#+end_src
+
+*** bullets
+
+Automatically use org-bullets-mode if available and add the
+possibility to disable it on a per-file basis with
+=#+STARTUP: nobullets=.
+
+#+begin_src emacs-lisp :noweb-ref org :tangle no
+ (defvar alex/org-startup-with-bullets t
+ "Not-nil means entering Org-mode will enable org-bullets. This can
+ also be configured on a per-file basis adding on of the following
+ lines anywhere in the buffer:
+
+ ,#+STARTUP: bullets
+ ,#+STARTUP: nobullets")
+
+ (defun alex/org-bullets-setup ()
+ "Enable org-bullets if `alex/org-startup-with-bullets' is not-nil."
+ (when alex/org-startup-with-bullets
+ (org-bullets-mode 1)))
+ (add-hook 'org-mode-hook 'alex/org-bullets-setup)
+
+ (setq org-startup-options
+ (append org-startup-options
+ '(("bullets" org-startup-with-bullets t)
+ ("nobullets" org-startup-with-bullets nil))))
+
+ (use-package org-bullets
+ :commands (org-bullets-mode))
+#+end_src
+
+*** agenda
+
+The agenda view should be generated only from the =todo.org= file.
+This file is the central place where I manage all TODO entries used
+for the agenda view and the daily schedule. The agenda view should
+always display 7 days from today, even if there are no scheduled tasks
+for a day.
+
+#+begin_src emacs-lisp :noweb-ref org :tangle no
+ (use-package org-agenda
+ :bind ("C-c a" . org-agenda)
+ :config
+ (setq org-agenda-files '("~/doc/org/todo.org")
+ org-agenda-span 'week
+ org-deadline-warning-days 14
+ org-agenda-show-all-dates t
+ org-agenda-skip-deadline-if-done t
+ org-agenda-skip-scheduled-if-done t
+ org-agenda-start-on-weekday nil
+ org-reverse-note-order t
+ org-fast-tag-selection-single-key 'expert))
+#+end_src
+
+*** capture
+
+Org-capture can quickly create notes or todo entries. It can also used
+in combination with org-protocol to receive information from other
+programs (like a web browser).
+
+#+begin_src emacs-lisp :noweb-ref org :tangle no
+ (use-package org-capture
+ :commands (org-capture)
+ :bind ("C-c o" . org-capture)
+ :config
+ (setq org-default-notes-file "~/doc/org/notes.org"
+ org-capture-templates
+ '(("t" "Tasks" entry
+ (file "~/doc/org/todo.org")
+ "* TODO %?\n%u")
+ ("n" "Notes" entry
+ (file+headline "~/doc/org/notes.org" "Notes")
+ "* %u %?")
+ ("c" "Capture" entry
+ (file+headline "~/doc/org/notes.org" "Links")
+ "* %^{Title}\n\nSource: %u, %c\n\n%i"))))
+#+end_src
+
+*** protocol
+
+Set default org-capture-template for org-protocol.
+
+#+begin_src emacs-lisp :noweb-ref org :tangle no
+ (setq org-protocol-default-template-key "c")
+#+end_src
+
+When I start an org-capture in an org-protocol popup, I want to show
+only the org-capture buffer (default behaviour would be to split the
+current buffer) and I want to close the popup after finishing the
+capture.
+
+When using org-capture with placeholders, we need to delete the other
+windows just before starting to filling out the placeholders. The
+advice after org-capture is too late, it would delete the other
+windows after filling the placeholders.
+
+#+begin_src emacs-lisp :noweb-ref org :tangle no
+ (defun alex/org-capture-single-window (&rest args)
+ "Make the org-capture the only window when used as a popup"
+ (when (equal "emacs-capture" (frame-parameter nil 'name))
+ (delete-other-windows)))
+ (advice-add 'org-capture :after #'alex/org-capture-single-window)
+ (advice-add 'org-completing-read-no-i :before #'alex/org-capture-single-window)
+
+ (defun alex/org-capture-delete-frame (&rest args)
+ "Close the frame after finishing the capture, when used org-capture
+ as a popup"
+ (when (equal "emacs-capture" (frame-parameter nil 'name))
+ (delete-frame)))
+ (advice-add 'org-capture-finalize :after #'alex/org-capture-delete-frame)
+#+end_src
+
+*** journal
+
+#+begin_src emacs-lisp :noweb org-config :tangle no
+ (use-package org-journal
+ :bind ("C-c C-j" . org-journal-new-entry)
+ :config
+ (setq org-journal-dir "~/doc/org/journal/"
+ org-agenda-file-regexp "\\`\\([^.].*\\.org\\|[0-9]+\\)\\'"))
+#+end_src
+
+*** org without helm
+
+org has a function, that requests input without ido completion. For
+this function I disable helm.
+
+#+begin_src emacs-lisp :noweb-ref org :tangle no
+ (defun alex/run-without-helm (orig-func &rest args)
+ "Run a function without helm completion."
+ (if (boundp 'helm-mode)
+ (let ((orig-helm-mode helm-mode))
+ (helm-mode 0)
+ (alex/safe-call
+ (apply orig-func args)
+ (when orig-helm-mode
+ (helm-mode 1))))
+ (apply orig-func args)))
+
+ (advice-add 'org-completing-read-no-i :around #'alex/run-without-helm)
+#+end_src
+** origami
+
+Sometimes I want to fold some code sections. There are several mode
+available, but only origami supports insertion of new regions without
+reopening or parsing the whole buffer. But I do not want to use the
+semantic expression feature of origami and my markers should support a
+title in the first line after the marker.
+
+I define my own parser for origami and modify the behaviour for my
+needs.
+
+#+begin_src emacs-lisp
+ (use-package origami
+ :demand t
+ :bind (("C-c C-f" . origami-toggle-node)
+ ("C-c M-f" . origami-close-all-nodes)
+ ("C-c f" . origami-open-all-nodes))
+
+ :config
+ <<origami-config>>)
+#+end_src
+
+*** custom format for folded display
+
+Per default origami is used to fold semantic expressions and only
+shows the marker at the front and end of the region. I want to use
+explicit marker inside comments and want to add a description (title)
+for the region after the opening marker. So I want to keep the whole
+first line visible while the region is folded.
+
+#+begin_src emacs-lisp :noweb-ref origami-config :tangle no
+ (defun alex/origami-build-pair-tree (create open close positions)
+ "This is like `origami-build-pair-tree' and now keeps the whole
+ first line visible while folded."
+ (cl-labels ((build (positions)
+ ;; this is so horrible, but fast
+ (let (acc beg (should-continue t))
+ (while (and should-continue positions)
+ (cond ((equal (caar positions) open)
+ (if beg ;go down a level
+ (let* ((res (build positions))
+ (new-pos (car res))
+ (children (cdr res))
+ (beg-end (save-excursion
+ (goto-char beg)
+ (line-end-position)))
+ (end (cdar new-pos)))
+ (setq positions (cdr new-pos))
+ (setq acc (cons (funcall create beg (+ end (length close)) (- beg-end beg) children)
+ acc))
+ (setq beg nil))
+ ;; begin a new pair
+ (setq beg (cdar positions))
+ (setq positions (cdr positions))))
+ ((equal (caar positions) close)
+ (if beg
+ (let ((beg-end (save-excursion
+ (goto-char beg)
+ (line-end-position)))
+ (end (cdar positions)))
+ (if (< beg-end end)
+ ;;close with no children
+ (setq acc (cons (funcall create beg (+ end (length close)) (- beg-end beg) nil)
+ acc)))
+ (setq positions (cdr positions))
+ (setq beg nil))
+ (setq should-continue nil)))))
+ (cons positions (reverse acc)))))
+ (cdr (build positions))))
+#+end_src
+
+*** respect derived modes
+
+I manually specify the parser for the origami markers. For more
+flexibility I want to support derived modes (f.e. if I assign a value
+for emacs-list-mode, this parser should also support the
+lisp-interaction-mode).
+
+Therefore I advice the =origami-get-parser= function and temporarily
+overwrite the =origami-parser-alist= and change all definitions with a
+compatible mode to the exact major mode of the requested buffer.
+
+#+begin_src emacs-lisp :noweb-ref origami-config :tangle no
+ (defun alex/origami-is-derived-mode (buffer parser-elem)
+ "Helper for `alex/origami-parser-derived-modes' to check if the
+ current major-mdoe in BUFFER is a dreived mode of the mode part of
+ an element from the `origami-parser-alist'."
+ (let ((mode (car parser-elem))
+ (parser (cdr parser-elem)))
+ (with-current-buffer buffer
+ (if (derived-mode-p mode)
+ (cons major-mode parser)
+ nil))))
+
+ (defun alex/origami-parser-derived-modes (func buffer &rest args)
+ "Modify the origami-parser-alist on demand to respect the derived
+ major-modes of the defined modes."
+ (let* ((check (apply-partially 'alex/origami-is-derived-mode buffer))
+ (origami-parser-alist (delq nil (mapcar check origami-parser-alist))))
+ (apply func buffer args)))
+
+ (advice-add 'origami-get-parser :around #'alex/origami-parser-derived-modes)
+#+end_src
+
+*** define simple marker for different modes
+
+#+begin_src emacs-lisp :noweb-ref origami-config :tangle no
+ (defun alex/origami-markers-parser (begin end create)
+ "Create a origami parser for regions between BEGIN and END
+ markers. The folded region will show the complete first line after the
+ marker but not the END marker."
+ (lexical-let ((create-tmp create)
+ (begin-tmp begin)
+ (end-tmp end)
+ (regexp (rx-to-string `(or ,begin ,end))))
+ (lambda (content)
+ (let ((positions (origami-get-positions content regexp)))
+ (alex/origami-build-pair-tree create-tmp begin-tmp end-tmp positions)))))
+
+ (defun alex/origami-marker (mode start end)
+ "Define a cons with MODE and the marker-parser for origmai, that
+ could be used directly as element for `origami-parser-alist'."
+ `(,mode . ,(apply-partially 'alex/origami-markers-parser start end)))
+
+ (setq origami-parser-alist
+ `(,(alex/origami-marker 'emacs-lisp-mode ";;{{{" ";;}}}")
+ ,(alex/origami-marker 'lisp-mode ";;{{{" ";;}}}")
+ ,(alex/origami-marker 'sh-mode "#{{{" "#}}}")
+ ,(alex/origami-marker 'php-mode "//{{{" "//}}}")
+ ,(alex/origami-marker 'haskell-mode "--{{{" "--}}}")))
+#+end_src
+
+*** global-minor-mode
+
+I want to use origami-mode everywhere, so I create a global minor-mode
+and activate it.
+
+#+begin_src emacs-lisp :noweb-ref origami-config :tangle no
+ (alex/define-global-excluding-minor-mode 'origami-mode)
+ (alex/global-origami-mode t)
+#+end_src
+** powerline
+
+I use powerline to get a nicer modeline, but I change some aspects to
+enhance it even more.
+
+#+begin_src emacs-lisp
+ (use-package powerline
+ :config
+ <<powerline-config>>)
+#+end_src
+
+*** display utf8 glyphs
+
+Currently powerline only displays the nice utf-8 glyphs (f.e. for git
+branches) if =window-system= is nil. So we simply wrap =powerline-vc=
+and temporarily unset =window-system=.
+
+#+begin_src emacs-lisp :noweb-ref powerline-config :tangle no
+ (defun alex/fix-powerline-vc (orig-fun &rest args)
+ "Fix utf8 glyphs display."
+ (let ((window-system nil))
+ (apply orig-fun args)))
+ (advice-add 'powerline-vc :around #'alex/fix-powerline-vc)
+#+end_src
+
+*** smart-mode-line
+
+I only use smart-mode-line for the file paths feature. I need to call
+=sml/setup=, but I do not want to load a theme because it is
+incompatible with powerline. So I simply overwrite =sml/-setup-theme=
+with =ignore=.
+
+#+begin_src emacs-lisp :noweb-ref powerline-config :tangle no
+ (use-package smart-mode-line
+ :config
+ (advice-add 'sml/-setup-theme :around #'ignore)
+ (sml/setup))
+#+end_src
+
+*** rich-minority
+
+I use rich-minority-mode, that has no support for powerline out of the
+box. So I advice the =powerline-minor-modes= function and let
+rich-minority temporarily overwrite the minor-mode-alist.
+
+#+begin_src emacs-lisp :noweb-ref powerline-config :tangle no
+ (defun alex/powerline-rm-setup ()
+ (defun alex/powerline-rm (orig-fun &rest args)
+ "Applies the rich-minority-mode on the powerline display of the
+ minor-modes."
+ (let ((minor-mode-alist (if rich-minority-mode
+ (rm--mode-list-as-string-list)
+ minor-mode-alist)))
+ (apply orig-fun args)))
+ (advice-add 'powerline-minor-modes :around #'alex/powerline-rm))
+
+ (eval-after-load 'rich-minority #'alex/powerline-rm-setup)
+#+end_src
+
+*** powerline theme
+
+Setup the powerline theme. Currently I only change the separator and
+make it a little bit higher.
+
+#+begin_src emacs-lisp :noweb-ref powerline-config :tangle no
+ (setq powerline-default-separator 'wave
+ powerline-height 25)
+
+ (powerline-default-theme)
+#+end_src
+
+** projectile
+
+Projectile allows fast search for files in project directories. I want
+to use it everywhere but do not want to see the minor-mode. It
+automatically recognize git repositories as projects.
+
+#+begin_src emacs-lisp
+ (use-package projectile
+ :diminish " Projectile.*"
+ :config
+ (projectile-global-mode)
+ (setq projectile-enable-caching t
+ projectile-cache-file (alex/cache-file "projectile")
+ projectile-known-projects-file (alex/cache-file "projectile-bookmarks")))
+#+end_src
+
+** semantic
+
+semantic is an emacs mode, that parses the source code of the current
+buffer. It has support for many languages out of the box (C/C++,
+Python, elisp, Erlang...). I want to enable it in all buffers. The
+only disadvantage is, that opening a file could trigger the parsing
+and will block emacs for a while (depending on how many files are in
+the including hierarchy).
+
+#+begin_src emacs-lisp
+ (use-package semantic
+ :config
+ (use-package semantic/ia)
+ (setq semanticdb-default-save-directory (alex/cache-file "semantic"))
+
+ (semantic-mode 1)
+ (global-semantic-idle-summary-mode 1))
+#+end_src
+
+** server
+
+Start server (if not running) to edit files with emacsclient and
+rebind =C-x k= in server buffers to close it.
+
+#+begin_src emacs-lisp
+ (use-package server
+ :config
+ (when (and (fboundp 'server-running-p)
+ (not (server-running-p)))
+ (server-start))
+
+ (defun alex/server-swtich-hook ()
+ (when (current-local-map)
+ (use-local-map (copy-keymap (current-local-map))))
+ (when server-buffer-clients
+ (local-set-key (kbd "C-x k") 'server-edit)))
+
+ (add-hook 'server-switch-hook 'alex/server-swtich-hook))
+
+#+end_src
+
+** smartparens
+
+smartparens-mode has various features. I only want to have the
+highlighting of matching parens and the automatic wrapping of the
+region, but I do not want that it inserts, deletes or skips some
+parens.
+
+#+begin_src emacs-lisp
+ (use-package smartparens-config
+ :config
+ (setq-default sp-autoinsert-pair nil
+ sp-autodelete-pair nil
+ sp-autodelete-opening-pair nil
+ sp-autodelete-closing-pair nil
+ sp-autoskip-closing-pair nil)
+
+ (smartparens-global-mode t)
+ (show-smartparens-global-mode t)
+ :diminish
+ " SP")
+#+end_src
+
+** template
+
+I want to insert template automatically in new empty files with the
+correct extension. But I only want to search for global templates by
+default and not in a sub directory of the new file. I also do not want
+to update the content of a file after saving (f.e. when saving under a
+different name).
+
+#+begin_src emacs-lisp
+ (use-package template
+ :config
+ (setq template-auto-insert t
+ template-auto-update nil
+ template-confirm-insecure nil
+
+ template-date-format "%Y-%m-%d"
+ template-time-format "%T"
+
+ template-subdirectories nil
+ template-default-directories (list (concat user-emacs-directory
+ "templates/")))
+ (template-initialize))
+#+end_src
+** tramp
+
+I usually have very heavy shell customization on remote hosts. I do
+not want to depend, that tramp can parse my custom prompt format. So I
+set =sshx= as default tramp method, that explicit invoke =/bin/sh= as
+shell on the remote host.
+
+#+begin_src emacs-lisp
+ (use-package tramp
+ :config
+ (setq tramp-default-method "sshx"
+ tramp-persistency-file-name (alex/cache-file "tramp")))
+#+end_src
+
+*** dir-locals
+
+Support dir-locals also via tramp. This leads to a additional delay
+while opening a file via tramp (because it has to check for the
+dir-locals file over ssh) but usually I do not want to clutter single
+files with file-local variables.
+
+#+begin_src emacs-lisp
+ (setq enable-remote-dir-locals t)
+#+end_src
+** uniquify
+
+Use a better approach to make unique buffer names. The default
+algorithm just adds a count after the filename if you opened two files
+with the same name. =uniquify= adds the path to the buffer name, so
+that the right buffer is easier to identify.
+
+#+begin_src emacs-lisp
+ (use-package uniquify
+ :config
+ (setq uniquify-buffer-name-style 'reverse))
+#+end_src
+
+** uptimes
+
+I want to measure the uptime of emacs. This should not be deferred
+loaded, because it captures the start time of in the moment it gets
+loaded.
+
+#+begin_src emacs-lisp
+ (use-package uptimes
+ :demand t
+ :config
+ (setq uptimes-database (alex/cache-file "uptimes")))
+#+end_src
+
+** weechat
+
+#+begin_src emacs-lisp
+ (use-package weechat
+ :commands (weechat-connect)
+ :functions (weechat-channel-names
+ weechat-monitor-buffer
+ weechat--find-buffer
+ weechat-buffer-hash)
+
+ :init
+ (defun weechat ()
+ "Start weechat with `weechat-connect' and automatically switch to
+ the first buffer in `weechat-auto-monitor-buffers'."
+ (interactive)
+ (weechat-connect)
+ (when weechat-auto-monitor-buffers
+ (switch-to-buffer
+ (car weechat-auto-monitor-buffers))))
+
+ :config
+ <<weechat-config>>)
+#+end_src
+
+*** config
+
+I connect to weechat running on the host called =island= via ssh
+tunneling, monitor only a few buffers by default and close the buffers
+on disconnect.
+
+#+begin_src emacs-lisp :noweb-ref weechat-config :tangle no
+ (setq weechat-buffer-kill-buffers-on-disconnect t
+
+ weechat-host-default "is.zedat.fu-berlin.de"
+ weechat-port-default 58224
+ weechat-mode-default "ssh -W localhost:%p %h"
+
+ weechat-text-column 25
+ weechat-header-line-format "%c/%s: %t"
+
+ weechat-auto-monitor-buffers '("freenode.#spline"
+ "ircnet.&ZEDAT-IS"
+ "oftc.#vserver"))
+
+ (defun alex/weechat-mode-hook ()
+ "Activate `visual-line-mode'."
+ (visual-line-mode 1))
+ (add-hook 'weechat-mode-hook 'alex/weechat-mode-hook)
+#+end_src
+
+*** helm support
+
+#+begin_src emacs-lisp :noweb-ref weechat-config :tangle no
+ (defun alex/helm-weechat-support ()
+
+ (defun alex/weechat-new-buffers ()
+ (let ((current (weechat-channel-names t))
+ (all (weechat-channel-names nil)))
+ (mapc (lambda (cur) (setq all (delete cur all))) current)
+ (sort all 'string-lessp)))
+
+ (defun alex/weechat-add-buffer (name)
+ (weechat-monitor-buffer (weechat--find-buffer name) t))
+
+ (defun alex/weechat-get-count (channel type)
+ (let ((hash (gethash type channel)))
+ (if (not (not hash))
+ (gethash :count hash)
+ 0)))
+
+ (defun alex/weechat-show-topic (channels)
+ (mapcar
+ (lambda (channel)
+ (let* ((hash (weechat-buffer-hash (weechat--find-buffer channel)))
+ (hlight (alex/weechat-get-count hash :background-highlight))
+ (message (alex/weechat-get-count hash :background-message))
+ (chan-name (if (> (string-width channel) helm-buffer-max-length)
+ (helm-substring-by-width
+ channel helm-buffer-max-length)
+ (concat channel (make-string
+ (- (+ helm-buffer-max-length 3)
+ (string-width channel)) ? ))))
+ (chan (cond
+ ((> hlight 0)
+ (propertize chan-name 'face 'helm-buffer-saved-out))
+ ((> message 0)
+ (propertize chan-name 'face 'helm-buffer-not-saved))
+ (t chan-name)))
+ (hlight-count (if (> hlight 0)
+ (propertize (format "%-3d" hlight)
+ 'face 'helm-buffer-saved-out)
+ " "))
+ (message-count (if (> message 0)
+ (format "%3d" message) " "))
+ (count-sep (if (and (> message 0) (> hlight 0))
+ "," " "))
+ (topic (propertize
+ (gethash "title" hash)
+ 'face 'helm-ff-symlink)))
+ (cons (format "%s\t%s%s%s\t%s" chan message-count count-sep
+ hlight-count topic)
+ channel)))
+ channels))
+
+ (defun alex/weechat-ignore-buffer (channels)
+ (delq nil
+ (mapcar
+ (lambda (channel)
+ (let* ((hash (weechat-buffer-hash (weechat--find-buffer channel)))
+ (plugin (cdr (assoc "plugin" (gethash "local_variables" hash))))
+ (type (cdr (assoc "type" (gethash "local_variables" hash)))))
+ (when (and (string= "irc" plugin) (string= "channel" type))
+ channel)))
+ channels)))
+
+ (defun alex/helm-weechat-buffer-toggle-ignore ()
+ (interactive)
+ (with-helm-alive-p
+ (let ((filter-attrs (helm-attr 'candidate-transformer
+ alex/weechat-new-buffers-source)))
+ (if (memq 'alex/weechat-ignore-buffer filter-attrs)
+ (helm-attrset 'candidate-transformer
+ (remove 'alex/weechat-ignore-buffer
+ filter-attrs)
+ alex/weechat-new-buffers-source t)
+ (helm-attrset 'candidate-transformer
+ (cons 'alex/weechat-ignore-buffer
+ filter-attrs)
+ alex/weechat-new-buffers-source t))
+ (helm-force-update))))
+
+ (setq alex/helm-weechat-buffer-map (copy-keymap helm-map))
+ (bind-key "C-c C-c" 'alex/helm-weechat-buffer-toggle-ignore
+ alex/helm-weechat-buffer-map)
+
+ (setq alex/weechat-new-buffers-source nil)
+ (defun alex/helm-weechat-buffer ()
+ (interactive)
+ (setq alex/weechat-new-buffers-source
+ (helm-build-sync-source "Available channel"
+ :candidates (alex/weechat-new-buffers)
+ :action '(("Monitor channel" . alex/weechat-add-buffer))
+ :candidate-transformer '(alex/weechat-ignore-buffer
+ alex/weechat-show-topic)))
+ (let ((helm-truncate-lines t))
+ (helm
+ :sources (list
+ (helm-build-sync-source "Buffers"
+ :candidates (weechat-channel-names t)
+ :action '(("Open buffer" . switch-to-buffer))
+ :candidate-transformer '(alex/weechat-show-topic))
+ alex/weechat-new-buffers-source)
+ :buffer "*weechat*"
+ :keymap alex/helm-weechat-buffer-map)))
+
+ (bind-key "C-c C-b" 'alex/helm-weechat-buffer weechat-mode-map)
+
+ (defun alex/mark-read ()
+ "Mark buffer as read up to current line."
+ (interactive)
+ (let ((inhibit-read-only t))
+ (put-text-property
+ (point-min) (line-beginning-position)
+ 'face 'font-lock-comment-face)))
+ (bind-key "<escape>" 'alex/mark-read weechat-mode-map))
+
+ (eval-after-load 'helm #'alex/helm-weechat-support)
+#+end_src
+** which-key
+
+I cannot remember all the key combinations. which-key will show a
+hint for possible completions, if I start a key combo and wait longer
+than 1s before continue with the next key.
+
+#+begin_src emacs-lisp
+ (use-package which-key
+ :config
+ (setq which-key-idle-delay 1.0)
+ (which-key-mode t)
+ :diminish
+ which-key-mode)
+#+end_src
+
+** winner
+
+I use winner to quickly restore a previous window configuration after
+it was changed by something. I demand it here, because winner mode
+need to be active to keep track of the changes and helm will notice it
+and will insert the helm buffer names into =winner-boring-buffers=.
+
+#+begin_src emacs-lisp
+ (use-package winner
+ :bind (("C-c <left>" . winner-undo)
+ ("C-c <right>" . winner-redo))
+ :demand t
+ :config
+ (winner-mode 1))
+#+end_src
+
+** winring
+
+With winring it is possible to manage different window configurations
+and switching between. This could be useful if working with
+specialized window configurations (f.e. for debugging) and activating
+it when needed.
+
+#+begin_src emacs-lisp
+ (use-package winring
+ :bind (("C-x j" . winring-jump-to-configuration)
+ ("C-x n" . winring-new-configuration)
+ ("C-x K" . winring-delete-configuration))
+ :functions (winring-initialize)
+ :config
+ (winring-initialize)
+
+ (defun alex/confirm-winring-deletion (&rest args)
+ (y-or-n-p (format "Delete winring configuration %s? " winring-name)))
+
+ (advice-add 'winring-delete-configuration
+ :before-while
+ #'alex/confirm-winring-deletion))
+#+end_src
+
+** wl
+
+Here are only the functions for auto-loading. I customize wanderlust,
+to load the profile from the org-babel file =init.d/wl.org= during
+start-up of wanderlust.
+
+I use a separate frame for wanderlust with a custom name, so that
+XMonad can shift it to a different desktop. Additionally I create
+a function, that should be called with emacsclient to compose a new
+message from a mailto link. This function also creates a new frame
+with a custom name and closes it after sending the mail.
+
+#+begin_src emacs-lisp
+ (use-package wl
+ :commands (wl-other-frame wl-draft)
+ :init
+ (defun wl-start ()
+ "Start wanderlust in a seperate frame and set the name of the new
+ frame to `wanderlust'."
+ (interactive)
+ (let ((default-frame-alist
+ (cons '(name . "wanderlust") default-frame-alist)))
+ (wl-other-frame)))
+
+ (defun alex/wl-mailto-compose-new-frame (mailto-url)
+ "Compose a new mail from a mailto link with wanderlust in a new
+ frame and customize the name of the new frame to
+ `wanderlust-draft'."
+ (let ((default-frame-alist
+ (cons '(name . "wanderlust-draft") default-frame-alist))
+ (wl-draft-use-frame t))
+ (alex/wl-mailto-compose mailto-url)
+ (set-window-dedicated-p (selected-window) t)
+
+ (make-local-variable 'wl-draft-force-delete-frame)
+ (setq wl-draft-force-delete-frame t)
+ (run-hooks 'wl-mail-setup-hook)))
+
+ (require 'rfc2368)
+ (defun alex/wl-mailto-compose (mailto-url)
+ "Parse a rfc2368 mailto links and call `wl-draft' with the
+ information for the headers and the body."
+ (when (and (stringp mailto-url) (string-match "\\`mailto:" mailto-url))
+ (let* ((headers (mapcar (lambda (h) (cons (intern (car h)) (cdr h)))
+ (rfc2368-parse-mailto-url mailto-url)))
+ (good-headers (assq-delete-all 'Body (copy-alist headers)))
+ (body (cdr (assoc 'Body headers))))
+ (wl-draft good-headers nil nil body))))
+
+ (defvar wl-draft-force-delete-frame nil
+ "If this variable is t `alex/wl-draft-force-hide' always delete
+ the frame after closing the draft. You may want to make this
+ variable buffer-local whenever you use it. This variable is used by
+ `alex/wl-mailto-compose-new-frame' to close the created frame after
+ composing the mail.")
+
+ (defun alex/wl-draft-force-hide (func &rest args)
+ "This advice removes the draft-frame even if no other frame is
+ visible if `alex/wl-draft-force-delete-frame' is non-nil."
+ (let ((force-delete (and (boundp 'wl-draft-force-delete-frame)
+ wl-draft-force-delete-frame)))
+ (apply func args)
+ (if force-delete
+ (delete-frame))))
+ (advice-add 'wl-draft-hide :around #'alex/wl-draft-force-hide)
+
+ :config
+ (defun alex/wl-babel-load-profile ()
+ "Load `wl-init-file' with `org-babel-load-file'."
+ (org-babel-load-file wl-init-file))
+
+ (setq wl-init-file (locate-user-emacs-file "init.d/wl.org")
+ wl-load-profile-function 'alex/wl-babel-load-profile))
+#+end_src
+
+** yasnippet
+
+I want to use yasnippets everywhere, so I enable the global mode. In
+addition to the default snippets I have some in my personal dir. It
+does not load the all snippets during startup, but only if the first
+buffer switches to the corresponding mode (only the directories are
+searched during activation of the global mode).
+
+#+begin_src emacs-lisp
+ (use-package yasnippet
+ :config
+ (setq yas-snippet-dirs `("~/.emacs.d/snippets/"
+ ,yas-installed-snippets-dir))
+ (yas-global-mode 1)
+ :diminish yas-minor-mode)
+#+end_src
+
diff --git a/init.el b/init.el
new file mode 100644
index 0000000..b841c11
--- /dev/null
+++ b/init.el
@@ -0,0 +1,5 @@
+(let ((file-name-handler-alist nil))
+ (package-initialize nil)
+ (setq package-enable-at-startup nil)
+
+ (org-babel-load-file "~/.emacs.d/init.d/main.org"))
diff --git a/lisp/filladapt.el b/lisp/filladapt.el
new file mode 100644
index 0000000..4ae63ab
--- /dev/null
+++ b/lisp/filladapt.el
@@ -0,0 +1,981 @@
+;;; Adaptive fill
+;;; Copyright (C) 1989, 1995-1998 Kyle E. Jones
+;;;
+;;; This program is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2, or (at your option)
+;;; any later version.
+;;;
+;;; This program is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;; GNU General Public License for more details.
+;;;
+;;; A copy of the GNU General Public License can be obtained from this
+;;; program's author (send electronic mail to kyle@uunet.uu.net) or from
+;;; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+;;; 02139, USA.
+;;;
+;;; Send bug reports to kyle_jones@wonderworks.com
+
+;; LCD Archive Entry:
+;; filladapt|Kyle Jones|kyle_jones@wonderworks.com|
+;; Minor mode to adaptively set fill-prefix and overload filling functions|
+;; 28-February-1998|2.12|~/packages/filladapt.el|
+
+;; These functions enhance the default behavior of Emacs' Auto Fill
+;; mode and the commands fill-paragraph, lisp-fill-paragraph,
+;; fill-region-as-paragraph and fill-region.
+;;
+;; The chief improvement is that the beginning of a line to be
+;; filled is examined and, based on information gathered, an
+;; appropriate value for fill-prefix is constructed. Also the
+;; boundaries of the current paragraph are located. This occurs
+;; only if the fill prefix is not already non-nil.
+;;
+;; The net result of this is that blurbs of text that are offset
+;; from left margin by asterisks, dashes, and/or spaces, numbered
+;; examples, included text from USENET news articles, etc. are
+;; generally filled correctly with no fuss.
+;;
+;; Since this package replaces existing Emacs functions, it cannot
+;; be autoloaded. Save this in a file named filladapt.el in a
+;; Lisp directory that Emacs knows about, byte-compile it and put
+;; (require 'filladapt)
+;; in your .emacs file.
+;;
+;; Note that in this release Filladapt mode is a minor mode and it is
+;; _off_ by default. If you want it to be on by default, use
+;; (setq-default filladapt-mode t)
+;;
+;; M-x filladapt-mode toggles Filladapt mode on/off in the current
+;; buffer.
+;;
+;; Use
+;; (add-hook 'text-mode-hook 'turn-on-filladapt-mode)
+;; to have Filladapt always enabled in Text mode.
+;;
+;; Use
+;; (add-hook 'c-mode-hook 'turn-off-filladapt-mode)
+;; to have Filladapt always disabled in C mode.
+;;
+;; In many cases, you can extend Filladapt by adding appropriate
+;; entries to the following three `defvar's. See `postscript-comment'
+;; or `texinfo-comment' as a sample of what needs to be done.
+;;
+;; filladapt-token-table
+;; filladapt-token-match-table
+;; filladapt-token-conversion-table
+
+(and (featurep 'filladapt)
+ (error "filladapt cannot be loaded twice in the same Emacs session."))
+
+(provide 'filladapt)
+
+(defvar filladapt-version "2.12"
+ "Version string for filladapt.")
+
+;; BLOB to make custom stuff work even without customize
+(eval-and-compile
+ (condition-case ()
+ (require 'custom)
+ (error nil))
+ (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
+ nil ;; We've got what we needed
+ ;; We have the old custom-library, hack around it!
+ (defmacro defgroup (&rest args)
+ nil)
+ (defmacro defcustom (var value doc &rest args)
+ (` (defvar (, var) (, value) (, doc))))))
+
+(defgroup filladapt nil
+ "Enhanced filling"
+ :group 'fill)
+
+(defvar filladapt-mode nil
+ "Non-nil means that Filladapt minor mode is enabled.
+Use the filladapt-mode command to toggle the mode on/off.")
+(make-variable-buffer-local 'filladapt-mode)
+
+(defcustom filladapt-mode-line-string " Filladapt"
+ "*String to display in the modeline when Filladapt mode is active.
+Set this to nil if you don't want a modeline indicator for Filladapt."
+ :type 'string
+ :group 'filladapt)
+
+(defcustom filladapt-fill-column-tolerance nil
+ "*Tolerate filled paragraph lines ending this far from the fill column.
+If any lines other than the last paragraph line end at a column
+less than fill-column - filladapt-fill-column-tolerance, fill-column will
+be adjusted using the filladapt-fill-column-*-fuzz variables and
+the paragraph will be re-filled until the tolerance is achieved
+or filladapt runs out of fuzz values to try.
+
+A nil value means behave normally, that is, don't try refilling
+paragraphs to make filled line lengths fit within any particular
+range."
+ :type '(choice (const nil)
+ integer)
+ :group 'filladapt)
+
+(defcustom filladapt-fill-column-forward-fuzz 5
+ "*Try values from fill-column to fill-column plus this variable
+when trying to make filled paragraph lines fall with the tolerance
+range specified by filladapt-fill-column-tolerance."
+ :type 'integer
+ :group 'filladapt)
+
+(defcustom filladapt-fill-column-backward-fuzz 5
+ "*Try values from fill-column to fill-column minus this variable
+when trying to make filled paragraph lines fall with the tolerance
+range specified by filladapt-fill-column-tolerance."
+ :type 'integer
+ :group 'filladapt)
+
+;; install on minor-mode-alist
+(or (assq 'filladapt-mode minor-mode-alist)
+ (setq minor-mode-alist (cons (list 'filladapt-mode
+ 'filladapt-mode-line-string)
+ minor-mode-alist)))
+
+(defcustom filladapt-token-table
+ '(
+ ;; this must be first
+ ("^" beginning-of-line)
+ ;; Included text in news or mail replies
+ (">+" citation->)
+ ;; Included text generated by SUPERCITE. We can't hope to match all
+ ;; the possible variations, your mileage may vary.
+ ("\\(\\w\\|[0-9]\\)[^'`\"< \t\n]*>[ \t]*" supercite-citation)
+ ;; Lisp comments
+ (";+" lisp-comment)
+ ;; UNIX shell comments
+ ("#+" sh-comment)
+ ;; Postscript comments
+ ("%+" postscript-comment)
+ ;; C++ comments
+ ("///*" c++-comment)
+ ;; Texinfo comments
+ ("@c[ \t]" texinfo-comment)
+ ("@comment[ \t]" texinfo-comment)
+ ;; Bullet types.
+ ;;
+ ;; LaTex \item
+ ;;
+ ("\\\\item[ \t]" bullet)
+ ;;
+ ;; 1. xxxxx
+ ;; xxxxx
+ ;;
+ ("[0-9]+\\.[ \t]" bullet)
+ ;;
+ ;; 2.1.3 xxxxx xx x xx x
+ ;; xxx
+ ;;
+ ("[0-9]+\\(\\.[0-9]+\\)+[ \t]" bullet)
+ ;;
+ ;; a. xxxxxx xx
+ ;; xxx xxx
+ ;;
+ ("[A-Za-z]\\.[ \t]" bullet)
+ ;;
+ ;; 1) xxxx x xx x xx or (1) xx xx x x xx xx
+ ;; xx xx xxxx xxx xx x x xx x
+ ;;
+ ("(?[0-9]+)[ \t]" bullet)
+ ;;
+ ;; a) xxxx x xx x xx or (a) xx xx x x xx xx
+ ;; xx xx xxxx xxx xx x x xx x
+ ;;
+ ("(?[A-Za-z])[ \t]" bullet)
+ ;;
+ ;; 2a. xx x xxx x x xxx
+ ;; xxx xx x xx x
+ ;;
+ ("[0-9]+[A-Za-z]\\.[ \t]" bullet)
+ ;;
+ ;; 1a) xxxx x xx x xx or (1a) xx xx x x xx xx
+ ;; xx xx xxxx xxx xx x x xx x
+ ;;
+ ("(?[0-9]+[A-Za-z])[ \t]" bullet)
+ ;;
+ ;; - xx xxx xxxx or * xx xx x xxx xxx
+ ;; xxx xx xx x xxx x xx x x x
+ ;;
+ ("[-~*+]+[ \t]" bullet)
+ ;;
+ ;; o xx xxx xxxx xx x xx xxx x xxx xx x xxx
+ ;; xxx xx xx
+ ;;
+ ("o[ \t]" bullet)
+ ;; don't touch
+ ("[ \t]+" space)
+ ("$" end-of-line)
+ )
+ "Table of tokens filladapt knows about.
+Format is
+
+ ((REGEXP SYM) ...)
+
+filladapt uses this table to build a tokenized representation of
+the beginning of the current line. Each REGEXP is matched
+against the beginning of the line until a match is found.
+Matching is done case-sensitively. The corresponding SYM is
+added to the list, point is moved to (match-end 0) and the
+process is repeated. The process ends when there is no REGEXP in
+the table that matches what is at point."
+ :type '(repeat (list regexp symbol))
+ :group 'filladapt)
+
+(defcustom filladapt-not-token-table
+ '(
+ "[Ee]\\.g\\.[ \t,]"
+ "[Ii]\\.e\\.[ \t,]"
+ ;; end-of-line isn't a token if whole line is empty
+ "^$"
+ )
+ "List of regexps that can never be a token.
+Before trying the regular expressions in filladapt-token-table,
+the regexps in this list are tried. If any regexp in this list
+matches what is at point then the token generator gives up and
+doesn't try any of the regexps in filladapt-token-table.
+
+Regexp matching is done case-sensitively."
+ :type '(repeat regexp)
+ :group 'filladapt)
+
+(defcustom filladapt-token-match-table
+ '(
+ (citation-> citation->)
+ (supercite-citation supercite-citation)
+ (lisp-comment lisp-comment)
+ (sh-comment sh-comment)
+ (postscript-comment postscript-comment)
+ (c++-comment c++-comment)
+ (texinfo-comment texinfo-comment)
+ (bullet)
+ (space bullet space)
+ (beginning-of-line beginning-of-line)
+ )
+ "Table describing what tokens a certain token will match.
+
+To decide whether a line belongs in the current paragraph,
+filladapt creates a token list for the fill prefix of both lines.
+Tokens and the columns where tokens end are compared. This table
+specifies what a certain token will match.
+
+Table format is
+
+ (SYM [SYM1 [SYM2 ...]])
+
+The first symbol SYM is the token, subsequent symbols are the
+tokens that SYM will match."
+ :type '(repeat (repeat symbol))
+ :group 'filladapt)
+
+(defcustom filladapt-token-match-many-table
+ '(
+ space
+ )
+ "List of tokens that can match multiple tokens.
+If one of these tokens appears in a token list, it will eat all
+matching tokens in a token list being matched against it until it
+encounters a token that doesn't match or a token that ends on
+a greater column number."
+ :type '(repeat symbol)
+ :group 'filladapt)
+
+(defcustom filladapt-token-paragraph-start-table
+ '(
+ bullet
+ )
+ "List of tokens that indicate the start of a paragraph.
+If parsing a line generates a token list containing one of
+these tokens, then the line is considered to be the start of a
+paragraph."
+ :type '(repeat symbol)
+ :group 'filladapt)
+
+(defcustom filladapt-token-conversion-table
+ '(
+ (citation-> . exact)
+ (supercite-citation . exact)
+ (lisp-comment . exact)
+ (sh-comment . exact)
+ (postscript-comment . exact)
+ (c++-comment . exact)
+ (texinfo-comment . exact)
+ (bullet . spaces)
+ (space . exact)
+ (end-of-line . exact)
+ )
+ "Table that specifies how to convert a token into a fill prefix.
+Table format is
+
+ ((SYM . HOWTO) ...)
+
+SYM is the symbol naming the token to be converted.
+HOWTO specifies how to do the conversion.
+ `exact' means copy the token's string directly into the fill prefix.
+ `spaces' means convert all characters in the token string that are
+ not a TAB or a space into spaces and copy the resulting string into
+ the fill prefix."
+ :type '(repeat (cons symbol (choice (const exact)
+ (const spaces))))
+ :group 'filladapt)
+
+(defvar filladapt-function-table
+ (let ((assoc-list
+ (list (cons 'fill-paragraph (symbol-function 'fill-paragraph))
+ (cons 'fill-region (symbol-function 'fill-region))
+ (cons 'fill-region-as-paragraph
+ (symbol-function 'fill-region-as-paragraph))
+ (cons 'do-auto-fill (symbol-function 'do-auto-fill)))))
+ ;; v18 Emacs doesn't have lisp-fill-paragraph
+ (if (fboundp 'lisp-fill-paragraph)
+ (nconc assoc-list
+ (list (cons 'lisp-fill-paragraph
+ (symbol-function 'lisp-fill-paragraph)))))
+ assoc-list )
+ "Table containing the old function definitions that filladapt usurps.")
+
+(defcustom filladapt-fill-paragraph-post-hook nil
+ "Hooks run after filladapt runs fill-paragraph."
+ :type 'hook
+ :group 'filladapt)
+
+(defvar filladapt-inside-filladapt nil
+ "Non-nil if the filladapt version of a fill function executing.
+Currently this is only checked by the filladapt version of
+fill-region-as-paragraph to avoid this infinite recursion:
+
+ fill-region-as-paragraph -> fill-paragraph -> fill-region-as-paragraph ...")
+
+(defcustom filladapt-debug nil
+ "Non-nil means filladapt debugging is enabled.
+Use the filladapt-debug command to turn on debugging.
+
+With debugging enabled, filladapt will
+
+ a. display the proposed indentation with the tokens highlighted
+ using filladapt-debug-indentation-face-1 and
+ filladapt-debug-indentation-face-2.
+ b. display the current paragraph using the face specified by
+ filladapt-debug-paragraph-face."
+ :type 'boolean
+ :group 'filladapt)
+
+(if filladapt-debug
+ (add-hook 'post-command-hook 'filladapt-display-debug-info-maybe))
+
+(defvar filladapt-debug-indentation-face-1 'highlight
+ "Face used to display the indentation when debugging is enabled.")
+
+(defvar filladapt-debug-indentation-face-2 'secondary-selection
+ "Another face used to display the indentation when debugging is enabled.")
+
+(defvar filladapt-debug-paragraph-face 'bold
+ "Face used to display the current paragraph when debugging is enabled.")
+
+(defvar filladapt-debug-indentation-extents nil)
+(make-variable-buffer-local 'filladapt-debug-indentation-extents)
+(defvar filladapt-debug-paragraph-extent nil)
+(make-variable-buffer-local 'filladapt-debug-paragraph-extent)
+
+;; kludge city, see references in code.
+(defvar filladapt-old-line-prefix)
+
+(defun do-auto-fill ()
+ (catch 'done
+ (if (and filladapt-mode (null fill-prefix))
+ (save-restriction
+ (let ((paragraph-ignore-fill-prefix nil)
+ ;; if the user wanted this stuff, they probably
+ ;; wouldn't be using filladapt-mode.
+ (adaptive-fill-mode nil)
+ (adaptive-fill-regexp nil)
+ ;; need this or Emacs 19 ignores fill-prefix when
+ ;; inside a comment.
+ (comment-multi-line t)
+ (filladapt-inside-filladapt t)
+ fill-prefix retval)
+ (if (filladapt-adapt nil nil)
+ (progn
+ (setq retval (filladapt-funcall 'do-auto-fill))
+ (throw 'done retval))))))
+ (filladapt-funcall 'do-auto-fill)))
+
+(defun filladapt-fill-paragraph (function arg)
+ (catch 'done
+ (if (and filladapt-mode (null fill-prefix))
+ (save-restriction
+ (let ((paragraph-ignore-fill-prefix nil)
+ ;; if the user wanted this stuff, they probably
+ ;; wouldn't be using filladapt-mode.
+ (adaptive-fill-mode nil)
+ (adaptive-fill-regexp nil)
+ ;; need this or Emacs 19 ignores fill-prefix when
+ ;; inside a comment.
+ (comment-multi-line t)
+ fill-prefix retval)
+ (if (filladapt-adapt t nil)
+ (progn
+ (if filladapt-fill-column-tolerance
+ (let* ((low (- fill-column
+ filladapt-fill-column-backward-fuzz))
+ (high (+ fill-column
+ filladapt-fill-column-forward-fuzz))
+ (old-fill-column fill-column)
+ (fill-column fill-column)
+ (lim (- high low))
+ (done nil)
+ (sign 1)
+ (delta 0))
+ (while (not done)
+ (setq retval (filladapt-funcall function arg))
+ (if (filladapt-paragraph-within-fill-tolerance)
+ (setq done 'success)
+ (setq delta (1+ delta)
+ sign (* sign -1)
+ fill-column (+ fill-column (* delta sign)))
+ (while (and (<= delta lim)
+ (or (< fill-column low)
+ (> fill-column high)))
+ (setq delta (1+ delta)
+ sign (* sign -1)
+ fill-column (+ fill-column
+ (* delta sign))))
+ (setq done (> delta lim))))
+ ;; if the paragraph lines never fell
+ ;; within the tolerances, refill using
+ ;; the old fill-column.
+ (if (not (eq done 'success))
+ (let ((fill-column old-fill-column))
+ (setq retval (filladapt-funcall function arg)))))
+ (setq retval (filladapt-funcall function arg)))
+ (run-hooks 'filladapt-fill-paragraph-post-hook)
+ (throw 'done retval))))))
+ ;; filladapt-adapt failed, so do fill-paragraph normally.
+ (filladapt-funcall function arg)))
+
+(defun fill-paragraph (arg)
+ "Fill paragraph at or after point. Prefix arg means justify as well.
+
+(This function has been overloaded with the `filladapt' version.)
+
+If `sentence-end-double-space' is non-nil, then period followed by one
+space does not end a sentence, so don't break a line there.
+
+If `fill-paragraph-function' is non-nil, we call it (passing our
+argument to it), and if it returns non-nil, we simply return its value."
+ (interactive "*P")
+ (let ((filladapt-inside-filladapt t))
+ (filladapt-fill-paragraph 'fill-paragraph arg)))
+
+(defun lisp-fill-paragraph (&optional arg)
+ "Like \\[fill-paragraph], but handle Emacs Lisp comments.
+
+(This function has been overloaded with the `filladapt' version.)
+
+If any of the current line is a comment, fill the comment or the
+paragraph of it that point is in, preserving the comment's indentation
+and initial semicolons."
+ (interactive "*P")
+ (let ((filladapt-inside-filladapt t))
+ (filladapt-fill-paragraph 'lisp-fill-paragraph arg)))
+
+(defun fill-region-as-paragraph (beg end &optional justify
+ nosqueeze squeeze-after)
+ "Fill the region as one paragraph.
+
+(This function has been overloaded with the `filladapt' version.)
+
+It removes any paragraph breaks in the region and extra newlines at the end,
+indents and fills lines between the margins given by the
+`current-left-margin' and `current-fill-column' functions.
+It leaves point at the beginning of the line following the paragraph.
+
+Normally performs justification according to the `current-justification'
+function, but with a prefix arg, does full justification instead.
+
+From a program, optional third arg JUSTIFY can specify any type of
+justification. Fourth arg NOSQUEEZE non-nil means not to make spaces
+between words canonical before filling. Fifth arg SQUEEZE-AFTER, if non-nil,
+means don't canonicalize spaces before that position.
+
+If `sentence-end-double-space' is non-nil, then period followed by one
+space does not end a sentence, so don't break a line there."
+ (interactive "*r\nP")
+ (if (and filladapt-mode (not filladapt-inside-filladapt))
+ (save-restriction
+ (narrow-to-region beg end)
+ (let ((filladapt-inside-filladapt t)
+ line-start last-token)
+ (goto-char beg)
+ (while (equal (char-after (point)) ?\n)
+ (delete-char 1))
+ (end-of-line)
+ (while (zerop (forward-line))
+ (if (setq last-token
+ (car (filladapt-tail (filladapt-parse-prefixes))))
+ (progn
+ (setq line-start (point))
+ (move-to-column (nth 1 last-token))
+ (delete-region line-start (point))))
+ ;; Dance...
+ ;;
+ ;; Do this instead of (delete-char -1) to keep
+ ;; markers on the correct side of the whitespace.
+ (goto-char (1- (point)))
+ (insert " ")
+ (delete-char 1)
+
+ (end-of-line))
+ (goto-char beg)
+ (fill-paragraph justify))
+ ;; In XEmacs 19.12 and Emacs 18.59 fill-region relies on
+ ;; fill-region-as-paragraph to do this. If we don't do
+ ;; it, fill-region will spin in an endless loop.
+ (goto-char (point-max)))
+ (condition-case nil
+ ;; five args for Emacs 19.31
+ (filladapt-funcall 'fill-region-as-paragraph beg end
+ justify nosqueeze squeeze-after)
+ (wrong-number-of-arguments
+ (condition-case nil
+ ;; four args for Emacs 19.29
+ (filladapt-funcall 'fill-region-as-paragraph beg end
+ justify nosqueeze)
+ ;; three args for the rest of the world.
+ (wrong-number-of-arguments
+ (filladapt-funcall 'fill-region-as-paragraph beg end justify)))))))
+
+(defun fill-region (beg end &optional justify nosqueeze to-eop)
+ "Fill each of the paragraphs in the region.
+
+(This function has been overloaded with the `filladapt' version.)
+
+Prefix arg (non-nil third arg, if called from program) means justify as well.
+
+Noninteractively, fourth arg NOSQUEEZE non-nil means to leave
+whitespace other than line breaks untouched, and fifth arg TO-EOP
+non-nil means to keep filling to the end of the paragraph (or next
+hard newline, if `use-hard-newlines' is on).
+
+If `sentence-end-double-space' is non-nil, then period followed by one
+space does not end a sentence, so don't break a line there."
+ (interactive "*r\nP")
+ (if (and filladapt-mode (not filladapt-inside-filladapt))
+ (save-restriction
+ (narrow-to-region beg end)
+ (let ((filladapt-inside-filladapt t)
+ start)
+ (goto-char beg)
+ (while (not (eobp))
+ (setq start (point))
+ (while (and (not (eobp)) (not (filladapt-parse-prefixes)))
+ (forward-line 1))
+ (if (not (equal start (point)))
+ (progn
+ (save-restriction
+ (narrow-to-region start (point))
+ (fill-region start (point) justify nosqueeze to-eop)
+ (goto-char (point-max)))
+ (if (and (not (bolp)) (not (eobp)))
+ (forward-line 1))))
+ (if (filladapt-parse-prefixes)
+ (progn
+ (save-restriction
+ ;; for the clipping region
+ (filladapt-adapt t t)
+ (fill-paragraph justify)
+ (goto-char (point-max)))
+ (if (and (not (bolp)) (not (eobp)))
+ (forward-line 1)))))))
+ (condition-case nil
+ (filladapt-funcall 'fill-region beg end justify nosqueeze to-eop)
+ (wrong-number-of-arguments
+ (condition-case nil
+ (filladapt-funcall 'fill-region beg end justify nosqueeze)
+ (wrong-number-of-arguments
+ (filladapt-funcall 'fill-region beg end justify)))))))
+
+(defvar zmacs-region-stays) ; for XEmacs
+
+(defun filladapt-mode (&optional arg)
+ "Toggle Filladapt minor mode.
+With arg, turn Filladapt mode on iff arg is positive. When
+Filladapt mode is enabled, auto-fill-mode and the fill-paragraph
+command are both smarter about guessing a proper fill-prefix and
+finding paragraph boundaries when bulleted and indented lines and
+paragraphs are used."
+ (interactive "P")
+ ;; don't deactivate the region.
+ (setq zmacs-region-stays t)
+ (setq filladapt-mode (or (and arg (> (prefix-numeric-value arg) 0))
+ (and (null arg) (null filladapt-mode))))
+ (if (fboundp 'force-mode-line-update)
+ (force-mode-line-update)
+ (set-buffer-modified-p (buffer-modified-p))))
+
+(defun turn-on-filladapt-mode ()
+ "Unconditionally turn on Filladapt mode in the current buffer."
+ (filladapt-mode 1))
+
+(defun turn-off-filladapt-mode ()
+ "Unconditionally turn off Filladapt mode in the current buffer."
+ (filladapt-mode -1))
+
+(defun filladapt-funcall (function &rest args)
+ "Call the old definition of a function that filladapt has usurped."
+ (apply (cdr (assoc function filladapt-function-table)) args))
+
+(defun filladapt-paragraph-start (list)
+ "Returns non-nil if LIST contains a paragraph starting token.
+LIST should be a token list as returned by filladapt-parse-prefixes."
+ (catch 'done
+ (while list
+ (if (memq (car (car list)) filladapt-token-paragraph-start-table)
+ (throw 'done t))
+ (setq list (cdr list)))))
+
+(defun filladapt-parse-prefixes ()
+ "Parse all the tokens after point and return a list of them.
+The tokens regular expressions are specified in
+filladapt-token-table. The list returned is of this form
+
+ ((SYM COL STRING) ...)
+
+SYM is a token symbol as found in filladapt-token-table.
+COL is the column at which the token ended.
+STRING is the token's text."
+ (save-excursion
+ (let ((token-list nil)
+ (done nil)
+ (old-point (point))
+ (case-fold-search nil)
+ token-table not-token-table moved)
+ (catch 'done
+ (while (not done)
+ (setq not-token-table filladapt-not-token-table)
+ (while not-token-table
+ (if (looking-at (car not-token-table))
+ (throw 'done t))
+ (setq not-token-table (cdr not-token-table)))
+ (setq token-table filladapt-token-table
+ done t)
+ (while token-table
+ (if (null (looking-at (car (car token-table))))
+ (setq token-table (cdr token-table))
+ (goto-char (match-end 0))
+ (setq token-list (cons (list (nth 1 (car token-table))
+ (current-column)
+ (buffer-substring
+ (match-beginning 0)
+ (match-end 0)))
+ token-list)
+ moved (not (eq (point) old-point))
+ token-table (if moved nil (cdr token-table))
+ done (not moved)
+ old-point (point))))))
+ (nreverse token-list))))
+
+(defun filladapt-tokens-match-p (list1 list2)
+ "Compare two token lists and return non-nil if they match, nil otherwise.
+The lists are walked through in lockstep, comparing tokens.
+
+When two tokens A and B are compared, they are considered to
+match if
+
+ 1. A appears in B's list of matching tokens or
+ B appears in A's list of matching tokens
+and
+ 2. A and B both end at the same column
+ or
+ A can match multiple tokens and ends at a column > than B
+ or
+ B can match multiple tokens and ends at a column > than A
+
+In the case where the end columns differ the list pointer for the
+token with the greater end column is not moved forward, which
+allows its current token to be matched against the next token in
+the other list in the next iteration of the matching loop.
+
+All tokens must be matched in order for the lists to be considered
+matching."
+ (let ((matched t)
+ (done nil))
+ (while (and (not done) list1 list2)
+ (let* ((token1 (car (car list1)))
+ (token1-matches-many-p
+ (memq token1 filladapt-token-match-many-table))
+ (token1-matches (cdr (assq token1 filladapt-token-match-table)))
+ (token1-endcol (nth 1 (car list1)))
+ (token2 (car (car list2)))
+ (token2-matches-many-p
+ (memq token2 filladapt-token-match-many-table))
+ (token2-matches (cdr (assq token2 filladapt-token-match-table)))
+ (token2-endcol (nth 1 (car list2)))
+ (tokens-match (or (memq token1 token2-matches)
+ (memq token2 token1-matches))))
+ (cond ((not tokens-match)
+ (setq matched nil
+ done t))
+ ((and token1-matches-many-p token2-matches-many-p)
+ (cond ((= token1-endcol token2-endcol)
+ (setq list1 (cdr list1)
+ list2 (cdr list2)))
+ ((< token1-endcol token2-endcol)
+ (setq list1 (cdr list1)))
+ (t
+ (setq list2 (cdr list2)))))
+ (token1-matches-many-p
+ (cond ((= token1-endcol token2-endcol)
+ (setq list1 (cdr list1)
+ list2 (cdr list2)))
+ ((< token1-endcol token2-endcol)
+ (setq matched nil
+ done t))
+ (t
+ (setq list2 (cdr list2)))))
+ (token2-matches-many-p
+ (cond ((= token1-endcol token2-endcol)
+ (setq list1 (cdr list1)
+ list2 (cdr list2)))
+ ((< token2-endcol token1-endcol)
+ (setq matched nil
+ done t))
+ (t
+ (setq list1 (cdr list1)))))
+ ((= token1-endcol token2-endcol)
+ (setq list1 (cdr list1)
+ list2 (cdr list2)))
+ (t
+ (setq matched nil
+ done t)))))
+ (and matched (null list1) (null list2)) ))
+
+(defun filladapt-make-fill-prefix (list)
+ "Build a fill-prefix for a token LIST.
+filladapt-token-conversion-table specifies how this is done."
+ (let ((prefix-list nil)
+ (conversion-spec nil))
+ (while list
+ (setq conversion-spec (cdr (assq (car (car list))
+ filladapt-token-conversion-table)))
+ (cond ((eq conversion-spec 'spaces)
+ (setq prefix-list
+ (cons
+ (filladapt-convert-to-spaces (nth 2 (car list)))
+ prefix-list)))
+ ((eq conversion-spec 'exact)
+ (setq prefix-list
+ (cons
+ (nth 2 (car list))
+ prefix-list))))
+ (setq list (cdr list)))
+ (apply (function concat) (nreverse prefix-list)) ))
+
+(defun filladapt-paragraph-within-fill-tolerance ()
+ (catch 'done
+ (save-excursion
+ (let ((low (- fill-column filladapt-fill-column-tolerance))
+ (shortline nil))
+ (goto-char (point-min))
+ (while (not (eobp))
+ (if shortline
+ (throw 'done nil)
+ (end-of-line)
+ (setq shortline (< (current-column) low))
+ (forward-line 1)))
+ t ))))
+
+(defun filladapt-convert-to-spaces (string)
+ "Return a copy of STRING, with all non-tabs and non-space changed to spaces."
+ (let ((i 0)
+ (space-list '(?\ ?\t))
+ (space ?\ )
+ (lim (length string)))
+ (setq string (copy-sequence string))
+ (while (< i lim)
+ (if (not (memq (aref string i) space-list))
+ (aset string i space))
+ (setq i (1+ i)))
+ string ))
+
+(defun filladapt-adapt (paragraph debugging)
+ "Set fill-prefix based on the contents of the current line.
+
+If the first arg PARAGRAPH is non-nil, also set a clipping region
+around the current paragraph.
+
+If the second arg DEBUGGING is non-nil, don't do the kludge that's
+necessary to make certain paragraph fills work properly."
+ (save-excursion
+ (beginning-of-line)
+ (let ((token-list (filladapt-parse-prefixes))
+ curr-list done)
+ (if (null token-list)
+ nil
+ (setq fill-prefix (filladapt-make-fill-prefix token-list))
+ (if paragraph
+ (let (beg end)
+ (if (filladapt-paragraph-start token-list)
+ (setq beg (point))
+ (save-excursion
+ (setq done nil)
+ (while (not done)
+ (cond ((not (= 0 (forward-line -1)))
+ (setq done t
+ beg (point)))
+ ((not (filladapt-tokens-match-p
+ token-list
+ (setq curr-list (filladapt-parse-prefixes))))
+ (forward-line 1)
+ (setq done t
+ beg (point)))
+ ((filladapt-paragraph-start curr-list)
+ (setq done t
+ beg (point)))))))
+ (save-excursion
+ (setq done nil)
+ (while (not done)
+ (cond ((not (= 0 (progn (end-of-line) (forward-line 1))))
+ (setq done t
+ end (point)))
+ ((not (filladapt-tokens-match-p
+ token-list
+ (setq curr-list (filladapt-parse-prefixes))))
+ (setq done t
+ end (point)))
+ ((filladapt-paragraph-start curr-list)
+ (setq done t
+ end (point))))))
+ (narrow-to-region beg end)
+ ;; Multiple spaces after the bullet at the start of
+ ;; a hanging list paragraph get squashed by
+ ;; fill-paragraph. We kludge around this by
+ ;; replacing the line prefix with the fill-prefix
+ ;; used by the rest of the lines in the paragraph.
+ ;; fill-paragraph will not alter the fill prefix so
+ ;; we win. The post hook restores the old line prefix
+ ;; after fill-paragraph has been called.
+ (if (and paragraph (not debugging))
+ (let (col)
+ (setq col (nth 1 (car (filladapt-tail token-list))))
+ (goto-char (point-min))
+ (move-to-column col)
+ (setq filladapt-old-line-prefix
+ (buffer-substring (point-min) (point)))
+ (delete-region (point-min) (point))
+ (insert fill-prefix)
+ (add-hook 'filladapt-fill-paragraph-post-hook
+ 'filladapt-cleanup-kludge-at-point-min)))))
+ t ))))
+
+(defun filladapt-cleanup-kludge-at-point-min ()
+ "Cleanup the paragraph fill kludge.
+See filladapt-adapt."
+ (save-excursion
+ (goto-char (point-min))
+ (insert filladapt-old-line-prefix)
+ (delete-char (length fill-prefix))
+ (remove-hook 'filladapt-fill-paragraph-post-hook
+ 'filladapt-cleanup-kludge-at-point-min)))
+
+(defun filladapt-tail (list)
+ "Returns the last cons in LIST."
+ (if (null list)
+ nil
+ (while (consp (cdr list))
+ (setq list (cdr list)))
+ list ))
+
+(defun filladapt-delete-extent (e)
+ (if (fboundp 'delete-extent)
+ (delete-extent e)
+ (delete-overlay e)))
+
+(defun filladapt-make-extent (beg end)
+ (if (fboundp 'make-extent)
+ (make-extent beg end)
+ (make-overlay beg end)))
+
+(defun filladapt-set-extent-endpoints (e beg end)
+ (if (fboundp 'set-extent-endpoints)
+ (set-extent-endpoints e beg end)
+ (move-overlay e beg end)))
+
+(defun filladapt-set-extent-property (e prop val)
+ (if (fboundp 'set-extent-property)
+ (set-extent-property e prop val)
+ (overlay-put e prop val)))
+
+(defun filladapt-debug ()
+ "Toggle filladapt debugging on/off in the current buffer."
+;; (interactive)
+ (make-local-variable 'filladapt-debug)
+ (setq filladapt-debug (not filladapt-debug))
+ (if (null filladapt-debug)
+ (progn
+ (mapcar (function (lambda (e) (filladapt-set-extent-endpoints e 1 1)))
+ filladapt-debug-indentation-extents)
+ (if filladapt-debug-paragraph-extent
+ (progn
+ (filladapt-delete-extent filladapt-debug-paragraph-extent)
+ (setq filladapt-debug-paragraph-extent nil)))))
+ (add-hook 'post-command-hook 'filladapt-display-debug-info-maybe))
+
+(defun filladapt-display-debug-info-maybe ()
+ (cond ((null filladapt-debug) nil)
+ (fill-prefix nil)
+ (t
+ (if (null filladapt-debug-paragraph-extent)
+ (let ((e (filladapt-make-extent 1 1)))
+ (filladapt-set-extent-property e 'detachable nil)
+ (filladapt-set-extent-property e 'evaporate nil)
+ (filladapt-set-extent-property e 'face
+ filladapt-debug-paragraph-face)
+ (setq filladapt-debug-paragraph-extent e)))
+ (save-excursion
+ (save-restriction
+ (let ((ei-list filladapt-debug-indentation-extents)
+ (ep filladapt-debug-paragraph-extent)
+ (face filladapt-debug-indentation-face-1)
+ fill-prefix token-list)
+ (if (null (filladapt-adapt t t))
+ (progn
+ (filladapt-set-extent-endpoints ep 1 1)
+ (while ei-list
+ (filladapt-set-extent-endpoints (car ei-list) 1 1)
+ (setq ei-list (cdr ei-list))))
+ (filladapt-set-extent-endpoints ep (point-min) (point-max))
+ (beginning-of-line)
+ (setq token-list (filladapt-parse-prefixes))
+ (message "(%s)" (mapconcat (function
+ (lambda (q) (symbol-name (car q))))
+ token-list
+ " "))
+ (while token-list
+ (if ei-list
+ (setq e (car ei-list)
+ ei-list (cdr ei-list))
+ (setq e (filladapt-make-extent 1 1))
+ (filladapt-set-extent-property e 'detachable nil)
+ (filladapt-set-extent-property e 'evaporate nil)
+ (setq filladapt-debug-indentation-extents
+ (cons e filladapt-debug-indentation-extents)))
+ (filladapt-set-extent-property e 'face face)
+ (filladapt-set-extent-endpoints e (point)
+ (progn
+ (move-to-column
+ (nth 1
+ (car token-list)))
+ (point)))
+ (if (eq face filladapt-debug-indentation-face-1)
+ (setq face filladapt-debug-indentation-face-2)
+ (setq face filladapt-debug-indentation-face-1))
+ (setq token-list (cdr token-list)))
+ (while ei-list
+ (filladapt-set-extent-endpoints (car ei-list) 1 1)
+ (setq ei-list (cdr ei-list))))))))))
diff --git a/lisp/promela-mode.el b/lisp/promela-mode.el
new file mode 100644
index 0000000..3ab4da7
--- /dev/null
+++ b/lisp/promela-mode.el
@@ -0,0 +1,985 @@
+;; promela-mode.el --- major mode for editing PROMELA program files
+;; $Revision: 1.11 $ $Date: 2001/07/09 18:36:45 $ $Author: engstrom $
+
+;; Author: Eric Engstrom <eric.engstrom@honeywell.com>
+;; Maintainer: Eric Engstrom
+;; Keywords: spin, promela, tools
+
+;; Copyright (C) 1998-2003 Eric Engstrom / Honeywell Laboratories
+
+;; ... Possibly insert GPL here someday ...
+
+;;; Commentary:
+
+;; This file contains code for a GNU Emacs major mode for editing
+;; PROMELA (SPIN) program files.
+
+;; Type "C-h m" in Emacs (while in a buffer in promela-mode) for
+;; information on how to configure indentation and fontification,
+;; or look at the configuration variables below.
+
+;; To use, place promela-mode.el in a directory in your load-path.
+;; Then, put the following lines into your .emacs and promela-mode
+;; will be automatically loaded when editing a PROMELA program.
+
+;; (autoload 'promela-mode "promela-mode" "PROMELA mode" nil t)
+;; (setq auto-mode-alist
+;; (append
+;; (list (cons "\\.promela$" 'promela-mode)
+;; (cons "\\.spin$" 'promela-mode)
+;; (cons "\\.pml$" 'promela-mode)
+;; ;; (cons "\\.other-extensions$" 'promela-mode)
+;; )
+;; auto-mode-alist))
+
+;; If you wish for promela-mode to be used for files with other
+;; extensions you add your own patterned after the code above.
+
+;; Note that promela-mode adhears to the font-lock "standards" and
+;; defines several "levels" of fontification or colorization. The
+;; default is fairly gaudy, so I can imagine that some folks would
+;; like a bit less. FMI: see `font-lock-maximum-decoration'
+
+;; This mode is known to work under the following versions of emacs:
+;; - XEmacs: 19.16, 20.x, 21.x
+;; - FSF/GNU Emacs: 19.34
+;; - NTEmacs (FSF): 20.[67]
+;; That is not to say there are no bugs specific to one of those versions :-)
+
+;; Please send any comments, bugs, patches or other requests to
+;; Eric Engstrom at engstrom@htc.honeywell.com
+
+;; To-Do:
+;; - compile/syntax-check/verify? (suggested by R.Goldman)
+;; - indentation - splitting lines at logical operators (M. Rangarajan)
+;; [ This might "devolve" to indentation after "->" or ";"
+;; being as is, but anything else indent even more? ]
+;; :: SomeReallyLongArrayRef[this].typedefField != SomeReallyLongConstant -> /* some-comment */
+;; [ Suggestion would be to break the first line after the !=, therefore: ]
+;; :: SomeReallyLongArrayRef[this].typedefField
+;; != SomeReallyLongConstant -> /* some-comment */
+;; [ at this point I'm not so sure about this change... EE: 2001/05/19 ]
+
+;;; -------------------------------------------------------------------------
+;;; Code:
+
+;; NOTE: same as CVS revision:
+(defconst promela-mode-version "$Revision: 1.11 $"
+ "Promela-mode version number.")
+
+;; -------------------------------------------------------------------------
+;; The following constant values can be modified by the user in a .emacs file
+
+(defconst promela-block-indent 2
+ "*Controls indentation of lines within a block (`{') construct")
+
+(defconst promela-selection-indent 2
+ "*Controls indentation of options within a selection (`if')
+or iteration (`do') construct")
+
+(defconst promela-selection-option-indent 3
+ "*Controls indentation of lines after options within selection or
+iteration construct (`::')")
+
+(defconst promela-comment-col 32
+ "*Defines the desired comment column for comments to the right of text.")
+
+(defconst promela-tab-always-indent t
+ "*Non-nil means TAB in Promela mode should always reindent the current line,
+regardless of where in the line point is when the TAB command is used.")
+
+(defconst promela-auto-match-delimiter t
+ "*Non-nil means typing an open-delimiter (i.e. parentheses, brace, quote, etc)
+should also insert the matching closing delmiter character.")
+
+;; That should be about it for most users...
+;; unless you wanna hack elisp, the rest of this is probably uninteresting
+
+
+;; -------------------------------------------------------------------------
+;; help determine what emacs we have here...
+
+(defconst promela-xemacsp (string-match "XEmacs" (emacs-version))
+ "Non-nil if we are running in the XEmacs environment.")
+
+;;;(defconst promela-xemacs20p (and promela-xemacsp (>= emacs-major-version 20))
+;; "Non-nil if we are running in an XEmacs environment version 20 or greater.")
+
+;; -------------------------------------------------------------------------
+;; promela-mode font faces/definitions
+
+;; make use of font-lock stuff, so say that explicitly
+(require 'font-lock)
+
+;; BLECH! YUCK! I just wish these guys could agree to something....
+;; Faces available in: ntemacs emacs xemacs xemacs xemacs
+;; font-lock- xxx -face 20.6 19.34 19.16 20.x 21.x
+;; -builtin- X
+;; -constant- X
+;; -comment- X X X X X
+;; -doc-string- X X X
+;; -function-name- X X X X X
+;; -keyword- X X X X X
+;; -preprocessor- X X X
+;; -reference- X X X X
+;; -signal-name- X X!20.0
+;; -string- X X X X X
+;; -type- X X X X X
+;; -variable-name- X X X X X
+;; -warning- X X
+
+;;; Compatibility on faces between versions of emacs-en
+(unless promela-xemacsp
+
+ (defvar font-lock-preprocessor-face 'font-lock-preprocessor-face
+ "Face name to use for preprocessor statements.")
+ ;; For consistency try to define the preprocessor face == builtin face
+ (condition-case nil
+ (copy-face 'font-lock-builtin-face 'font-lock-preprocessor-face)
+ (error
+ (defface font-lock-preprocessor-face
+ '((t (:foreground "blue" :italic nil :underline t)))
+ "Face Lock mode face used to highlight preprocessor statements."
+ :group 'font-lock-highlighting-faces)))
+
+ (defvar font-lock-reference-face 'font-lock-reference-face
+ "Face name to use for constants and reference and label names.")
+ ;; For consistency try to define the reference face == constant face
+ (condition-case nil
+ (copy-face 'font-lock-constant-face 'font-lock-reference-face)
+ (error
+ (defface font-lock-reference-face
+ '((((class grayscale) (background light))
+ (:foreground "LightGray" :bold t :underline t))
+ (((class grayscale) (background dark))
+ (:foreground "Gray50" :bold t :underline t))
+ (((class color) (background light)) (:foreground "CadetBlue"))
+ (((class color) (background dark)) (:foreground "Aquamarine"))
+ (t (:bold t :underline t)))
+ "Font Lock mode face used to highlight constancs, references and labels."
+ :group 'font-lock-highlighting-faces)))
+
+ )
+
+;; send-poll "symbol" face is custom to promela-mode
+;; but check for existence to allow someone to override it
+(defvar promela-fl-send-poll-face 'promela-fl-send-poll-face
+ "Face name to use for Promela Send or Poll symbols: `!' or `?'")
+(copy-face (if promela-xemacsp 'modeline 'region)
+ 'promela-fl-send-poll-face)
+
+;; some emacs-en don't define or have regexp-opt available.
+(unless (functionp 'regexp-opt)
+ (defmacro regexp-opt (strings)
+ "Cheap imitation of `regexp-opt' since it's not availble in this emacs"
+ `(mapconcat 'identity ,strings "\\|")))
+
+
+;; -------------------------------------------------------------------------
+;; promela-mode font lock specifications/regular-expressions
+;; - for help, look at definition of variable 'font-lock-keywords
+;; - some fontification ideas from -- [engstrom:20010309.1435CST]
+;; Pat Tullman (tullmann@cs.utah.edu) and
+;; Ny Aina Razermera Mamy (ainarazr@cs.uoregon.edu)
+;; both had promela-mode's that I discovered after starting this one...
+;; (but neither did any sort of indentation ;-)
+
+(defconst promela-font-lock-keywords-1 nil
+ "Subdued level highlighting for Promela mode.")
+
+(defconst promela-font-lock-keywords-2 nil
+ "Medium level highlighting for Promela mode.")
+
+(defconst promela-font-lock-keywords-3 nil
+ "Gaudy level highlighting for Promela mode.")
+
+;; set each of those three variables now..
+(let ((promela-keywords
+ (eval-when-compile
+ (regexp-opt
+ '("active" "assert" "atomic" "break" "d_step"
+ "do" "dproctype" "else" "empty" "enabled"
+ "eval" "fi" "full" "goto" "hidden" "if" "init"
+ "inline" "len" "local" "mtype" "nempty" "never"
+ "nfull" "od" "of" "pcvalue" "printf" "priority"
+ "proctype" "provided" "run" "show" "skip"
+ "timeout" "trace" "typedef" "unless" "xr" "xs"))))
+ (promela-types
+ (eval-when-compile
+ (regexp-opt '("bit" "bool" "byte" "short"
+ "int" "unsigned" "chan")))))
+
+ ;; really simple fontification (strings and comments come for "free")
+ (setq promela-font-lock-keywords-1
+ (list
+ ;; Keywords:
+ (cons (concat "\\<\\(" promela-keywords "\\)\\>")
+ 'font-lock-keyword-face)
+ ;; Types:
+ (cons (concat "\\<\\(" promela-types "\\)\\>")
+ 'font-lock-type-face)
+ ;; Special constants:
+ '("\\<_\\(np\\|pid\\|last\\)\\>" . font-lock-reference-face)))
+
+ ;; more complex fontification
+ ;; add function (proctype) names, lables and goto statements
+ ;; also add send/receive/poll fontification
+ (setq promela-font-lock-keywords-2
+ (append promela-font-lock-keywords-1
+ (list
+ ;; ANY Pre-Processor directive (lazy method: any line beginning with "#[a-z]+")
+ '("^\\(#[ \t]*[a-z]+\\)" 1 'font-lock-preprocessor-face t)
+
+ ;; "Functions" (proctype-s and inline-s)
+ (list (concat "\\<\\("
+ (eval-when-compile
+ (regexp-opt '("run" "dproctype" "proctype" "inline")))
+ "\\)\\>[ \t]*\\(\\sw+\\)?")
+ ;;'(1 'font-lock-keyword-face nil)
+ '(2 'font-lock-function-name-face nil t))
+
+ ;; Labels and GOTO labels
+ '("^\\(\\sw+\\):" 1 'font-lock-reference-face)
+ '("\\<\\(goto\\)\\>[ \t]+\\(\\sw+\\)"
+ ;;(1 'font-lock-keyword-face nil)
+ (2 'font-lock-reference-face nil t))
+
+ ;; Send, Receive and Poll
+ '("\\(\\sw+\\)\\(\\[[^\\?!]+\\]\\)?\\(\\??\\?\\|!?!\\)\\(\\sw+\\)"
+ (1 'font-lock-variable-name-face nil t)
+ (3 'promela-fl-send-poll-face nil t)
+ (4 'font-lock-reference-face nil t)
+ )
+ )))
+
+ ;; most complex fontification
+ ;; add pre-processor directives, typed variables and hidden/typedef decls.
+ (setq promela-font-lock-keywords-3
+ (append promela-font-lock-keywords-2
+ (list
+ ;; ANY Pre-Processor directive (lazy method: any line beginning with "#[a-z]+")
+ ;;'("^\\(#[ \t]*[a-z]+\\)" 1 'font-lock-preprocessor-face t)
+ ;; "defined" in an #if or #elif and associated macro names
+ '("^#[ \t]*\\(el\\)?if\\>"
+ ("\\<\\(defined\\)\\>[ \t]*(?\\(\\sw+\\)" nil nil
+ (1 'font-lock-preprocessor-face nil t)
+ (2 'font-lock-reference-face nil t)))
+ '("^#[ \t]*ifn?def\\>"
+ ("[ \t]*\\(\\sw+\\)" nil nil
+ (1 'font-lock-reference-face nil t)))
+ ;; Filenames in #include <...> directives
+ '("^#[ \t]*include[ \t]+<\\([^>\"\n]+\\)>" 1 'font-lock-string-face nil t)
+ ;; Defined functions and constants/types (non-functions)
+ '("^#[ \t]*define[ \t]+"
+ ("\\(\\sw+\\)(" nil nil (1 'font-lock-function-name-face nil t))
+ ("\\(\\sw+\\)[ \t]+\\(\\sw+\\)" nil nil (1 'font-lock-variable-name-face)
+ (2 'font-lock-reference-face nil t))
+ ("\\(\\sw+\\)[^(]?" nil nil (1 'font-lock-reference-face nil t)))
+
+ ;; Types AND variables
+ ;; - room for improvement: (i.e. don't currently):
+ ;; highlight user-defined types and asociated variable declarations
+ (list (concat "\\<\\(" promela-types "\\)\\>")
+ ;;'(1 'font-lock-type-face)
+ ;; now match the variables after the type definition, if any
+ '(promela-match-variable-or-declaration
+ nil nil
+ (1 'font-lock-variable-name-face) ;; nil t)
+ (2 font-lock-reference-face nil t)))
+
+ ;; Typedef/hidden types and declarations
+ '("\\<\\(typedef\\|hidden\\)\\>[ \t]*\\(\\sw+\\)?"
+ ;;(1 'font-lock-keyword-face nil)
+ (2 'font-lock-type-face nil t)
+ ;; now match the variables after the type definition, if any
+ (promela-match-variable-or-declaration
+ nil nil
+ (1 'font-lock-variable-name-face nil t)
+ (2 'font-lock-reference-face nil t)))
+ )))
+ )
+
+(defvar promela-font-lock-keywords promela-font-lock-keywords-1
+ "Default expressions to highlight in Promela mode.")
+
+;; Font-lock matcher functions:
+(defun promela-match-variable-or-declaration (limit)
+ "Match, and move over, any declaration/definition item after point.
+Matches after point, but ignores leading whitespace characters.
+Does not move further than LIMIT.
+
+The expected syntax of a declaration/definition item is `word' (preceded
+by optional whitespace) optionally followed by a `= value' (preceded and
+followed by more optional whitespace)
+
+Thus the regexp matches after point: word [ = value ]
+ ^^^^ ^^^^^
+Where the match subexpressions are: 1 2
+
+The item is delimited by (match-beginning 1) and (match-end 1).
+If (match-beginning 2) is non-nil, the item is followed by a `value'."
+ (when (looking-at "[ \t]*\\(\\sw+\\)[ \t]*=?[ \t]*\\(\\sw+\\)?[ \t]*,?")
+ (goto-char (min limit (match-end 0)))))
+
+
+;; -------------------------------------------------------------------------
+;; "install" promela-mode font lock specifications
+
+;; FMI: look up 'font-lock-defaults
+(defconst promela-font-lock-defaults
+ '(
+ (promela-font-lock-keywords
+ promela-font-lock-keywords-1
+ promela-font-lock-keywords-2
+ promela-font-lock-keywords-3) ;; font-lock stuff (keywords)
+ nil ;; keywords-only flag
+ nil ;; case-fold keyword searching
+ ;;((?_ . "w") (?$ . ".")) ;; mods to syntax table
+ nil ;; mods to syntax table (see below)
+ nil ;; syntax-begin
+ (font-lock-mark-block-function . mark-defun))
+)
+
+;; "install" the font-lock-defaults based upon version of emacs we have
+(cond (promela-xemacsp
+ (put 'promela-mode 'font-lock-defaults promela-font-lock-defaults))
+ ((not (assq 'promela-mode font-lock-defaults-alist))
+ (setq font-lock-defaults-alist
+ (cons
+ (cons 'promela-mode promela-font-lock-defaults)
+ font-lock-defaults-alist))))
+
+
+;; -------------------------------------------------------------------------
+;; other promela-mode specific definitions
+
+(defconst promela-defun-prompt-regexp
+ "^[ \t]*\\(\\(active \\)?d?proctype\\|init\\|inline\\|never\\|trace\\|typedef\\|mtype\\s-+=\\)[ \t][^{]*"
+ "Regexp describing the beginning of a Promela top-level definition.")
+
+(defvar promela-mode-syntax-table nil
+ "Syntax table in use in PROMELA-mode buffers.")
+(if promela-mode-syntax-table
+ ()
+ (setq promela-mode-syntax-table (make-syntax-table))
+ (modify-syntax-entry ?\\ "\\" promela-mode-syntax-table)
+ (modify-syntax-entry ?/ ". 14" promela-mode-syntax-table)
+ (modify-syntax-entry ?* ". 23" promela-mode-syntax-table)
+ (modify-syntax-entry ?+ "." promela-mode-syntax-table)
+ (modify-syntax-entry ?- "." promela-mode-syntax-table)
+ (modify-syntax-entry ?= "." promela-mode-syntax-table)
+ (modify-syntax-entry ?% "." promela-mode-syntax-table)
+ (modify-syntax-entry ?< "." promela-mode-syntax-table)
+ (modify-syntax-entry ?> "." promela-mode-syntax-table)
+ (modify-syntax-entry ?& "." promela-mode-syntax-table)
+ (modify-syntax-entry ?| "." promela-mode-syntax-table)
+ (modify-syntax-entry ?. "_" promela-mode-syntax-table)
+ (modify-syntax-entry ?_ "w" promela-mode-syntax-table)
+ (modify-syntax-entry ?\' "\"" promela-mode-syntax-table)
+ )
+
+(defvar promela-mode-abbrev-table nil
+ "*Abbrev table in use in promela-mode buffers.")
+(if promela-mode-abbrev-table
+ nil
+ (define-abbrev-table 'promela-mode-abbrev-table
+ '(
+;; Commented out for now - need to think about what abbrevs make sense
+;; ("assert" "ASSERT" promela-check-expansion 0)
+;; ("d_step" "D_STEP" promela-check-expansion 0)
+;; ("break" "BREAK" promela-check-expansion 0)
+;; ("do" "DO" promela-check-expansion 0)
+;; ("proctype" "PROCTYPE" promela-check-expansion 0)
+ )))
+
+(defvar promela-mode-map nil
+ "Keymap for promela-mode.")
+(if promela-mode-map
+ nil
+ (setq promela-mode-map (make-sparse-keymap))
+ (define-key promela-mode-map "\t" 'promela-indent-command)
+ (define-key promela-mode-map "\C-m" 'promela-newline-and-indent)
+ ;(define-key promela-mode-map 'backspace 'backward-delete-char-untabify)
+ (define-key promela-mode-map "\C-c\C-p" 'promela-beginning-of-block)
+ ;(define-key promela-mode-map "\C-c\C-n" 'promela-end-of-block)
+ (define-key promela-mode-map "\M-\C-a" 'promela-beginning-of-defun)
+ ;(define-key promela-mode-map "\M-\C-e" 'promela-end-of-defun)
+ (define-key promela-mode-map "\C-c(" 'promela-toggle-auto-match-delimiter)
+ (define-key promela-mode-map "{" 'promela-open-delimiter)
+ (define-key promela-mode-map "}" 'promela-close-delimiter)
+ (define-key promela-mode-map "(" 'promela-open-delimiter)
+ (define-key promela-mode-map ")" 'promela-close-delimiter)
+ (define-key promela-mode-map "[" 'promela-open-delimiter)
+ (define-key promela-mode-map "]" 'promela-close-delimiter)
+ (define-key promela-mode-map ";" 'promela-insert-and-indent)
+ (define-key promela-mode-map ":" 'promela-insert-and-indent)
+ ;;
+ ;; this is preliminary at best - use at your own risk:
+ (define-key promela-mode-map "\C-c\C-s" 'promela-syntax-check)
+ ;;
+ ;;(define-key promela-mode-map "\C-c\C-d" 'promela-mode-toggle-debug)
+ ;;(define-key promela-mode-map "\C-c\C-r" 'promela-mode-revert-buffer)
+ )
+
+(defvar promela-matching-delimiter-alist
+ '( (?( . ?))
+ (?[ . ?])
+ (?{ . "\n}")
+ ;(?< . ?>)
+ (?\' . ?\')
+ (?\` . ?\`)
+ (?\" . ?\") )
+ "List of pairs of matching open/close delimiters - for auto-insert")
+
+
+;; -------------------------------------------------------------------------
+;; Promela-mode itself
+
+(defun promela-mode ()
+ "Major mode for editing PROMELA code.
+\\{promela-mode-map}
+
+Variables controlling indentation style:
+ promela-block-indent
+ Relative offset of lines within a block (`{') construct.
+
+ promela-selection-indent
+ Relative offset of option lines within a selection (`if')
+ or iteration (`do') construct.
+
+ promela-selection-option-indent
+ Relative offset of lines after/within options (`::') within
+ selection or iteration constructs.
+
+ promela-comment-col
+ Defines the desired comment column for comments to the right of text.
+
+ promela-tab-always-indent
+ Non-nil means TAB in PROMELA mode should always reindent the current
+ line, regardless of where in the line the point is when the TAB
+ command is used.
+
+ promela-auto-match-delimiter
+ Non-nil means typing an open-delimiter (i.e. parentheses, brace,
+ quote, etc) should also insert the matching closing delmiter
+ character.
+
+Turning on PROMELA mode calls the value of the variable promela-mode-hook with
+no args, if that value is non-nil.
+
+For example: '
+ (setq promela-mode-hook '(lambda ()
+ (setq promela-block-indent 2)
+ (setq promela-selection-indent 0)
+ (setq promela-selection-option-indent 2)
+ (local-set-key \"\\C-m\" 'promela-indent-newline-indent)
+ ))'
+
+will indent block two steps, will make selection options aligned with DO/IF
+and sub-option lines indent to a column after the `::'. Also, lines will
+be reindented when you hit RETURN.
+
+Note that promela-mode adhears to the font-lock \"standards\" and
+defines several \"levels\" of fontification or colorization. The
+default is fairly gaudy, so if you would prefer a bit less, please see
+the documentation for the variable: `font-lock-maximum-decoration'.
+"
+ (interactive)
+ (kill-all-local-variables)
+ (setq mode-name "Promela")
+ (setq major-mode 'promela-mode)
+ (use-local-map promela-mode-map)
+ (set-syntax-table promela-mode-syntax-table)
+ (setq local-abbrev-table promela-mode-abbrev-table)
+
+ ;; Make local variables
+ (make-local-variable 'case-fold-search)
+ (make-local-variable 'paragraph-start)
+ (make-local-variable 'paragraph-separate)
+ (make-local-variable 'paragraph-ignore-fill-prefix)
+ (make-local-variable 'indent-line-function)
+ (make-local-variable 'indent-region-function)
+ (make-local-variable 'parse-sexp-ignore-comments)
+ (make-local-variable 'comment-start)
+ (make-local-variable 'comment-end)
+ (make-local-variable 'comment-column)
+ (make-local-variable 'comment-start-skip)
+ (make-local-variable 'comment-indent-hook)
+ (make-local-variable 'defun-prompt-regexp)
+ (make-local-variable 'compile-command)
+ ;; Now set their values
+ (setq case-fold-search t
+ paragraph-start (concat "^$\\|" page-delimiter)
+ paragraph-separate paragraph-start
+ paragraph-ignore-fill-prefix t
+ indent-line-function 'promela-indent-command
+ ;;indent-region-function 'promela-indent-region
+ parse-sexp-ignore-comments t
+ comment-start "/* "
+ comment-end " */"
+ comment-column 32
+ comment-start-skip "/\\*+ *"
+ ;;comment-start-skip "/\\*+ *\\|// *"
+ ;;comment-indent-hook 'promela-comment-indent
+ defun-prompt-regexp promela-defun-prompt-regexp
+ )
+
+ ;; Turn on font-lock mode
+ ;; (and promela-font-lock-mode (font-lock-mode))
+ (font-lock-mode)
+
+ ;; Finally, run the hooks and be done.
+ (run-hooks 'promela-mode-hook))
+
+
+;; -------------------------------------------------------------------------
+;; Interactive functions
+;;
+
+(defun promela-mode-version ()
+ "Print the current version of promela-mode in the minibuffer"
+ (interactive)
+ (message (concat "Promela-Mode: " promela-mode-version)))
+
+(defun promela-beginning-of-block ()
+ "Move backward to start of containing block.
+Containing block may be `{', `do' or `if' construct, or comment."
+ (interactive)
+ (goto-char (promela-find-start-of-containing-block-or-comment)))
+
+(defun promela-beginning-of-defun (&optional arg)
+ "Move backward to the beginning of a defun.
+With argument, do it that many times.
+Negative arg -N means move forward to Nth following beginning of defun.
+Returns t unless search stops due to beginning or end of buffer.
+
+See also 'beginning-of-defun.
+
+This is a Promela-mode specific version since default (in xemacs 19.16 and
+NT-Emacs 20) don't seem to skip comments - they will stop inside them.
+
+Also, this makes sure that the beginning of the defun is actually the
+line which starts the proctype/init/etc., not just the open-brace."
+ (interactive "p")
+ (beginning-of-defun arg)
+ (if (not (looking-at promela-defun-prompt-regexp))
+ (re-search-backward promela-defun-prompt-regexp nil t))
+ (if (promela-inside-comment-p)
+ (goto-char (promela-find-start-of-containing-comment))))
+
+(defun promela-indent-command ()
+ "Indent the current line as PROMELA code."
+ (interactive)
+ (if (and (not promela-tab-always-indent)
+ (save-excursion
+ (skip-chars-backward " \t")
+ (not (bolp))))
+ (tab-to-tab-stop)
+ (promela-indent-line)))
+
+(defun promela-newline-and-indent ()
+ "Promela-mode specific newline-and-indent which expands abbrevs before
+running a regular newline-and-indent."
+ (interactive)
+ (if abbrev-mode
+ (expand-abbrev))
+ (newline-and-indent))
+
+(defun promela-indent-newline-indent ()
+ "Promela-mode specific newline-and-indent which expands abbrevs and
+indents the current line before running a regular newline-and-indent."
+ (interactive)
+ (save-excursion (promela-indent-command))
+ (if abbrev-mode
+ (expand-abbrev))
+ (newline-and-indent))
+
+(defun promela-insert-and-indent ()
+ "Insert the last character typed and re-indent the current line"
+ (interactive)
+ (insert last-command-char)
+ (save-excursion (promela-indent-command)))
+
+(defun promela-open-delimiter ()
+ "Inserts the open and matching close delimiters, indenting as appropriate."
+ (interactive)
+ (insert last-command-char)
+ (if (and promela-auto-match-delimiter (not (promela-inside-comment-p)))
+ (save-excursion
+ (insert (cdr (assq last-command-char promela-matching-delimiter-alist)))
+ (promela-indent-command))))
+
+(defun promela-close-delimiter ()
+ "Inserts and indents a close delimiter."
+ (interactive)
+ (insert last-command-char)
+ (if (not (promela-inside-comment-p))
+ (save-excursion (promela-indent-command))))
+
+(defun promela-toggle-auto-match-delimiter ()
+ "Toggle auto-insertion of parens and other delimiters.
+See variable `promela-auto-insert-matching-delimiter'"
+ (interactive)
+ (setq promela-auto-match-delimiter
+ (not promela-auto-match-delimiter))
+ (message (concat "Promela auto-insert matching delimiters "
+ (if promela-auto-match-delimiter
+ "enabled" "disabled"))))
+
+
+;; -------------------------------------------------------------------------
+;; Compilation/Verification functions
+
+;; all of this is in serious "beta" mode - don't trust it ;-)
+(setq
+ promela-compile-command "spin "
+ promela-syntax-check-args "-a -v "
+)
+
+;;(setq compilation-error-regexp-alist
+;; (append compilation-error-regexp-alist
+;; '(("spin: +line +\\([0-9]+\\) +\"\\([^\"]+\\)\"" 2 1))))
+
+(defun promela-syntax-check ()
+ (interactive)
+ (compile (concat promela-compile-command
+ promela-syntax-check-args
+ (buffer-name))))
+
+
+;; -------------------------------------------------------------------------
+;; Indentation support functions
+
+(defun promela-indent-around-label ()
+ "Indent the current line as PROMELA code,
+but make sure to consider the label at the beginning of the line."
+ (beginning-of-line)
+ (delete-horizontal-space) ; delete any leading whitespace
+ (if (not (looking-at "\\sw+:\\([ \t]*\\)"))
+ (error "promela-indent-around-label: no label on this line")
+ (goto-char (match-beginning 1))
+ (let* ((space (length (match-string 1)))
+ (indent (promela-calc-indent))
+ (wanted (max 0 (- indent (current-column)))))
+ (if (>= space wanted)
+ (delete-region (point) (+ (point) (- space wanted)))
+ (goto-char (+ (point) space))
+ (indent-to-column indent)))))
+
+;; Note that indentation is based ENTIRELY upon the indentation of the
+;; previous line(s), esp. the previous non-blank line and the line
+;; starting the current containgng block...
+(defun promela-indent-line ()
+ "Indent the current line as PROMELA code.
+Return the amount the by which the indentation changed."
+ (beginning-of-line)
+ (if (looking-at "[ \t]*\\sw+:")
+ (promela-indent-around-label)
+ (let ((indent (promela-calc-indent))
+ beg
+ shift-amt
+ (pos (- (point-max) (point))))
+ (setq beg (point))
+ (skip-chars-forward " \t")
+ (setq shift-amt (- indent (current-column)))
+ (if (zerop shift-amt)
+ (if (> (- (point-max) pos) (point))
+ (goto-char (- (point-max) pos)))
+ (delete-region beg (point))
+ (indent-to indent)
+ (if (> (- (point-max) pos) (point))
+ (goto-char (- (point-max) pos))))
+ shift-amt)))
+
+(defun promela-calc-indent ()
+ "Return the appropriate indentation for this line as an int."
+ (save-excursion
+ (beginning-of-line)
+ (let* ((orig-point (point))
+ (state (promela-parse-partial-sexp))
+ (paren-depth (nth 0 state))
+ (paren-point (or (nth 1 state) 1))
+ (paren-char (char-after paren-point)))
+ ;;(what-cursor-position)
+ (cond
+ ;; Indent not-at-all - inside a string
+ ((nth 3 state)
+ (current-indentation))
+ ;; Indent inside a comment
+ ((nth 4 state)
+ (promela-calc-indent-within-comment))
+ ;; looking at a pre-processor directive - indent=0
+ ((looking-at "[ \t]*#\\(define\\|if\\(n?def\\)?\\|else\\|endif\\)")
+ 0)
+ ;; If we're not inside a "true" block (i.e. "{}"), then indent=0
+ ;; I think this is fair, since no (indentable) code in promela
+ ;; exists outside of a proctype or similar "{ .. }" structure.
+ ((zerop paren-depth)
+ 0)
+ ;; Indent relative to non curly-brace "paren"
+ ;; [ NOTE: I'm saving this, but don't use it any more.
+ ;; Now, we let parens be indented like curly braces
+ ;;((and (>= paren-depth 1) (not (char-equal ?\{ paren-char)))
+ ;; (goto-char paren-point)
+ ;; (1+ (current-column)))
+ ;;
+ ;; Last option: indent relative to contaning block(s)
+ (t
+ (goto-char orig-point)
+ (promela-calc-indent-within-block paren-point))))))
+
+(defun promela-calc-indent-within-block (&optional limit)
+ "Return the appropriate indentation for this line, assume within block.
+with optional arg, limit search back to `limit'"
+ (save-excursion
+ (let* ((stop (or limit 1))
+ (block-point (promela-find-start-of-containing-block stop))
+ (block-type (promela-block-type-after block-point))
+ (indent-point (point))
+ (indent-type (promela-block-type-after indent-point)))
+ (if (not block-type) 0
+ ;;(message "paren: %d (%d); block: %s (%d); indent: %s (%d); stop: %d"
+ ;; paren-depth paren-point block-type block-point
+ ;; indent-type indent-point stop)
+ (goto-char block-point)
+ (cond
+ ;; Indent (options) inside "if" or "do"
+ ((memq block-type '(selection iteration))
+ (if (re-search-forward "\\(do\\|if\\)[ \t]*::" indent-point t)
+ (- (current-column) 2)
+ (+ (current-column) promela-selection-indent)))
+ ;; indent (generic code) inside "::" option
+ ((eq 'option block-type)
+ (if (and (not indent-type)
+ (re-search-forward "::.*->[ \t]*\\sw"
+ (save-excursion (end-of-line) (point))
+ t))
+ (1- (current-column))
+ (+ (current-column) promela-selection-option-indent))
+ )
+ ;; indent code inside "{"
+ ((eq 'block block-type)
+ (cond
+ ;; if we are indenting the end of a block,
+ ;; use indentation of start-of-block
+ ((equal 'block-end indent-type)
+ (current-indentation))
+ ;; if the start of the code inside the block is not at eol
+ ;; then indent to the same column as the block start +some
+ ;; [ but ignore comments after "{" ]
+ ((and (not (promela-effective-eolp (1+ (point))))
+ (not (looking-at "{[ \t]*/\\*")))
+ (forward-char) ; skip block-start
+ (skip-chars-forward "{ \t") ; skip whitespace, if any
+ (current-column))
+ ;; anything else we indent +promela-block-indent from
+ ;; the indentation of the start of block (where we are now)
+ (t
+ (+ (current-indentation)
+ promela-block-indent))))
+ ;; dunno what kind of block this is - sound an error
+ (t
+ (error "promela-calc-indent-within-block: unknown block type: %s" block-type)
+ (current-indentation)))))))
+
+(defun promela-calc-indent-within-comment ()
+ "Return the indentation amount for line, assuming that the
+current line is to be regarded as part of a block comment."
+ (save-excursion
+ (beginning-of-line)
+ (skip-chars-forward " \t")
+ (let ((indenting-end-of-comment (looking-at "\\*/"))
+ (indenting-blank-line (eolp)))
+ ;; if line is NOT blank and next char is NOT a "*'
+ (if (not (or indenting-blank-line (= (following-char) ?\*)))
+ ;; leave indent alone
+ (current-column)
+ ;; otherwise look back for _PREVIOUS_ possible nested comment start
+ (let ((comment-start (save-excursion
+ (re-search-backward comment-start-skip))))
+ ;; and see if there is an appropriate middle-comment "*"
+ (if (re-search-backward "^[ \t]+\\*" comment-start t)
+ (current-indentation)
+ ;; guess not, so indent relative to comment start
+ (goto-char comment-start)
+ (if indenting-end-of-comment
+ (current-column)
+ (1+ (current-column)))))))))
+
+
+;; -------------------------------------------------------------------------
+;; Misc other support functions
+
+(defun promela-parse-partial-sexp (&optional start limit)
+ "Return the partial parse state of current defun or from optional start
+to end limit"
+ (save-excursion
+ (let ((end (or limit (point))))
+ (if start
+ (goto-char start)
+ (promela-beginning-of-defun))
+ (parse-partial-sexp (point) end))))
+
+;;(defun promela-at-end-of-block-p ()
+;; "Return t if cursor is at the end of a promela block"
+;; (save-excursion
+;; (let ((eol (progn (end-of-line) (point))))
+;; (beginning-of-line)
+;; (skip-chars-forward " \t")
+;; ;;(re-search-forward "\\(}\\|\\b\\(od\\|fi\\)\\b\\)" eol t))))
+;; (looking-at "[ \t]*\\(od\\|fi\\)\\b"))))
+
+(defun promela-inside-comment-p ()
+ "Check if the point is inside a comment block."
+ (save-excursion
+ (let ((origpoint (point))
+ state)
+ (goto-char 1)
+ (while (> origpoint (point))
+ (setq state (parse-partial-sexp (point) origpoint 0)))
+ (nth 4 state))))
+
+(defun promela-inside-comment-or-string-p ()
+ "Check if the point is inside a comment or a string."
+ (save-excursion
+ (let ((origpoint (point))
+ state)
+ (goto-char 1)
+ (while (> origpoint (point))
+ (setq state (parse-partial-sexp (point) origpoint 0)))
+ (or (nth 3 state) (nth 4 state)))))
+
+
+(defun promela-effective-eolp (&optional point)
+ "Check if we are at the effective end-of-line, ignoring whitespace"
+ (save-excursion
+ (if point (goto-char point))
+ (skip-chars-forward " \t")
+ (eolp)))
+
+(defun promela-check-expansion ()
+ "If abbrev was made within a comment or a string, de-abbrev!"
+ (if promela-inside-comment-or-string-p
+ (unexpand-abbrev)))
+
+(defun promela-block-type-after (&optional point)
+ "Return the type of block after current point or parameter as a symbol.
+Return one of 'iteration `do', 'selection `if', 'option `::',
+'block `{' or `}' or nil if none of the above match."
+ (save-excursion
+ (goto-char (or point (point)))
+ (skip-chars-forward " \t")
+ (cond
+ ((looking-at "do\\b") 'iteration)
+ ;;((looking-at "od\\b") 'iteration-end)
+ ((looking-at "if\\b") 'selection)
+ ;;((looking-at "fi\\b") 'selection-end)
+ ((looking-at "::") 'option)
+ ((looking-at "[{(]") 'block)
+ ((looking-at "[})]") 'block-end)
+ (t nil))))
+
+(defun promela-find-start-of-containing-comment (&optional limit)
+ "Return the start point of the containing comment block.
+Stop at `limit' or beginning of buffer."
+ (let ((stop (or limit 1)))
+ (save-excursion
+ (while (and (>= (point) stop)
+ (nth 4 (promela-parse-partial-sexp)))
+ (re-search-backward comment-start-skip stop t))
+ (point))))
+
+(defun promela-find-start-of-containing-block (&optional limit)
+ "Return the start point of the containing `do', `if', `::' or
+`{' block or containing comment.
+Stop at `limit' or beginning of buffer."
+ (save-excursion
+ (skip-chars-forward " \t")
+ (let* ((type (promela-block-type-after))
+ (stop (or limit
+ (save-excursion (promela-beginning-of-defun) (point))))
+ (state (promela-parse-partial-sexp stop))
+ (level (if (looking-at "\\(od\\|fi\\)\\b")
+ 2
+ (if (zerop (nth 0 state)) 0 1))))
+ ;;(message "find-start-of-containing-block: type: %s; level %d; stop %d"
+ ;; type level stop)
+ (while (and (> (point) stop) (not (zerop level)))
+ (re-search-backward
+ "\\({\\|}\\|::\\|\\b\\(do\\|od\\|if\\|fi\\)\\b\\)"
+ stop 'move)
+ ;;(message "looking from %d back-to %d" (point) stop)
+ (setq state (promela-parse-partial-sexp stop))
+ (setq level (+ level
+ (cond ((or (nth 3 state) (nth 4 state)) 0)
+ ((and (= 1 level) (looking-at "::")
+ (not (equal type 'option))) -1)
+ ((looking-at "\\({\\|\\(do\\|if\\)\\b\\)") -1)
+ ((looking-at "\\(}\\|\\(od\\|fi\\)\\b\\)") +1)
+ (t 0)))))
+ (point))))
+
+(defun promela-find-start-of-containing-block-or-comment (&optional limit)
+ "Return the start point of the containing comment or
+the start of the containing `do', `if', `::' or `{' block.
+Stop at limit or beginning of buffer."
+ (if (promela-inside-comment-p)
+ (promela-find-start-of-containing-comment limit)
+ (promela-find-start-of-containing-block limit)))
+
+;; -------------------------------------------------------------------------
+;; Debugging/testing
+
+;; (defun promela-mode-toggle-debug ()
+;; (interactive)
+;; (make-local-variable 'debug-on-error)
+;; (setq debug-on-error (not debug-on-error)))
+
+;;(defun promela-mode-revert-buffer ()
+;; (interactive)
+;; (revert-buffer t t))
+
+;; -------------------------------------------------------------------------
+;;###autoload
+
+(provide 'promela-mode)
+
+
+;;----------------------------------------------------------------------
+;; Change History:
+;;
+;; $Log: promela-mode.el,v $
+;; Revision 1.11 2001/07/09 18:36:45 engstrom
+;; - added comments on use of font-lock-maximum-decoration
+;; - moved basic preprocess directive fontification to "level 2"
+;;
+;; Revision 1.10 2001/05/22 16:29:59 engstrom
+;; - fixed error introduced in fontification levels stuff (xemacs only)
+;;
+;; Revision 1.9 2001/05/22 16:21:29 engstrom
+;; - commented out the compilation / syntax check stuff for now
+;;
+;; Revision 1.8 2001/05/22 16:18:49 engstrom
+;; - Munched history in preparation for first non-Honeywell release
+;; - Added "levels" of fontification to be controlled by the std. variable:
+;; 'font-lock-maximum-decoration'
+;;
+;; Revision 1.7 2001/04/20 01:41:46 engstrom
+;; Revision 1.6 2001/04/06 23:57:18 engstrom
+;; Revision 1.5 2001/04/04 20:04:15 engstrom
+;; Revision 1.4 2001/03/15 02:22:18 engstrom
+;; Revision 1.3 2001/03/09 19:39:51 engstrom
+;; Revision 1.2 2001/03/01 18:07:47 engstrom
+;; Revision 1.1 2001/02/01 xx:xx:xx engstrom
+;; migrated to CVS versioning...
+;; Pre-CVS-History:
+;; 99-10-04 V0.4 EDE Fixed bug in end-of-block indentation
+;; Simplified indentation code significantly
+;; 99-09-2x V0.3 EDE Hacked on indentation more while at FM'99
+;; 99-09-16 V0.2 EDE Hacked, hacked, hacked on indentation
+;; 99-04-01 V0.1 EDE Introduced (less-than) half-baked indentation
+;; 98-11-05 V0.0 EDE Created - much code stolen from rexx-mode.el
+;; Mostly just a fontification mode -
+;; (indentation is HARD ;-)
+;;
+;; EOF promela-mode.el
diff --git a/lisp/template.el b/lisp/template.el
new file mode 100644
index 0000000..ea36c4b
--- /dev/null
+++ b/lisp/template.el
@@ -0,0 +1,2609 @@
+;;; template.el --- use templates, decorate comments, auto-update buffers
+
+;; Copyright (C) 1995-2003 Free Software Foundation, Inc.
+;;
+;; Author: Christoph Wedler <wedler@users.sourceforge.net>
+;; Version: (see `template-version' below)
+;; Keywords: template, comment decoration, auto-updating, data, tools
+;; X-URL: http://emacs-template.sourceforge.net/
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, write to the Free Software
+;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; When you create a new file with Emacs, package Template supplies an initial
+;; buffer content via a template: a file with normal text and expansion
+;; forms. There is a menu to easily create such templates. You can also use new
+;; commands to decorate comments and update the buffer contents.
+
+;; The main difference between Template and other similar packages is that you
+;; can define very flexible templates without having to learn Lisp or changing
+;; your Emacs init file. This package does not help Lisp programmers to define
+;; complex macros.
+
+;; For details, check <http://emacs-template.sourceforge.net/> or, if you
+;; prefer the manual style, the documentation of the following commands and
+;; variables:
+;;
+;; * for templates: \\[template-new-file], `template-auto-insert',
+;; `template-derivation-alist', `template-default-expansion-alist' and
+;; `template-definition-start',
+;; * for comment decoration: \\[template-single-comment] and
+;; \\[template-block-comment], `template-comment-specification-alist'
+;; * for updating: \\[template-update-buffer], `template-auto-update',
+;; `template-update-buffer-alist' and `template-header-regexp-alist'.
+
+;; Bug fixes, bug reports, improvements, and suggestions for the newest version
+;; are strongly appreciated.
+
+;;; Installation:
+
+;; This file requires Emacs-20.2, XEmacs-20.2 or higher.
+
+;; Put this file into your load-path and the following into your ~/.emacs:
+;; (require 'template)
+;; (template-initialize)
+
+;; You might want to add another item to the "File" menu by (in XEmacs):
+;; (add-menu-button '("File")
+;; ["Insert and Expand Template..."
+;; template-expand-template
+;; :active (not buffer-read-only)]
+;; "Insert File...")
+
+;; To customize, use `M-x customize-group RET template RET' or the customize
+;; entry in menu Options.
+
+;;; Code:
+
+(provide 'template)
+(require 'custom)
+
+;; General Emacs/XEmacs-compatibility compile-time macros
+(eval-when-compile
+ (require 'cl)
+ (defmacro cond-emacs-xemacs (&rest args)
+ (cond-emacs-xemacs-macfn
+ args "`cond-emacs-xemacs' must return exactly one element"))
+ (defun cond-emacs-xemacs-macfn (args &optional msg)
+ (if (atom args) args
+ (and (eq (car args) :@) (null msg) ; (:@ ...spliced...)
+ (setq args (cdr args)
+ msg "(:@ ....) must return exactly one element"))
+ (let ((ignore (if (string-match "XEmacs" emacs-version) :EMACS :XEMACS))
+ (mode :BOTH) code)
+ (while (consp args)
+ (if (memq (car args) '(:EMACS :XEMACS :BOTH)) (setq mode (pop args)))
+ (if (atom args)
+ (or args (error "Used selector %s without elements" mode))
+ (or (eq ignore mode)
+ (push (cond-emacs-xemacs-macfn (car args)) code))
+ (pop args)))
+ (cond (msg (if (or args (cdr code)) (error msg) (car code)))
+ ((or (null args) (eq ignore mode)) (nreverse code))
+ (t (nconc (nreverse code) args))))))
+ ;; Emacs/XEmacs-compatibility `defun': remove interactive "_" for Emacs, use
+ ;; existing functions when they are `fboundp', provide shortcuts if they are
+ ;; known to be defined in a specific Emacs branch (for short .elc)
+ (defmacro defunx (name arglist &rest definition)
+ (let ((xemacsp (string-match "XEmacs" emacs-version)) reuses first)
+ (while (memq (setq first (car definition))
+ '(:try :emacs-and-try :xemacs-and-try
+ :emacs-only :xemacs-only))
+ (if (memq first (if xemacsp
+ '(:xemacs-and-try :xemacs-only)
+ '(:emacs-and-try :emacs-only)))
+ (setq reuses (cadr definition)
+ definition nil)
+ (unless (memq first '(:emacs-only :xemacs-only))
+ (push (cadr definition) reuses)))
+ (setq definition (cddr definition)))
+ (if (and reuses (symbolp reuses))
+ `(defalias ',name ',reuses)
+ (let* ((docstring (if (stringp (car definition)) (pop definition)))
+ (spec (and (not xemacsp)
+ (eq (car-safe (car definition)) 'interactive)
+ (null (cddar definition))
+ (cadar definition))))
+ (if (and (stringp spec)
+ (not (string-equal spec ""))
+ (eq (aref spec 0) ?_))
+ (setq definition
+ (cons (if (string-equal spec "_")
+ '(interactive)
+ `(interactive ,(substring spec 1)))
+ (cdr definition))))
+ (if (null reuses)
+ `(defun ,name ,arglist ,docstring
+ ,@(cond-emacs-xemacs-macfn definition))
+ ;; no dynamic docstring in this case
+ `(eval-and-compile ; no warnings in Emacs
+ (defalias ',name
+ (cond ,@(mapcar (lambda (func) `((fboundp ',func) ',func))
+ (nreverse reuses))
+ (t ,(if definition
+ `(lambda ,arglist ,docstring
+ ,@(cond-emacs-xemacs-macfn definition))
+ 'ignore)))))))))))
+
+(eval-when-compile
+ (require 'cl)
+ (defvar init-file-loaded) ; would be useful in Emacs, too...
+ (defvar file-name-buffer-file-type-alist))
+
+
+
+;;;;##########################################################################
+;;;; User Options, Variables
+;;;;##########################################################################
+
+
+(defconst template-version "3.1c"
+ "Current version of package template.
+Check <http://emacs-template.sourceforge.net/> for the newest.")
+
+
+;;;===========================================================================
+;;; Customization and initialization
+;;;===========================================================================
+
+(defgroup template nil
+ "Use templates, decorate comments, auto-update buffers."
+ :group 'data
+ :link '(emacs-commentary-link "template.el")
+ :link '(url-link "http://emacs-template.sourceforge.net/")
+ :prefix "template-")
+
+(defgroup template-comments nil
+ "Comment decorations in package template."
+ :group 'template
+ :prefix "template-")
+
+(defgroup template-updating nil
+ "Updating with package template."
+ :group 'template
+ :prefix "template-")
+
+(defgroup template-derivation nil
+ "Deriving templates for new files."
+ :group 'template
+ :prefix "template-")
+
+(defgroup template-expansion nil
+ "Expanding the expansion forms in templates."
+ :group 'template
+ :prefix "template-")
+
+(defgroup template-miscellaneous nil
+ "Miscellaneous configurations of package template."
+ :group 'template
+ :prefix "template-")
+
+;; I could imagine that a future version of package custom could make this
+;; `PACKAGE-initialize' stuff easier
+(defcustom template-use-package nil
+ "Pseudo variable. Used to initialize template in custom buffer.
+Put `(template-initialize)' into your ~/.emacs to initialize package
+template in future sessions. See variable `template-initialize'."
+ :group 'template
+ :type '(boolean :format "%{%t%}: %[(template-initialize)%], %v\n"
+ :on "in use" :off "not yet initialized"
+ :help-echo "Initialize package Template."
+ :action template-initialize))
+
+(defcustom template-initialize t
+ "Whether/what to initialize with `template-initialize'.
+If t, do full initialization. Otherwise, the value should be a list
+with elements. To enable, include
+
+ * `auto' to enable `template-auto-update' and `template-auto-insert',
+ * `ffap' to make sure that `auto' works with `find-file-at-point',
+ * `cc-mode' to enable correct C/C++/Java/Antlr comment filling, i.e.,
+ to add `template-c-init-fill-function' to `c-mode-common-hook',
+ * `de-html-helper' to disable `html-helper's template and time-stamps,
+ * `keys' to setup the default key bindings,
+ * `menus' to setup the menus."
+ :group 'template-miscellaneous
+ :type '(choice (const :tag "All" t)
+ (set :value (auto cc-mode keys menus)
+ (const :tag "Auto Updating/Inserting" auto)
+ (const :tag "Correct Auto Inserting with Ffap" ffap)
+ (const :tag "Correct C Comment Filling" cc-mode)
+ (const :tag "Deactivate html-helper" de-html-helper)
+ (const :tag "Setup Key Bindings" keys)
+ (const :tag "Setup Menus" menus))))
+
+
+;;;===========================================================================
+;;; Menu
+;;;===========================================================================
+
+(defvar template-comment-menu
+ '("Comment"
+ ["Decorate Comment Line" template-single-comment
+ :active (and (not buffer-read-only)
+ (memq (template-comment-at-point)
+ '(none delimited single cont)))]
+ ["Decorate Comment Block" template-block-comment
+ :active (and (not buffer-read-only)
+ (memq (template-comment-at-point)
+ '(single block)))]
+ "---"
+ ["Indent for Comment" indent-for-comment
+ :active (and comment-start (not buffer-read-only))]
+ ["Continue Comment" indent-new-comment-line
+ :active (and comment-start (not buffer-read-only))]
+ ["Comment Region" comment-region
+ :active (and comment-start (not buffer-read-only) (mark))]
+ ["Comment Region 2" (comment-region 2)
+ :active (and comment-start (not buffer-read-only) (mark))]
+ ["Comment Region 3" (comment-region 3)
+ :active (and comment-start (not buffer-read-only) (mark))]
+ "---"
+ ["Update Buffer" template-update-buffer
+ :active (and template-update-buffer-alist (not buffer-read-only))])
+ "Menu for comment functions.")
+
+(defvar template-creation-menu
+ '("Template Creation"
+ :filter template-menu-filter
+ ["Open Template" template-open-template
+ :active (null (template-buffer-template-p))]
+ "--"
+ ["Define User Input" template-define-prompt t]
+ ["Define Text Register" template-define-register t]
+ ["Define Message" template-define-message t]
+ "---"
+ ["Insert Expansion Form" template-insert-form t])
+ "Menu for template creation.")
+
+
+;;;===========================================================================
+;;; Commenting
+;;;===========================================================================
+
+(defcustom template-max-column -1
+ "*Width of the separator line, to use with an empty `comment-end'.
+If the value is zero or negative, it is added to `fill-column'. See
+also `template-max-column-with-end'."
+ :group 'template-comments
+ :type 'integer)
+
+(defcustom template-max-column-with-end 0
+ "*Width of the separator line including a non-empty `comment-end'.
+If the value is zero or negative, it is added to `fill-column'. See
+also `template-max-column'."
+ :group 'template-comments
+ :type 'integer)
+
+(defcustom template-alt-comment-syntax-alist
+ '((t "/* " " */"))
+ "Alternative comment syntax for languages with \"mixed\" comments.
+Used by function `template-comment-syntax'. Elements look like
+ (MODES-OR-REGEXP COMMENT-START COMMENT-END)
+
+If the current `major-mode' has a empty `comment-end' and a commenting
+command does not work at `point' with the usual `comment-start', we
+search for the first matching alternative comment syntax in this alist.
+
+Each element must \"pass\" MODES-OR-REGEXP. If this is a list, it must
+include the current major-mode, if this is a regexp, it must match the
+`buffer-file-name' without version, otherwise it must be non-nil.
+
+Then, COMMENT-START and COMMENT-END is used as the alternative comment
+syntax if `comment-start-skip' matches COMMENT-START."
+ :group 'template-comments
+ :type '(repeat (group (choice (repeat :tag "In major modes" :value nil
+ function)
+ (regexp :tag "Buffer matching" :value "")
+ (sexp :tag "Always" :value t))
+ (string :tag "Alt comment start" :value "/* ")
+ (string :tag "Alt comment end" :value " */"))))
+
+(defcustom template-comment-indent t
+ "Non-nil means, indent single-line/block comments.
+Commands \\[template-single-comment] and \\[template-block-comment]
+indent the comment lines if this value is non-nil and the current major
+mode is not a member of `template-indent-mode-disable-list' or if this
+value is nil and the current major mode is a member of
+`template-indent-mode-enable-list'."
+ :group 'template-comments
+ :type 'boolean)
+
+(defcustom template-indent-mode-disable-list '(sh-mode makefile-mode)
+ "Major modes not having indented single-line/block comments.
+Used if `template-comment-indent' is non-nil. Major modes in which
+pressing TAB twice is different from pressing TAB once are good
+candidates for this list."
+ :group 'template-comments
+ :type '(repeat (function :tag "Major mode")))
+
+(defcustom template-indent-mode-enable-list nil
+ "Major modes having indented single-line/block comments.
+Used if `template-comment-indent' is nil."
+ :group 'template-comments
+ :type '(repeat (function :tag "Major mode")))
+
+(defcustom template-comment-specification-alist
+ '(("-" "" "" 0)
+ ("-" "" "" 0)
+ ("=" "\n\n" "\n" 1)
+ ("#" "\n\n\f\n" "\n\n" 2))
+ "List of specifications for comment functions.
+Each specification at LEVEL, starting at 1, is a list
+ (SEPARATOR BEFORE-BLOCK AFTER-BLOCK DELETE-LINES)
+
+SEPARATOR is the string which is inserted repeatedly by commands
+\\[template-single-comment] and \\[template-block-comment] up to
+`template-max-column'.
+
+After that, \\[template-block-comment] deletes DELETE-LINES after the
+comment block and inserts string AFTER-BLOCK at the end of the block and
+BEFORE-BLOCK at the front of the block.
+
+The specification LEVEL to use is determined by:
+ (1) If the prefix argument is non-nil and its numeric value is > 0,
+ this value is the LEVEL.
+ (2) If the prefix argument is nil, and there is an old comment style,
+ use old comment style.
+ (3) If `template-comment-specification-special' is a function or the
+ current major mode has a property with this name and its value is a
+ function, this function returns the specification.
+ (4) If `comment-end' is empty and `comment-start' is a string of length
+ 1: LEVEL is number of repetitions of `comment-start' at the
+ beginning of the line. Otherwise, if the correctly indented line
+ starts at the beginning of the line, LEVEL=3, else LEVEL=2."
+ :group 'template-comments
+ :type '(repeat (group (string :tag "Separator" :value "-")
+ (string :tag "Before block" :value "")
+ (string :tag "After block" :value "")
+ (integer :tag "Delete lines" :value 0))))
+
+(defcustom template-comment-specification-special nil
+ "Function used for special commenting styles or nil.
+See `template-comment-specification-alist' for details."
+ :group 'template-comments
+ :type '(choice (const nil) function))
+
+
+;;;===========================================================================
+;;; Auto updating
+;;;===========================================================================
+
+(defcustom template-auto-update 'query
+ "*Whether to update parts of the file when saving the buffer.
+When non-nil and `template-auto-update-disable-regexp' does not match
+the file name, automatically updates parts of the buffer, see
+`template-update-buffer-alist'. With value t or if the entry in the
+alist has no prompt, do not ask for confirmation.
+
+You should have called `template-initialize' to enable this feature."
+ :group 'template-updating
+ :type '(radio (const :tag "No" nil)
+ (const :tag "Without confirmation" t)
+ (sexp :tag "With confirmation" :format "%t" :value query)))
+
+(defcustom template-auto-update-disable-regexp nil
+ "*Regexp matching files not to automatically update.
+Value nil matches no file. See `template-auto-update'."
+ :group 'template-updating
+ :type '(choice (const :tag "none" nil) regexp))
+
+(defcustom template-update-buffer-alist
+ '((t "Update header in %s? "
+ (template-update-header t)
+ (file-name-sans-versions (file-name-nondirectory buffer-file-name)))
+ ((html-mode) "Update date inside <address> in %s? "
+ (-2000
+ "\\([0-9]+[ \t]+[A-Za-z][A-Za-z][A-Za-z][ \t]+[0-9]+\\)[ \t\n]*</address>"
+ 1)
+ (format-time-string "%d %b %Y")))
+ "Alist used how to update parts of the buffer.
+Used by function `template-update-buffer'. Elements look like
+ (MODES-OR-REGEXP PROMPT TEST NEW REPLACEMENT-FUN)
+
+Each element must \"pass\" MODES-OR-REGEXP. If this is a list, it must
+include the current major-mode, if this is a regexp, it must match the
+`buffer-file-name' without version, otherwise it must be non-nil.
+
+Then, TEST is `eval'd and must return the region = (BEG . END) to be
+replaced or nil if nothing should be updated according to the current
+element. If TEST is a list and the `car' of TEST is not a function,
+`template-update-buffer-region' is used as the default function, i.e.,
+REPLACEMENT-FUN looks like (LIMIT REGEXP GROUP). Then, check first/last
+LIMIT characters in buffer and return region according to GROUP's regexp
+group in REGEXP.
+
+Then, NEW is `eval'd. If it is a string, it is considered as
+replacement for the region, otherwise REPLACE-FUN must be non-nil.
+
+Then, ask user for confirmation with PROMPT where %s is substituted by
+the buffer name if PROMPT is a string and `template-auto-update' is not
+t.
+
+Finally, REPLACEMENT-FUN is called the `eval'd NEW and the beginning and
+the end of the region returned by TEST. If REPLACEMENT-FUN is nil, just
+replace the region by the `eval'd NEW."
+ :group 'template-updating
+ :type '(repeat (group (choice (repeat :tag "In major modes" :value nil
+ function)
+ (regexp :tag "Buffer matching" :value "")
+ (sexp :tag "Always" :value t))
+ (string :tag "Prompt" :value "Update in %s? ")
+ (choice (list :tag "Default test"
+ (choice (const :tag "No limit" nil)
+ (integer :tag "Limit" -1000))
+ regexp
+ (integer :tag "Regexp group" :value 0))
+ (sexp :tag "Eval sexp"))
+ (sexp :tag "Eval New string")
+ (option (function :tag "Replacement function")))))
+
+(defcustom template-header-lines 3
+ "*Last line number which is checked by \\[template-update-header]."
+ :group 'template-updating
+ :type 'integer)
+
+(put 'template-header-lines 'template-secure-value #'integerp)
+
+(defcustom template-header-regexp-alist
+ '(("@(#)\\([^ \t\n]+\\)" . 1)
+ ("^%s[ \t]*\\([^ \t\n%s][^ \t\n]*\\)[ \t]+--" . 1))
+ "Alist of regexps matching the file name in the header.
+The `car' of each element is the REGEXP with %s, if present, substituted
+by the comment start. A second %s, if present, is substitud by a single
+letter non-alpha comment start, or the empty string otherwise.
+
+The `cdr' is the regexp group to be replaced. Used by
+\\[template-update-header].
+
+The comment start is evaluated from `comment-start', the first character
+in the buffer or \"#\". It is assumed that a non-alpha single character
+comment start may be repeated. For example, the substituted regexp in
+`emacs-lisp-mode' is \"\;+\", in `c++-mode' \"//\"."
+ :group 'template-updating
+ :type '(repeat (cons :format "%v"
+ regexp
+ (integer :tag "Regexp group" :value 0))))
+
+
+;;;===========================================================================
+;;; Templates: finding templates
+;;;===========================================================================
+
+(defcustom template-auto-insert 'query
+ "*Whether to automatically use template files for new files.
+Used if the user gave a non-existent file as argument to a command in
+`template-find-file-commands'. When non-nil and a matching template
+file can be found, use a template like in `template-new-file'. File
+name refinement is never performed, see `template-derivation-alist'.
+
+With value t, do not ask for confirmation.
+
+You should have called `template-initialize' to enable this feature."
+ :group 'template-derivation
+ :type '(radio (const :tag "No" nil)
+ (const :tag "Without confirmation" t)
+ (sexp :tag "With confirmation" :format "%t" :value query)))
+
+(defcustom template-find-file-commands
+ '(find-file find-file-other-frame find-file-other-screen
+ find-file-other-window find-file-at-point ffap nil)
+ "*Commands which use templates as last resort, see `template-auto-insert'.
+See also `template-file-select-commands'.
+
+Include nil if you want to use templates for non-existing files as
+command line arguments when starting Emacs."
+ :group 'template-derivation
+ :type '(repeat (function :tag "Command")))
+
+(defcustom template-file-select-commands
+ '(exit-minibuffer minibuffer-complete-and-exit
+ list-mode-item-mouse-selected
+ list-mode-item-keyboard-selected)
+ "*Commands which select the file name via minibuffer/completions.
+Checked with commands in `template-find-file-commands'."
+ :group 'template-derivation
+ :type '(repeat (function :tag "Command")))
+
+(defface template-message-face
+ '((((class color) (background light)) (:background "pink"))
+ (t (:bold t)))
+ "Face for temporary message at point. This only works with XEmacs."
+ :group 'template-miscellaneous)
+
+(defcustom template-extension ".tpl"
+ "*Extension used for template files."
+ :group 'template-derivation
+ :type 'string)
+
+(defcustom template-subdirectories '("./" "Templates/")
+ "*List of subdirectories for template files.
+See `template-derivation-alist' for details."
+ :group 'template-derivation
+ :type '(repeat directory))
+
+(defcustom template-stop-derivation
+ (cond ((fboundp 'file-remote-p) 'file-remote-p)
+ ((fboundp 'efs-ftp-path) 'efs-ftp-path)
+ ((fboundp 'ange-ftp-ftp-path) 'ange-ftp-ftp-path))
+ "If non-nil, function used to determine whether to stop derivation.
+If non-nil, function is called with argument DIR. If it returns t,
+`template-derivation' stops to search for more project specific
+templates, i\.e\., just searches in `template-default-directories'."
+ :group 'template-derivation
+ :type '(choice (const :tag "Never" nil)
+ function))
+
+(defcustom template-default-directories
+ (cons (if (and (not (file-directory-p "~/.templates/"))
+ (file-directory-p "~/lib/templates"))
+ (expand-file-name "~/lib/templates/")
+ (expand-file-name "~/.templates/"))
+ (and (fboundp 'locate-data-directory)
+ (let ((dir (locate-data-directory "template")))
+ (and dir (list dir)))))
+ "*List of default directories for template files.
+See `template-derivation-alist' for details."
+ :group 'template-derivation
+ :type '(repeat directory))
+
+(defcustom template-derivation-alist
+ '(;;(("00readme" "" ".txt" "\\`00") . ("00readme" "" ".txt"))
+ ((t "" t))
+ ((t nil null) . (nil nil t 1))
+ (("TEMPLATE" "" t)))
+ "Alist for template file name derivation and file name refinement.
+Template derivation searches for the most specific readable template
+file. By default, files with the same RAW part as the name of the new
+file are considered to be more specific than files with just the same
+EXT part. Also files in the same directory are considered to be more
+specific than files in their parent directory or any default template
+directory. This behavior can be changed by this alist.
+
+Each FORM in this alist has the form (TEMPLATE . REFINEMENT). If
+TEMPLATE matches, we have found a valid template file and the
+corresponding REFINEMENT is used for the file name refinement.
+
+Before the derivation, the given file name is split into the directory
+part DIR, the file name without directory FILE, and the raw part RAW of
+FILE, the numbering NUM and the extension EXT. The result is stored in
+`template-file'.
+
+TEMPLATE can have the form (FUNCTION ARG...). If TEMPLATE matches,
+FUNCTION, called with arguments ARGs, should return the split template
+file name, see `template-split-filename'.
+
+TEMPLATE can also have the form (T-RAW T-NUM T-EXT F-REGEXP) where all
+elements are optional, i.e., have value nil as default. For TEMPLATE to
+match, all conditions T-RAW, T-NUM and T-EXT must be met and F-REGEXP,
+if non-nil, should match FILE, the non-directory part of the given file
+name. If a condition is a string, the corresponding part of the
+template file must be equal to it. If t, the part must be equal to
+RAW/NUM/EXT of the given file name. If nil, any value will do it. Any
+other value acts like t when the part of the given file name is
+non-empty, as nil otherwise.
+
+REFINEMENT can have the form (FUNCTION ARG...). FUNCTION, called with
+the list of the split template filename and ARGs as arguments, should
+set `template-file' if the file name should be refined.
+
+REFINEMENT can also have the form (F-RAW F-NUM F-EXT AUTO-NUM) where all
+elements are optional, i.e., have value nil as default. If F-RAW, F-NUM
+and F-EXT are non-nil, they change RAW/NUM/EXT of `template-file'. A
+string will be used as the new part. If t, the corresponding part of
+the template name will be used.
+
+We will use auto numbering in the following two cases: if NUM is
+non-empty and the file exists already, or if NUM is empty and AUTO-NUM
+is non-nil. Auto numbering looks at the file names in DIR to generate
+the next unique number which is at least as high as NUM in the first
+case and AUTO-NUM in the second.
+
+Let us use parts of the default value as examples:
+
+Use a template with the same RAW part of the given file name and the
+same EXT part if provided, e.g., for \"exercise2\" use template
+\"exercise.tex.tpl\". Refine file name to use the extension of the
+template file, also use auto numbering, e.g., if files \"exercise2.tex\"
+and \"exercise3.tex\" exist, refine name to \"exercise4.tex\":
+ ((t nil null) \. (nil nil t 1))
+
+For a file with extension EXT, use TEMPLATE.EXT:
+ ((\"TEMPLATE\" \"\" t))
+
+We could define: If the given file name starts with \"00\", use template
+\"00readme.txt.tpl\". Refine file name to \"00readme.txt\":
+ ((\"00readme\" \"\" \".txt\" \"\\\\`00\") \. (\"00readme\" \"\" \".txt\"))
+
+Since more than one template file could meet this conditions, the
+template derivation searches for first readable file with extension
+`template-extension' which is found by the following algorithm:
+
+ forall FORMs in `template-derivation-alist' do
+ for directory BASE from DIR
+ while not stopped according to `template-stop-derivation' do
+ forall subdirectories DIRs in `template-subdirectories'
+ relative to BASE do
+ forall TEMPLATEs in DIR do
+ if check_form (FORM, FULL, TEMPLATE) return TEMPLATE
+ forall directories DIRs in `template-default-directories' do
+ forall TEMPLATEs in DIR do
+ if check_form (FORM, FULL, TEMPLATE) return TEMPLATE
+ if not used via `template-auto-insert'
+ forall TEMPLATEs in `template-default-directories'
+ where name_nondir (TEMPLATE) = \"DEFAULT.tpl\" do
+ if readable (TEMPLATE) return TEMPLATE
+ return TEMPLATE in first (`template-default-directories')
+ where name_nondir (TEMPLATE) = \"DEFAULT.tpl\""
+ :group 'template-derivation
+ :type '(repeat (cons :format "%v"
+ (sexp :tag "Derivation" :value ("TEMPLATE" nil t))
+ (sexp :tag "Refinement" :value nil))))
+
+
+;;;===========================================================================
+;;; Templates: expanding templates
+;;;===========================================================================
+
+(defcustom template-confirm-insecure t
+ "*Non-nil means, ask whether to use insecure template expansions.
+Only set this to nil if you ALWAYS check template files before using
+it!"
+ :group 'template-expansion
+ :type 'boolean)
+
+(put 'template-confirm-insecure 'risky-local-variable t)
+
+(defcustom template-message-buffer "*Template Message*"
+ "If non-nil, name of buffer where messages are shown.
+The following messages will be displayed in definition sequence before
+the expansion has taken place:
+ - :before messages, see `template-definition-start',
+ - user defined prompts if `template-message-prompt-format' is non-nil,
+ - user defined registers when there has been a :before message before,
+ see `template-message-register-format'.
+
+The following messages will be displayed in definition sequence after
+the expansion has taken place:
+ - :after messages, see `template-definition-start',
+ - user defined registers, display them at point if the value of this
+ variable is nil, see `template-message-register-format'."
+ :group 'template-miscellaneous
+ :type '(choice (const :tag "None" nil)
+ (string :tag "Buffer Name")))
+
+(defcustom template-message-prompt-intro
+ "Template expansion will ask for input with the following prompts:"
+ "Default intro message used before listing user defined prompts.
+Used with :before messages, see `template-message-prompt-format'."
+ :group 'template-miscellaneous
+ :type '(choice (const :tag "None" nil)
+ (string :tag "Intro text")))
+
+(defcustom template-message-prompt-format " %s"
+ "If non-nil, format string for user defined prompts.
+If non-nil and `template-message-buffer' is non-nil, user defined
+prompts will be listed before starting the expansions. Prompts can be
+defined as specified in the docstring of `template-definition-start'.
+For each PROMPT, this format string will be used with substitution
+PROMPT/%s.
+
+If no :before message has been defined before, use, if non-nil,
+`template-message-prompt-intro' as the first :before message."
+ :group 'template-miscellaneous
+ :type '(choice (const :tag "No prompt" nil)
+ (string :tag "Format string")))
+
+(defcustom template-message-register-intro
+ "Template has defined the following registers:"
+ "Default intro message used before listing user defined prompts.
+Used with :after messages, see `template-message-register-format'."
+ :group 'template-miscellaneous
+ :type '(choice (const :tag "None" nil)
+ (string :tag "Intro text")))
+
+(defcustom template-message-register-format " %c:\t\"%s\"\t%s"
+ "If non-nil, format string for user defined registers.
+If non-nil, user defined text registers will be listed. Registers can
+be defined as specified in the docstring of `template-definition-start'.
+For each register CHAR with contents CONTENTS and optional comment
+COMMENT, this format string will be used with substitution CHAR/%c,
+CONTENT/%s and \(COMMENT/%s or \"\"/%s).
+
+The list of register definitions will be displayed:
+ - at point if `template-message-buffer' is nil,
+ - with :before messages if there has been at least one :before message
+ defined before and if `template-message-buffer' is non-nil,
+ - with :after messages if `template-message-buffer' is non-nil.
+ If no :after message has been defined before, use, if non-nil,
+ `template-message-register-intro' as the first :after message."
+ :group 'template-miscellaneous
+ :type '(choice (const :tag "No register content" nil)
+ (string :tag "Format string")))
+
+(defcustom template-message-timeout 600
+ "*Maximum duration the temporary message will be displayed at point.
+Any user event will also make the temporary message disappear. The
+temporary message uses face in `template-message-face'."
+ :group 'template-miscellaneous
+ :type 'integer)
+
+(put 'template-message-timeout 'template-secure-value #'integerp)
+
+(defcustom template-date-format "%d %b %Y"
+ "*Date/time format used with the expansion form (>>>DATE<<<).
+See `template-default-expansion-alist' and `format-time-string'. See
+also `template-time-format'."
+ :group 'template-expansion
+ :type 'string)
+
+(put 'template-date-format 'template-secure-value #'stringp)
+
+(defcustom template-time-format "%T"
+ "*Date/time format used with the expansion form (>>>TIME<<<).
+See `template-default-expansion-alist' and `format-time-string'. See
+also `template-date-format'."
+ :group 'template-expansion
+ :type 'string)
+
+(put 'template-time-format 'template-secure-value #'stringp)
+
+(defcustom template-string-default "%0.0S"
+ "*Format string used for non-string variable extensions.
+If SYMBOL in (\"KEY\" \. SYMBOL) is not a string, use string with
+substitution SYMBOL/%S. Default value \"%0.0S\" causes to print
+nothing. See `template-definition-start'."
+ :group 'template-expansion
+ :type 'string)
+
+(put 'template-string-default 'template-secure-value #'stringp)
+
+(defcustom template-expansion-format "(>>>%s<<<)"
+ "Format string for expansion forms.
+Is a expansion form with substitution KEY/%s. The value should
+correspond with `template-expansion-regexp'. Used by
+`template-insert-form'."
+ :group 'template-expansion
+ :type 'string)
+
+(put 'template-expansion-format 'template-secure-value #'stringp)
+
+(defcustom template-expansion-regexp "(>>>\\([-A-Za-z0-9_]+\\)<<<)"
+ "Regexp matching strings which are replaced by their expansions.
+The first regexp group contains the KEY used by the per-template
+expansion, see `template-definition-start' and the global expansions in
+`template-expansion-alist' and `template-default-expansion-alist'. The
+value should correspond with `template-expansion-alist'.
+
+If there is no defined expansion for the key, ask the user for a
+replacement, see `template-read'. If the key is matched by
+`template-register-regexp', store buffer position in register, see
+`template-register', .
+
+If you want to use a text literally which is matched by this regexp, use
+the zero expansion form (>>>ZERO_FORM<<<)."
+ :group 'template-expansion
+ :type 'regexp)
+
+(put 'template-expansion-regexp 'template-secure-value #'stringp)
+
+(defcustom template-literal-environment '("LITERAL" . "/LITERAL")
+ "Environment for literal text in template.
+Looks like (OPEN . CLOSE). Text between expansion forms with keys OPEN
+and CLOSE is not expanded. If you change OPEN, you should change key
+\"LITERAL\" in `template-default-expansion-alist' accordingly."
+ :group 'template-expansion
+ :type '(cons (string :tag "Open tag") (string :tag "Close tag")))
+
+(defcustom template-register-regexp "\\`[0-9]\\'"
+ "*Regexp matching keys for storing point positions in registers.
+These keys use `template-register' as the default expansion instead of
+`template-read'. See `template-expansion-regexp'. If a register is used
+twice, it is marked by a \"*\" in the echo area after the expansion."
+ :group 'template-expansion
+ :type 'regexp)
+
+(put 'template-register-regexp 'template-secure-value #'stringp)
+
+(defcustom template-expansion-alist nil
+ "User defined expansions forms.
+Predefined expansion forms for `template-expansion-regexp'. Each entry
+has the form (KEY . SEXP). These expansion forms shadow those in
+`template-default-expansion-alist' and are shadowed by those in the
+per-template definition section. See `template-definition-start'."
+ :group 'template-expansion
+ :type '(repeat (cons :format "%v"
+ (string :tag "Key" :value "")
+ (repeat :tag "Evaluate all" sexp))))
+
+(put 'template-expansion-alist 'risky-local-variable t)
+
+(defvar template-default-expansion-alist
+ '(("POINT" (setq template-point (point-marker))) ; point
+ ("MARK" (setq template-mark (point-marker))) ; mark
+ ("DIR" (insert (car template-file))) ; directory
+ ("FILE" (insert (cadr template-file))) ; file name without directory
+ ("FILE_SANS" (insert (nth 2 template-file)
+ (nth 3 template-file)))
+ ("FILE_RAW" (insert (nth 2 template-file))) ; raw file name without number
+ ("FILE_NUM" (insert (nth 3 template-file))) ; number
+ ("FILE_UPCASE" (insert (upcase (nth 2 template-file))
+ (nth 3 template-file)))
+ ("FILE_EXT" (or (string= (nth 4 template-file) "") ; extension
+ (insert (substring (nth 4 template-file) 1))))
+ ("DATE" (template-insert-time template-date-format))
+ ("TIME" (template-insert-time template-time-format))
+ ("VC_DATE" (set-time-zone-rule "UTC")
+ (template-insert-time "%Y/%m/%d %T" "0000/00/00 00:00:00")
+ ;; using saved `current-time-zone' doesn't work, but nil does
+ (set-time-zone-rule nil))
+ ("YEAR" (template-insert-time "%Y" "0000"))
+ ("ISO_DATE" (template-insert-time "%Y-%m-%d" "0000-00-00"))
+ ("COMMENT" (template-read "Initial comment: ")) ; comment
+ ("AUTHOR" (insert (or user-mail-address ; author
+ (and (fboundp 'user-mail-address)
+ (user-mail-address))
+ (concat (user-login-name) "@" (system-name)))))
+ ("USER_NAME" (insert (or (and (boundp 'user-full-name) ; user name
+ user-full-name)
+ (user-full-name))))
+ ("LOGIN_NAME" (insert (user-login-name))) ; login name
+ ("HOST_ADDR" (insert (or (and (boundp 'mail-host-address) ; host address
+ (stringp mail-host-address)
+ mail-host-address)
+ (system-name))))
+ ("LITERAL" (if (search-forward (format template-expansion-format
+ (cdr template-literal-environment))
+ nil 'limit)
+ (delete-region (match-beginning 0) (match-end 0))))
+ ("ZERO_FORM")) ; zero form
+ "Predefined default expansions forms.
+Predefined expansion forms for `template-expansion-regexp'. Each entry
+has the form (KEY . SEXP). These expansion forms are shadowed by those
+in `template-expansion-alist' and by those in the per-template
+definition section. See `template-definition-start'.
+
+The default predefined expansion forms are --default is inserting--:
+ (>>>POINT<<<) set point
+ (>>>MARK<<<) set mark, jump to it with \\[exchange-point-and-mark]
+ (>>>DIR<<<) directory: /home/clstaff/wedler/lib/
+ (>>>FILE<<<) file w/o directory: text1.txt
+ (>>>FILE_SANS<<<) file name w/o extension: text1
+ (>>>FILE_RAW<<<) raw file name: text
+ (>>>FILE_NUM<<<) number in name: 1
+ (>>>FILE_EXT<<<) extension: txt
+ (>>>FILE_UPCASE<<<) upcase file name w/o extension: TEXT1
+ (>>>DATE<<<) date using `template-date-format': 11 Jan 1999
+ (>>>TIME<<<) time using `template-time-format': 11:58:49
+ (>>>YEAR<<<) the year: 1999
+ (>>>ISO_DATE<<<) ISO 8601 date: 1999-01-11
+ (>>>VC_DATE<<<) UTC date/time for vc: 1999/01/11 10:58:49
+ (>>>COMMENT<<<) ask user for initial comment
+ (>>>AUTHOR<<<) author, i.e., `user-mail-address'
+ (>>>USER_NAME<<<) user name: Christoph Wedler
+ (>>>LOGIN_NAME<<<) login name: wedler
+ (>>>HOST_ADDR<<<) Host address: fmi.uni-passau.de
+ (>>>LITERAL<<<) literal text up to (>>>/LITERAL<<<)
+ (>>>ZERO_FORM<<<) zero form, i.e., insert nothing. Useful to insert
+ a text part matched by `template-expansion-regexp' literally.
+
+There are aliases with one-letter keys, see `template-key-alias-alist'.
+
+It is useful to follow the following conventions: upper case keys for
+predefined extensions, lower case and digits for per-template and the
+following default expansions:
+ (>>>0<<<) to (>>>9<<<) set registers 0 to 9, jump to it with
+ \\[jump-to-register] 0 etc., see `template-register-regexp'
+ (>>>x<<<) where x is any unused letter sequence: ask user.")
+
+(put 'template-default-expansion-alist 'risky-local-variable t)
+
+(defvar template-key-alias-alist
+ '(("P" . "POINT")
+ ("M" . "MARK")
+ ("D" . "DIR")
+ ("F" . "FILE")
+ ("R" . "FILE_RAW")
+ ("N" . "FILE_NUM")
+ ("B" . "FILE_UPCASE")
+ ("E" . "FILE_EXT")
+ ("T" . "DATE")
+ ("V" . "VC_DATE")
+ ("Y" . "YEAR")
+ ("I" . "ISO_DATE")
+ ("C" . "COMMENT")
+ ("A" . "AUTHOR")
+ ("U" . "USER_NAME")
+ ("L" . "LOGIN_NAME")
+ ("H" . "HOST_ADDR")
+ ("Z" . "ZERO_FORM"))
+ "Alist to support the old one-letter predefined expansion forms.
+Used for `template-expansion-alist' and
+`template-default-expansion-alist'.")
+
+(defcustom template-definition-start
+ ">>>TEMPLATE-DEFINITION-SECTION<<<"
+ "Header for the per-template definition section.
+The region following the the first match of this regexp defines the
+per-template definition section. The region will be deleted before the
+actual expansion, see `template-new-file'. If you use the \"Local
+Variables:\" section, define it before this region.
+
+The definition section defines expansion forms for strings KEYs matched
+by `template-expansion-regexp' which might shadow those in
+`template-expansion-alist' and `template-default-expansion-alist':
+
+ (\"KEY\"): zero form, same as (>>>ZERO_FORM<<<) in default value of
+`template-default-expansion-alist', useful for inserting text matched by
+`template-expansion-regexp' literally.
+
+ (\"KEY\". CHAR): CHAR is the register where the current buffer
+position is stored, see `template-register-regexp'.
+
+ (\"KEY\" \"PROMPT\" \"PREFIX\" \"SUFFIX\" \"DEFAULT\" AGAIN-P) where
+the last four arguments are optional: ask user with PROMPT for a STRING.
+If STRING is not \"\", insert PREFIX STRING SUFFIX, otherwise DEFAULT.
+For AGAIN-P, see `template-read'. To define, use
+\\[template-define-prompt].
+
+ (\"KEY\" \"PROMPT\" (\"ANSWER\" \. \"TEXT\")...): ask user with PROMPT
+for an input with completion over all ANSWERs and insert corresponding
+TEXT. Expansion forms in TEXT will be expanded.
+
+ (\"KEY\" \"PROMPT\" (t \. \"TEXT-y\") (nil \. \"TEXT-n\")): ask user
+with PROMPT a \"y or n\" question with `y-or-n-p' and insert TEXT-y or
+TEXT-n, correspondingly. Expansion forms in TEXT-X will be expanded.
+The y-case and the n-case are optional and can be exchanged.
+
+ (\"KEY\" \. SYMBOL): insert value of SYMBOL; if value is no string at
+the time of the replacement, use `template-string-default' as format
+string for SYMBOL.
+
+ (\"KEY\" COMMAND \. PREFIX): COMMAND is a symbol or a vector and is
+called with `command-execute' after setting `prefix-arg' to PREFIX, not
+evaluated. If COMMANDs symbol property `template-secure-command' is
+nil, the form is insecure. If that symbol property is a function, it is
+called with PREFIX to check whether COMMAND could be called directly
+with PREFIX as remaining arguments.
+
+ (\"KEY\" SEXPR...): evaluate SEXPR during the expansion, see
+`template-expansion-alist' for examples. This form is insecure.
+
+There are other per-template definitions:
+
+ \"MESSAGE\": additional line displayed at point until first user event
+or after `template-message-timeout' seconds. The lines are displayed
+with face in `template-message-face'. With active form selector
+:before, define a message which is displayed in
+`template-message-buffer' before the exansion has started. With active
+form selector :after, define a message which is displayed in
+`template-message-buffer' after the exansion has taken place. To
+define interactively, use \\[template-define-message].
+
+ (CHAR \. \"CONTENTS\"): Set register CHAR to have contents CONTENTS.
+CONTENTS can then be inserted into a buffer with \\[insert-register] CHAR.
+
+ (CHAR \"CONTENTS\" COMMENT) where COMMENT is optional: Set register
+CHAR to have contents CONTENTS. CONTENTS can then be inserted into a
+buffer with \\[insert-register] CHAR. Also display an additional line
+at point to show the contents with COMMENT. To define, use
+\\[template-define-register].
+
+The following forms depend on the active form selector which is the last
+of the following expansion forms:
+ - :before: \"MESSAGE\" will be displayed before the expansion
+ - :after: \"MESSAGE\" will be displayed after the expansion
+ - :eval-before: execute COMMAND and SEXPR before expansion
+ - :eval-after: execute COMMAND and SEXPR after expansion
+ - nil, deprecated: with the first form, the active form selector is
+ :eval-before, with the second, it is :eval-after.
+
+ (VARIABLE . VALUE): set SYMBOL's local value to VALUE, not evaluated.
+This form is only secure if VARIABLE has a symbol property
+`template-secure-value' which returns non-nil when applied to VALUE, not
+evaluated. This form is useful for variables which determine the
+expansion, like `template-time-format' and `template-date-format'. For
+local variables in your new file, use the normal way via the \"Local
+Variables:\" section. The active form selector must not be :eval-before
+or :eval-after.
+
+ COMMAND: COMMAND is a symbol or a vector and is called with
+`command-execute' before the expansion with form selector :eval-before,
+and after the expansion with form selector :eval-after. If COMMANDs
+symbol property `template-secure-command' is nil, the form is insecure.
+You should use the safe command `normal-mode' in the pre-expansion forms
+if the expansion forms depend on the correct major mode.
+
+ SEXPR: evaluate SEXPR before the expansion with form selector
+:eval-before, and after the expansion with form selector :eval-after.
+This form is insecure.
+
+If any insecure forms have been used, the user of the template will be
+asked whether to use the template, see `template-confirm-insecure'."
+ :group 'template-expansion
+ :type 'string)
+
+
+
+;;;;##########################################################################
+;;;; Commenting
+;;;;##########################################################################
+
+
+(defunx template-point-at-bol (&optional count)
+ :emacs-only line-beginning-position
+ :xemacs-only point-at-bol)
+
+(defunx template-point-at-eol (&optional count)
+ :emacs-only line-end-position
+ :xemacs-only point-at-eol)
+
+(defunx template-char-or-char-int-p (object)
+ :emacs-only integerp
+ :xemacs-only char-or-char-int-p)
+
+(defunx template-char-or-int-to-char (object)
+ :emacs-only identity
+ "Convert character or integer OBJECT into the equivalent character."
+ (if (characterp object) object (int-to-char object)))
+
+
+;;;===========================================================================
+;;; Main functions
+;;;===========================================================================
+
+;;;###autoload
+(defun template-single-comment (&optional arg)
+ "Decorate the comment in the current line with dashes and alike.
+The line must be a comment-only line or must contain a comment ending by
+eol. That is, jump to the end of the current line and insert the dashes
+and the final comment end-string up-to the fill position. Prefix
+argument ARG and `template-comment-specification' determines the comment
+style to use. The length of the resulting line is determined by
+`template-max-column' and `template-max-column-with-end'."
+ (interactive "*P")
+ (let* ((orig (point-marker))
+ (syntax0 (and comment-start comment-start-skip
+ (condition-case nil
+ (template-comment-syntax orig 'boc)
+ (error nil))))
+ (syntax (cond ((cdr syntax0)
+ (template-comment-syntax orig))
+ (syntax0
+ (condition-case nil
+ (template-comment-syntax (point-marker))
+ (error syntax0)))
+ (t
+ (back-to-indentation)
+ nil)))
+ (sep (template-comment-separator-regexp syntax))
+ (end (template-point-at-eol))
+ old)
+ (save-excursion
+ (cond ((re-search-forward sep end t)
+ ;; with sep in current line
+ (setq old (buffer-substring (match-beginning 1) (match-end 1)))
+ (delete-region (match-beginning 0) (match-end 0)))
+ ((cdr syntax) ; with start-end comment
+ (if (looking-at (concat "[ \t]*\\(.+\\)?"
+ (regexp-quote (cadr syntax))
+ "[ \t]*\\(.+\\)?$"))
+ (if (or (match-beginning 1) (match-beginning 2))
+ (error "This line contains non-separator chars and %S"
+ (cadr syntax))
+ ;; Delete comment-end. Don't delete its first char if it is
+ ;; the same as the second of comment-start.
+ (delete-region (if (and (= (length (car syntax)) 2)
+ (= (length (cadr syntax)) 2)
+ (eq (aref (car syntax) 1)
+ (aref (cadr syntax) 0)))
+ (1+ (match-beginning 0))
+ (match-beginning 0))
+ (match-end 0))))
+ (goto-char (cddr syntax))
+ (if (re-search-forward sep end t)
+ ;; sep in line between comment-start and point-at-eol
+ (setq old (buffer-substring (match-beginning 1)
+ (match-end 1)))))))
+ (template-insert-separator
+ (car (template-comment-specification arg old syntax))
+ nil syntax)))
+(put 'template-single-comment 'template-secure-command t)
+
+;;;###autoload
+(defun template-block-comment (&optional arg)
+ "Decorate the current block of comment-only lines with dashes and alike.
+That is, surround the the contiguous comment-only lines around point
+with extra lines containing dashes and alike and to put the correct
+number of newlines around the block.
+
+Barf if the comment syntax at point has a non-empty `comment-end' or if
+point is not in a comment-only line.
+
+A block comment consists of all neighboring lines which start with
+spaces and `comment-start'. If `comment-start' is a string of length 1,
+the number of repetitions of `comment-start' must be the same or larger
+than in the line where the command is invoked from, too.
+
+Prefix argument ARG and `template-comment-specification' determines the
+comment style to use. The length of the separator line is determined by
+`template-max-column'.
+
+This command can also be used with point in an empty line after a block
+comment. A second invocation of this command directly after a
+successful invocation deletes the remaining empty lines from the current
+line on."
+ (interactive "*P")
+ (let* ((orig (point-marker))
+ (syntax (progn
+ (end-of-line)
+ (skip-chars-backward " \t\n\f")
+ (template-comment-syntax orig))))
+ (when (cdr syntax)
+ (goto-char orig)
+ (error "Command only works with comments terminated by end-of-line"))
+
+ (if (and (eq last-command 'template-block-comment-success)
+ (looking-at "[ \t]*$"))
+ (template-insert-newline "" nil (1- (template-point-at-bol)))
+ (let* ((prefix (concat "[ \t]*" (regexp-quote (car syntax))))
+ (sepline (concat prefix "[ \t]*"
+ (template-comment-separator-regexp syntax)))
+ old block-beg block-end def)
+ ;; go to the first line with same comment prefix ---------------------
+ (beginning-of-line)
+ (while (and (not (bobp)) (looking-at prefix))
+ (beginning-of-line 0))
+ (or (looking-at prefix) (beginning-of-line 2))
+ (while (looking-at sepline)
+ (setq old (buffer-substring (1- (match-end 0)) (match-end 0)))
+ (kill-line 1))
+ (setq block-beg (point-marker))
+ ;; go to the last line with same comment prefix ----------------------
+ (while (looking-at prefix)
+ (template-indent-according-to-mode)
+ (beginning-of-line 2))
+ (if (eobp) (newline))
+ (setq block-end (copy-marker (point) t))
+ (while (progn (forward-line -1) (looking-at sepline))
+ (setq old (buffer-substring (1- (match-end 0)) (match-end 0)))
+ (kill-line 1))
+ ;; insert separator lines --------------------------------------------
+ (goto-char block-beg)
+ (set-marker block-beg nil)
+ (back-to-indentation)
+ (setq def (template-comment-specification arg old syntax))
+ (beginning-of-line)
+ (template-insert-newline (cadr def))
+ (template-insert-separator (car def) (car syntax) syntax)
+ (goto-char block-end)
+ (set-marker block-end nil)
+ (template-insert-separator (car def) (car syntax) syntax)
+ (template-insert-newline (caddr def)
+ (and (cadddr def)
+ (save-excursion
+ (forward-line (cadddr def))
+ (point))))
+ (setq this-command 'template-block-comment-success)))
+ (template-indent-according-to-mode)
+ (back-to-indentation)))
+(put 'template-block-comment 'template-secure-command t)
+
+
+;;;===========================================================================
+;;; Check comment start, return specification
+;;;===========================================================================
+
+(defun template-indent-according-to-mode ()
+ "Indent line according to `template-comment-indent'."
+ (if (if template-comment-indent
+ (not (memq major-mode template-indent-mode-disable-list))
+ (memq major-mode template-indent-mode-enable-list))
+ (indent-according-to-mode)))
+
+(defun template-default-comment ()
+ "Return default comment according to current position."
+ (if comment-start
+ (substring comment-start 0 (string-match "[ \t]\\'" comment-start))
+ (if (eolp) "#"
+ (let ((default (buffer-substring (point) (1+ (point)))))
+ (if (string-match "[A-Za-z]" default) "#" default)))))
+
+(defun template-comment-at-point ()
+ "Return the comment syntax at the current position.
+Return nil, if no commenting command can be used, i.e., if point is not
+in a comment-only line. Return `none' if the `major-mode' doesn't
+define a comment syntax. Return `delimited' if point is between
+`comment-start' and a non-empty `comment-end'. Return `single' if point
+is in a comment line where the comment syntax has a empty `comment-end',
+return `block' if point is in an empty line after such a comment line."
+ (if (and comment-start comment-start-skip)
+ (save-excursion
+ (let ((orig (point)))
+ (condition-case nil
+ (progn
+ (end-of-line)
+ (skip-chars-backward " \t\n\f")
+ (if (cdr (template-comment-syntax orig t)) 'delimited
+ (if (< (template-point-at-eol) orig) 'block 'single)))
+ (error
+ (condition-case nil
+ (progn
+ (goto-char orig)
+ (beginning-of-line)
+ (when (re-search-forward comment-start-skip
+ (template-point-at-eol) t)
+ (goto-char (or (match-end 1) (match-beginning 0)))
+ (unless (or (cdr (template-comment-syntax orig 'boc))
+ (< (template-point-at-eol) orig))
+ 'cont)))
+ (error nil))))))
+ 'none))
+
+(defun template-comment-syntax (orig &optional no-indent)
+ "Return the comment syntax at ORIG. Signal error if not in comment.
+Return (COMMENT-START) if the comment syntax has an empty `comment-end'.
+Return (COMMENT-START COMMENT-END . START-POS) if the comment syntax has
+a non-empty `comment-end' where START-POS is the position of the first
+character inside the comment. Move point to first character after the
+comment start or the first non-whitespace character on this line.
+
+ORIG should be the same as `point' or in a empty line after `point'.
+
+If optional argument NO-INDENT is nil, indents the current line
+according to `template-comment-indent' and `indent-according-to-mode'.
+If NO-INDENT is `boc', move point to the beginning of the comment.
+
+COMMENT-START is stripped off its final spaces, COMMENT-END off its
+initial spaces."
+ (unless (and comment-start comment-start-skip)
+ (error "No comment syntax has been defined for %s" major-mode))
+ (if (eq no-indent 'boc)
+ (progn
+ (beginning-of-line)
+ (if (re-search-forward comment-start-skip (template-point-at-eol) t)
+ (goto-char (or (match-end 1) (match-beginning 0)))))
+ (or no-indent (template-indent-according-to-mode))
+ (back-to-indentation))
+ (let* ((string (template-default-comment)))
+ (if (string= comment-end "")
+ (if (looking-at (concat (regexp-quote string)
+ (and (= (length string) 1)
+ (not (eq no-indent 'boc))
+ "+")))
+ (progn
+ (goto-char (match-end 0))
+ (list (buffer-substring (match-beginning 0) (point))))
+ (let ((alist template-alt-comment-syntax-alist)
+ elem c-start c-end)
+ (while alist
+ (setq elem (pop alist))
+ (and (template-match-modes-or-regexp (car elem))
+ (string-match comment-start-skip (cadr elem))
+ (setq c-start (cadr elem)
+ c-end (caddr elem)
+ alist nil)))
+ (template-comment-syntax-0 orig c-start c-end string)))
+ (template-comment-syntax-0 orig comment-start comment-end))))
+
+(defun template-comment-syntax-0 (orig c-start c-end &optional single)
+ ;; checkdoc-params: (orig c-start c-end single)
+ "Internal function for `template-comment-syntax'."
+ (unless (and (stringp c-start) (stringp c-end) (not (string= c-end "")))
+ (goto-char orig)
+ (error "Line does not start with %S"
+ (or single (template-default-comment))))
+ (setq c-start (substring c-start 0 (string-match "[ \t]\\'" c-start))
+ c-end (if (string-match "\\`[ \t]+" c-end)
+ (substring c-end (match-end 0))
+ c-end))
+ (cond ((looking-at (regexp-quote c-start))
+ (goto-char (match-end 0))
+ (cons c-start (cons c-end (point))))
+ ((save-excursion
+ (when (re-search-backward (concat "^[ \t]*" (regexp-quote c-start))
+ nil t)
+ (goto-char (match-end 0))
+ (let ((match (point)))
+ (unless (when (search-forward c-end orig t)
+ (skip-chars-forward " \t")
+ (< (point) orig))
+ (cons c-start (cons c-end match)))))))
+ (t
+ (goto-char orig)
+ (if single
+ (error "Not inside a comment (%S or %S-%S) starting in new line"
+ single c-start c-end)
+ (error "Not inside a comment (%S-%S) starting in new line"
+ c-start c-end)))))
+
+
+;;;===========================================================================
+;;; Comment specification
+;;;===========================================================================
+
+;; A simple `mapconcat' is likely to slow down Emacs' regexp search algorithm
+;; considerably (backtracking => near-infloop).
+(defun template-comment-separator-regexp (syntax)
+ "Return regexp matching separator comment lines.
+The regexp also matches if the lines ends with parts of COMMENT-END in
+argument SYNTAX, see `template-comment-syntax'."
+ (let ((estring (cadr syntax))
+ (alist template-comment-specification-alist)
+ (chars nil)
+ str i c)
+ (while alist
+ (setq str (car (pop alist)))
+ (when str
+ (setq i (length str))
+ (while (>= (decf i) 0)
+ ;; (pushnew (aref str i) chars), but requires cl at runtime:
+ (or (memq (setq c (aref str i)) chars) (push c chars)))))
+ (concat "\\("
+ (mapconcat (lambda (c) (regexp-quote (char-to-string c)))
+ (or chars "#")
+ "\\|")
+ (if estring
+ (concat "\\)+[ \t]*"
+ (mapconcat (lambda (c)
+ (regexp-quote (char-to-string c)))
+ estring
+ "?")
+ "?[ \t]*$")
+ "\\)+[ \t]*$"))))
+
+(defun template-comment-specification (arg old syntax)
+ "Return the comment specification to use.
+See `template-comment-specification-alist' for details. ARG is the
+prefix argument, OLD the SEPARATOR of the old comment style and SYNTAX
+is the comment syntax returned by `template-comment-syntax'."
+ (and arg (setq arg (prefix-numeric-value arg)))
+ ;; assumes point-at-indentation
+ (or (and arg (> arg 0)
+ (if (< (length template-comment-specification-alist) arg)
+ (car (last template-comment-specification-alist))
+ (nth (1- arg) template-comment-specification-alist)))
+ (and (null arg) old
+ (assoc old template-comment-specification-alist))
+ (and (functionp template-comment-specification-special)
+ (funcall template-comment-specification-special))
+ (and (functionp (get major-mode 'template-comment-specification-special))
+ (funcall (get major-mode 'template-comment-specification-special)))
+ (and syntax
+ (template-comment-specification
+ (if (or (cdr syntax) (> (length comment-start) 1))
+ (save-excursion
+ (if (cddr syntax) (goto-char (cddr syntax)))
+ (beginning-of-line)
+ (if (looking-at "[ \t]") 2 3))
+ (length (car syntax)))
+ nil nil))
+ '("-" "" "" 0)))
+
+
+;;;===========================================================================
+;;; Inserting
+;;;===========================================================================
+
+(defun template-insert-newline (string &optional limit start-limit)
+ "Deletes blank lines around point and insert STRING.
+After optional LIMIT and before optional START-LIMIT, no character will
+be deleted."
+ (let ((start (save-excursion
+ (skip-chars-backward " \t\n\f" start-limit)
+ (or (bobp) (forward-line 1))
+ (point)))
+ (end (save-excursion
+ (skip-chars-forward " \t\n\f" limit)
+ (beginning-of-line)
+ (point))))
+ (if (> end start) (delete-region start end)))
+ (or (bobp) (insert string)))
+
+(defun template-insert-separator (separator &optional cstring syntax)
+ "Insert separator line at point.
+If CSTRING is not nil, insert in special line which starts with CSTRING.
+Insert SEPARATOR repeatedly. End the line with COMMENT-END as specified
+in `template-comment-syntax'."
+ (when separator
+ (when cstring
+ (open-line 1)
+ (insert cstring)
+ (template-indent-according-to-mode))
+ (end-of-line)
+ (let* ((estring (cadr syntax))
+ (max-column (if estring
+ template-max-column-with-end
+ template-max-column))
+ (max (- (if (> max-column 0) max-column (+ fill-column max-column))
+ (length separator)
+ (length estring))))
+ (while (<= (current-column) max) (insert separator))
+ (if (>= (length separator) (- (current-column) max))
+ (insert (substring separator 0 (- max (current-column)))))
+ (if estring (insert estring))
+ (if cstring (forward-line 1)))))
+
+
+;;;===========================================================================
+;;; Adaptations: cc-mode
+;;;===========================================================================
+
+;; There isn't really anything I can do against the filling of "/**" in C, C++
+;; and Antlr mode (it is correct in Java), it should be done in the cc-mode
+;; package. Similar for filling "*/" with the previous line...
+
+(defun template-c-fill-paragraph (&optional arg)
+ ;; checkdoc-params: (arg)
+ "Like \\[c-fill-paragraph] but handles comment separator lines."
+ (let* ((regexp (concat "\\|[ \t]*\\(/[*/]\\|\\*\\)[ \t]*"
+ (template-comment-separator-regexp '("/*" "*/"))))
+ (paragraph-start (concat paragraph-start regexp)) ;#dynamic
+ (paragraph-separate (concat paragraph-separate regexp)))
+ (c-fill-paragraph arg)))
+
+(defun template-c-init-fill-function ()
+ "Set `fill-paragraph-function' to use `template-c-fill-paragraph'."
+ (when (boundp 'fill-paragraph-function)
+ (make-local-variable 'fill-paragraph-function)
+ (setq fill-paragraph-function 'template-c-fill-paragraph)))
+
+
+
+;;;;##########################################################################
+;;;; Updating (File Name in Header)
+;;;;##########################################################################
+
+
+;;;===========================================================================
+;;; General updating
+;;;===========================================================================
+
+(defun template-update-buffer-region (limit regexp group)
+ "Return region = (BEG . END) in buffer to be updated.
+If LIMIT is positive, check first LIMIT characters in buffer, otherwise
+check last -LIMIT characters in buffer for a text to be matched by
+REGEXP. Return region according to GROUP's regexp group in REGEXP."
+ (let ((case-fold-search nil))
+ (goto-char (if limit
+ (if (natnump limit) (point-min) (+ (point-max) limit))
+ (point-min)))
+ (when (re-search-forward regexp
+ (if (natnump limit)
+ (+ (point-min) limit)
+ (point-max))
+ t)
+ (cons (match-beginning group) (match-end group)))))
+
+(defun template-match-modes-or-regexp (modes-or-regexp)
+ "Return non-nil, if the current buffer passes MODES-OR-REGEXP.
+If MODES-OR-REGEXP is a list, it must include the current `major-mode',
+if it is a regexp, it must match the `buffer-file-name' without version,
+otherwise it must be non-nil."
+ (if (stringp modes-or-regexp)
+ (and buffer-file-name
+ (string-match modes-or-regexp
+ (file-name-sans-versions buffer-file-name)))
+ (or (nlistp modes-or-regexp) (memq major-mode modes-or-regexp))))
+
+(defun template-update-buffer (&optional arg)
+ "Update buffer according to `template-update-buffer-alist'.
+Do not do anything if `template-auto-update-disable-regexp' matches the
+file name or if `template-auto-update' is nil. When optional ARG is
+non-nil, i.e., if called interactively *without* prefix arg, always
+update."
+ (interactive (list (null current-prefix-arg)))
+ (when (or arg
+ (and template-auto-update buffer-file-name
+ (null (and template-auto-update-disable-regexp
+ (string-match template-auto-update-disable-regexp
+ buffer-file-name)))))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (let ((alist template-update-buffer-alist)
+ (case-fold-search (memq system-type '(vax-vms ms-dos windows-nt)))
+ stamp prompt region new)
+ (while alist
+ (setq stamp (pop alist))
+ (condition-case nil
+ (and (template-match-modes-or-regexp (pop stamp))
+ ;; Run TEST ---------------------------------------------
+ (setq prompt (pop stamp)
+ region (pop stamp) ; TEST
+ region (eval (if (or (atom region)
+ (functionp (car region)))
+ region
+ (cons 'template-update-buffer-region
+ region))))
+ (if (stringp (setq new (eval (pop stamp))))
+ (null (string= (buffer-substring (car region)
+ (cdr region))
+ new))
+ (car stamp))
+ ;; user confirmation, replacement -----------------------
+ (or (null prompt)
+ arg
+ (eq template-auto-update t)
+ (y-or-n-p (format prompt (buffer-name))))
+ (progn
+ (goto-char (car region))
+ (if (car stamp)
+ (funcall (car stamp) new (car region) (cdr region))
+ (delete-region (car region) (cdr region))
+ (insert new))))
+ (error nil))))))))
+
+
+;;;===========================================================================
+;;; Update header
+;;;===========================================================================
+
+;;;###autoload
+(defun template-update-header (&optional show)
+ "Replace old file name in header with current file name.
+If SHOW is t, just return region of the filename or nil. Otherwise,
+replace filename if possible and signal an error if SHOW is nil and
+there is no filename in the header. See `template-header-lines' and
+`template-header-regexp-alist'."
+ (interactive "*P")
+ (if buffer-file-name
+ (save-excursion
+ (goto-char (point-min))
+ (let ((case-fold-search nil)
+ (comment-regexp (template-default-comment)) ; at `point-min'!
+ (end (progn (forward-line template-header-lines) (point)))
+ (alist template-header-regexp-alist)
+ (disallowed "")
+ group)
+ (if (string-match "[A-Za-z]\\|.." comment-regexp)
+ (setq comment-regexp (regexp-quote comment-regexp)
+ disallowed "")
+ (or (eq comment-regexp '(?\]))
+ (setq disallowed comment-regexp))
+ (setq comment-regexp (concat (regexp-quote comment-regexp) "+")))
+ (while alist
+ (goto-char (point-min))
+ (if (re-search-forward (format (caar alist)
+ comment-regexp disallowed)
+ end t)
+ (setq group (cdar alist)
+ alist nil)
+ (setq alist (cdr alist))))
+ (if (and group (match-beginning group))
+ (if (eq show t)
+ (cons (match-beginning group) (match-end group))
+ (goto-char (match-beginning group))
+ (delete-region (point) (match-end group))
+ (insert (file-name-sans-versions
+ (file-name-nondirectory buffer-file-name)))
+ t)
+ (if show nil (error "No file name in header")))))
+ (if show nil (error "Buffer is not visiting a file"))))
+
+
+
+;;;;##########################################################################
+;;;; Templates
+;;;;##########################################################################
+
+
+(defvar template-history nil
+ "History, used by `template-read'.")
+
+(defvar template-choice-history nil
+ "History, used by `template-choice'.")
+
+(put 'normal-mode 'template-secure-command t)
+
+(defvar template-all-templates nil
+ "Internal variable. Template files used for template derivation.")
+(defvar template-file nil
+ "Partitioned name of new file: (DIR FILE RAW NUMBER EXT).
+Internal variable. DIR is the directory part, FILE the file name
+without directory part. FILE consists of its extension EXT, RAW and a
+numbering NUMBER just in front of the extension. It is used by the
+expansions DIR, FILE, FILE_SANS, FILE_EXT and others in
+`template-expansion-alist'. Also useful for user defined functions in
+`template-derivation-alist' and the per-template definition section.")
+
+(defvar template-modified nil
+ "Internal variable. Whether user is asked during the expansion process.")
+(defvar template-secure t
+ "Internal variable. Whether all per-template definitions are secure.")
+(defvar template-point-messages nil
+ "Internal variable. List of lines for temporary message at point.")
+(defvar template-before-messages nil
+ "Internal variable. List of lines for temporary message before expansion.")
+(defvar template-after-messages nil
+ "Internal variable. List of lines for temporary message after expansion.")
+
+(defvar template-point nil
+ "Internal variable. Position of point. Set with expansion form P.")
+(defvar template-mark nil
+ "Internal variable. Position of mark. Set with expansion form M.")
+
+(defvar template-current nil
+ "Internal variable. Current key of expansion form.")
+(defvar template-string-alist nil
+ "Internal variable. Alist of user inputs for `template-read'.")
+(defvar template-register-alist nil
+ "Internal variable. Alist of used registers.")
+(defvar template-local-alist nil
+ "Internal variable. Alist of per-template defined expansions.")
+
+(defvar template-ffap-file-finder nil
+ "Value used inside `template-ffap-find-file'.
+If nil, initialize it to the value of `ffap-file-finder', i.e., this
+variable holds the original value of that variable which will be set to
+`template-ffap-find-file' in `template-initialize'.")
+
+
+;;;===========================================================================
+;;; Functions: `find-file'/`insert-file-contents', hooking into `find-file'
+;;;===========================================================================
+
+(defun template-find-template (filename &optional replace)
+ "Switch to a buffer visiting template file FILENAME.
+If optional REPLACE is non-nil, replace the current buffer contents with
+the contents of file FILENAME.
+
+This function always considers template files as text files."
+ (let ((file-name-buffer-file-type-alist nil)) ; Emacs on DOS/NT
+ (if replace
+ (insert-file-contents filename nil nil nil
+ ;; 5th arg not t with empty accessible part
+ ;; (XEmacs bug workaround: would infloop)
+ (> (point-max) (point-min)))
+ (let ((template-auto-insert nil))
+ (switch-to-buffer (find-file-noselect filename))))))
+
+(defun template-not-found-function ()
+ "Use a template when visiting a non-existent file.
+See `template-auto-insert' and `template-find-file-commands'. Function
+in `find-file-not-found-hooks'."
+ (and template-auto-insert (not buffer-read-only) (bobp) (eobp)
+ (or (memq this-command template-find-file-commands)
+ (and (memq this-command template-file-select-commands)
+ ;; thanks to Dave Love <d.love@dl.ac.uk>:
+ (memq (car-safe (car command-history))
+ ;; To always include `find-file-at-point', use ffap
+ ;; initialization (see `template-ffap-find-file')
+ template-find-file-commands)))
+ (let ((template (cdr (template-derivation buffer-file-name t t))))
+ (and template
+ (file-readable-p template)
+ (or (eq template-auto-insert t)
+ (y-or-n-p
+ (format "Use template %s? "
+ (cond-emacs-xemacs
+ (abbreviate-file-name template :XEMACS t)))))
+ (progn
+ (template-new-file nil template)
+ (setq this-command 'session-disable)
+ t)))))
+
+(defun template-ffap-find-file (filename)
+ "Function to use in `ffap-file-finder'.
+Add an entry to `command-history' if necessary and call function in
+`template-ffap-file-finder' with argument FILENAME."
+ (or (memq (car-safe (car command-history))
+ '(ffap find-file-at-point))
+ (setq command-history
+ (cons (list 'find-file-at-point filename) command-history)))
+ (if (eq template-ffap-file-finder 'template-ffap-find-file)
+ (find-file filename)
+ (funcall template-ffap-file-finder filename)))
+
+
+;;;===========================================================================
+;;; Main function
+;;;===========================================================================
+
+(defun template-expand-template-interactive ()
+ (let* ((use (template-derivation (expand-file-name
+ (or buffer-file-name "NONE"))
+ t))
+ (tpl (read-file-name "Insert and expand template: "
+ (file-name-directory (cdr use))
+ (file-name-nondirectory (cdr use))
+ t
+ (file-name-nondirectory (cdr use)))))
+ (if (string= tpl "")
+ (error "No template file provided"))
+ (list (expand-file-name tpl (file-name-directory (cdr use))))))
+
+;;;###autoload
+(defun template-expand-template (template)
+ "Expand template file TEMPLATE and insert result in current buffer.
+Using a template for inserting some text consists of:
+ 1. Template derivation: suggest a reasonable template file to the user
+ according to `buffer-file-name', see `template-derivation-alist'.
+ 2. Template insertion: insert the template file at point into the
+ current buffer.
+ 3.. as steps 6.. of `template-new-file'."
+ (interactive (template-expand-template-interactive))
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (template-new-file nil template t)))
+
+(defun template-new-file-interactive ()
+ "Interactive specification for `template-new-file'.
+Return \(FILE TEMPLATE)."
+ (let* ((inp (read-file-name (if current-prefix-arg
+ "New file (+template, no name change): "
+ "New file (+template): ")
+ nil ""))
+ (use (cond ((equal inp "")
+ (error "Empty/no input"))
+ ((file-directory-p inp)
+ (error "%S is a directory" inp))
+ (t (template-derivation (expand-file-name inp)
+ current-prefix-arg))))
+ (tpl (read-file-name (format "File %s uses template: "
+ (file-name-nondirectory (car use)))
+ (file-name-directory (cdr use))
+ (file-name-nondirectory (cdr use))
+ t
+ (file-name-nondirectory (cdr use)))))
+ (list (car use)
+ (if (string= tpl "")
+ nil
+ (expand-file-name tpl (file-name-directory (cdr use)))))))
+
+;;;###autoload
+(defun template-new-file (file template &optional with-undo)
+ "Open a new file FILE by using a TEMPLATE.
+Using a template for creating a new file consists of, steps 1 to 3 are
+only executed when called interactively:
+ 1. Prompt for the name of the new file.
+ 2. Template derivation: suggest a reasonable template file to the user
+ see `template-derivation-alist'.
+ 3. File name refinement: e.g., if the given file name is \"exercise\"
+ and there are two files \"exercise1.tex\" and \"exercise2.tex\" in
+ the same directory and if we have a template \"exercise.tex.tpl\",
+ the file name is refined to \"exercise3.tex\". This is turned off
+ when \\[template-new-file] is called with a prefix argument.
+ 4. Template insertion: insert the template file into the empty buffer.
+ 5. Read per-template expansion definition section starting at
+ `template-definition-start' and delete it.
+ 6. Display :before message in `template-message-buffer'.
+ 7. Execute pre-expansion commands defined in the definition section.
+ 8. Set local variables defined in the definition section.
+ 9. Expansion: expand the expansion forms (text matched by
+ `template-expansion-regexp') They are defined in the definition
+ section, in `template-expansion-alist', or provided by default, see
+ `template-expansion-regexp' and `template-register-regexp'.
+ 10. Execute post-expansion commands defined in the definition section.
+ 11. Run `normal-mode' and functions in `find-file-hooks'.
+ 12. Update header according to `template-update-header' with argument
+ `if-exists'.
+ 13. Display :after message in `template-message-buffer'.
+ 14. Report: display a temporary message at point defined in the
+ definition section and an automatically generated message in the
+ minibuffer area, see `template-message-timeout'.
+
+If optional WITH-UNDO is non-nil, store corresponding changes in
+`buffer-undo-list'. If FILE is nil, the buffer for FILE has already
+been created and the accessible part will be replaced by the expanded
+template. If TEMPLATE is nil (empty input when called interactively),
+do not use a template."
+ (interactive (template-new-file-interactive))
+ ;; check template and file name --------------------------------------------
+ (if template
+ (if (file-readable-p template)
+ (if (file-directory-p template)
+ (error "Template %s is a directory" template))
+ (if (null (yes-or-no-p (format "Template %s does not exist. Create? "
+ template)))
+ (error "No template file to use")
+ (template-make-directory (file-name-directory template))
+ (template-find-template template)
+ (error "You should create this template first"))))
+ (if (not file)
+ (switch-to-buffer (current-buffer))
+ (and (or (get-file-buffer file) (file-exists-p file))
+ (null (yes-or-no-p (format "File %s exists. Delete contents? " file)))
+ (error "Cannot use templates for existing files"))
+ (let ((auto-mode-alist nil)
+ (enable-local-variables nil)
+ (find-file-not-found-hooks nil)
+ (enable-local-eval nil))
+ (switch-to-buffer (find-file-noselect file))))
+ (when template
+ (or with-undo (setq buffer-undo-list t))
+ (template-find-template template t)
+ (template-new-file-0 with-undo)))
+
+(defun template-new-file-0 (with-undo)
+ "Perform template replacements in current buffer.
+If WITH-UNDO is non-nil, store corresponding changes in
+`buffer-undo-list'."
+ ;; start replacement -------------------------------------------------------
+ (or with-undo (set-buffer-modified-p nil))
+ (goto-char (point-min))
+ (setq template-secure t
+ template-point nil
+ template-mark nil
+ template-modified nil
+ template-point-messages nil
+ template-before-messages nil
+ template-after-messages nil
+ template-local-alist nil
+ template-register-alist nil
+ template-string-alist nil)
+ (let ((form-selector nil)
+ (pre-command-list nil)
+ (post-command-list nil)
+ (local-variable-list nil)
+ val)
+ ;; read per-template definition section ----------------------------------
+ (goto-char (point-min))
+ (when (re-search-forward
+ (concat "^[ \t]*" template-definition-start "[ \t]*$") nil t)
+ (condition-case ()
+ (while t
+ (setq val (read (current-buffer)))
+ (cond (;; ("KEY" . xxx): ask user --------------------------------
+ (and (consp val) (stringp (car val)))
+ (let* ((def (cdr val)) ; expansion forms
+ (msg (cond ((null template-message-prompt-format)
+ nil)
+ ((stringp def) def)
+ ((and (consp def) (stringp (car def)))
+ (car def)))))
+ (when msg ; list prompts in before-messages
+ (or template-before-messages
+ (null template-message-prompt-intro)
+ (push template-message-prompt-intro
+ template-before-messages))
+ (push (format template-message-prompt-format msg)
+ template-before-messages))
+ (push (cons (car val) (template-translate-definition def))
+ template-local-alist)))
+ ;; :before, :after, :eval-before, :eval-after --------------
+ ((null val) ; nil is deprecated
+ (setq form-selector
+ (cond ((null form-selector) :old-before)
+ ((eq form-selector :old-before) :old-after)
+ ((eq form-selector :old-after)
+ (error "More than two (obsolete) nil forms"))
+ (t
+ (error "Used obsolete nil form with new form selectors")))))
+ ((memq val '(:before :after :eval-before :eval-after))
+ (setq form-selector val))
+ ;; "MESSAGE" -----------------------------------------------
+ ((stringp val)
+ (cond ((eq form-selector :before)
+ (push val template-before-messages))
+ ((eq form-selector :after)
+ (push val template-after-messages))
+ (t
+ (push val template-point-messages))))
+ ;; (CHAR . xxx): set register ------------------------------
+ ((and (consp val) (template-char-or-char-int-p (car val)))
+ (let ((reg (template-char-or-int-to-char (car val))))
+ (if (atom (cdr val))
+ (set-register reg (cdr val))
+ (set-register reg (cadr val))
+ (when template-message-register-format
+ (let ((msg (format template-message-register-format
+ reg (cadr val)
+ (or (caddr val) ""))))
+ (if template-message-buffer
+ (progn
+ (if template-before-messages
+ (push msg template-before-messages))
+ (or template-after-messages
+ (null template-message-register-intro)
+ (push template-message-register-intro
+ template-after-messages))
+ (push msg template-after-messages))
+ (push msg template-point-messages)))))))
+ ;; set var, execute command and sexpr ----------------------
+ ((and (memq form-selector '(nil :before :after))
+ (consp val)
+ (symbolp (car val)))
+ (or (and (functionp (get (car val) 'template-secure-value))
+ (funcall (get (car val) 'template-secure-value)
+ (cdr val)))
+ (setq template-secure nil))
+ (push val local-variable-list))
+ ((memq form-selector '(:eval-before :old-before))
+ (push (template-elisp-in-definition val)
+ pre-command-list))
+ ((memq form-selector '(:eval-after :old-after))
+ (push (template-elisp-in-definition val)
+ post-command-list))
+ (t
+ (error "Illegal form"))))
+ (error nil))
+ (skip-chars-forward " \t\n\f")
+ (or (eobp)
+ (error "Invalid definition in line %d (pos %d) of the template file"
+ (count-lines 1 (point)) (point)))
+ (or template-secure
+ (null (default-value template-confirm-insecure))
+ (y-or-n-p "Have you checked the template functions? ")
+ (error "Failed security check"))
+ (delete-region (match-beginning 0) (point-max)))
+ ;; expand ----------------------------------------------------------------
+ (template-display-messages template-before-messages)
+ (eval (cons 'progn (nreverse pre-command-list)))
+ (while local-variable-list
+ (make-local-variable (caar local-variable-list))
+ (set (caar local-variable-list) (cdar local-variable-list))
+ (setq local-variable-list (cdr local-variable-list)))
+ (goto-char (point-min))
+ (while (re-search-forward template-expansion-regexp nil t)
+ (setq template-current (buffer-substring (match-beginning 1)
+ (match-end 1))
+ val (assoc template-current template-local-alist))
+ (unless val
+ (if (setq val (assoc template-current template-key-alias-alist))
+ (setq template-current (cdr val)))
+ (setq val (or (assoc template-current template-expansion-alist)
+ (assoc template-current
+ template-default-expansion-alist))))
+ (delete-region (match-beginning 0) (match-end 0))
+ (cond (val
+ (eval (cons 'progn (cdr val))))
+ ((string-match template-register-regexp template-current)
+ (template-register))
+ (t
+ (template-read (format "Replacement for `%s': "
+ template-current)))))
+ (eval (cons 'progn (nreverse post-command-list)))
+ (save-restriction
+ (widen)
+ (normal-mode t)
+ (or with-undo (template-update-header 'if-exists))
+ (run-hooks 'find-file-hooks))
+ ;; message ---------------------------------------------------------------
+ (template-display-messages template-after-messages)
+ (cond ((null template-register-alist)
+ (message "%s, no buffer location in register"
+ (if template-mark "Mark set" "No mark")))
+ (t (message "%s, buffer location in register: %s"
+ (if template-mark "Mark set" "No mark")
+ (mapconcat (function
+ (lambda (x)
+ (if (cdr x)
+ (concat (char-to-string (car x)) "*")
+ (char-to-string (car x)))))
+ (nreverse template-register-alist)
+ ", "))))
+ (or with-undo (set-buffer-modified-p template-modified))
+ (goto-char (point-min))
+ (when template-point
+ (goto-char template-point)
+ (set-marker template-point nil))
+ (when template-mark
+ (push-mark template-mark)
+ (set-marker template-mark nil)
+ (if (fboundp 'zmacs-activate-region) (zmacs-activate-region)))
+ (when (and template-point-messages
+ (or (cdr template-point-messages)
+ (not (string-equal (car template-point-messages) ""))))
+ (let ((beg (point))
+ end)
+ (if (cdr template-point-messages)
+ (insert (mapconcat 'identity
+ (nreverse template-point-messages)
+ "\n")
+ "\n")
+ (insert (car template-point-messages)))
+ (setq end (point))
+ (goto-char beg)
+ (and (fboundp 'make-extent) (fboundp 'set-extent-face)
+ (set-extent-face (make-extent beg end) 'template-message-face))
+ (recenter)
+ (sit-for template-message-timeout)
+ (delete-region beg end))))
+ (recenter)
+ (unless with-undo
+ (setq buffer-undo-list nil)
+ (set-buffer-modified-p template-modified)))
+
+(defun template-display-messages (messages)
+ (when (and messages template-message-buffer)
+ (setq messages (nreverse messages))
+ (with-output-to-temp-buffer template-message-buffer
+ (while messages
+ (princ (pop messages))
+ (if messages (princ "\n"))))))
+
+
+;;;===========================================================================
+;;; Determine name of the new file and the template
+;;;===========================================================================
+
+(defun template-derivation (full arg &optional no-default)
+ "Derive template file name and do file name refinement.
+Return (REFINED . TEMPLATE) where REFINED is the refined version of FULL
+and TEMPLATE and template file name, see `template-derivation-alist'.
+FULL is the initial file name given by the user. File name refinement
+is turned off when ARG is non-nil. If optional argument NO-DEFAULT is
+non-nil, return nil instead (FULL \. \"~/.templates/DEFAULT.tpl\") if no
+matching entry can be found in `template-derivation-alist'."
+ ;; Get all templates -------------------------------------------------------
+ (setq template-all-templates nil)
+ (let* ((dir (file-name-directory full))
+ (len (length dir))
+ (case-fold-search (memq system-type '(vax-vms ms-dos windows-nt))))
+ (while (and dir
+ (not (and template-stop-derivation
+ (fboundp template-stop-derivation)
+ (funcall template-stop-derivation dir))))
+ (template-all-templates template-subdirectories dir)
+ (setq dir (file-name-directory (directory-file-name dir)))
+ (or (> len (setq len (length dir)))
+ (setq dir nil)))
+ (template-all-templates template-default-directories)
+ (setq template-all-templates (nreverse template-all-templates)))
+ ;; Get template file -------------------------------------------------------
+ (if (string= (file-name-nondirectory full) "")
+ (error "You cannot use templates for directories"))
+ (setq template-file (template-split-filename full))
+ (let ((tests template-derivation-alist)
+ test template file)
+ (while tests
+ (setq test (caar tests)
+ file (cdar tests))
+ (if (setq template
+ (if (functionp (car test))
+ (apply (car test) (cdr test))
+ (apply 'template-default-template test)))
+ (setq tests nil)
+ (setq tests (cdr tests))))
+ (if template
+ (or arg
+ (if (functionp (car file))
+ (apply (car file) template (cdr file))
+ (apply 'template-unique-file template file)))
+ (or no-default
+ (setq template (template-split-filename
+ "DEFAULT"
+ (template-default-directory)))))
+ (if template
+ (cons (expand-file-name (cadr template-file) (car template-file))
+ (expand-file-name (concat (cadr template) template-extension)
+ (car template))))))
+
+(defun template-default-directory ()
+ "Return directory of file \"DEFAULT.tpl\"."
+ (let ((dirs template-default-directories)
+ (name (concat "DEFAULT" template-extension))
+ dir)
+ (while dirs
+ (setq dir (pop dirs))
+ (if (file-readable-p (expand-file-name name dir))
+ (setq dirs nil)
+ (setq dir nil)))
+ (or dir
+ (car template-default-directories)
+ (expand-file-name "~/.templates/"))))
+
+
+;;;===========================================================================
+;;; Small functions
+;;;===========================================================================
+
+(defun template-make-directory (dir)
+ "Create DIR if it does not exists yet."
+ (cond ((file-exists-p dir))
+ ((yes-or-no-p (format "The directory %s does not exist. Create? " dir))
+ (make-directory dir t))
+ (t (error "You should create a directory \"%s\"" dir)))
+ dir)
+
+(defun template-split-filename (file &optional dir)
+ "Split file name into its parts.
+If DIR is nil, FILE is a fully expanded file name, otherwise FILE is a
+file name without its directory part DIR. See `template-file'."
+ (or dir (setq dir (template-make-directory (file-name-directory file))
+ file (file-name-nondirectory file)))
+ (let* ((ext (string-match "\\.[^.]*\\'" file))
+ (raw (substring file 0 ext))
+ (num (string-match "[^0-9][0-9]+\\'" raw)))
+ (if num
+ (list dir file
+ (substring raw 0 (1+ num))
+ (substring raw (1+ num))
+ (if ext (substring file ext) ""))
+ (list dir file raw "" (if ext (substring file ext) "")))))
+
+(defun template-translate-definition (def)
+ "Translate DEF of expansion and set `template-secure' accordingly."
+ (cond ((null def) ; zero form
+ nil)
+ ((template-char-or-char-int-p def)
+ `((template-register ,def)))
+ ((stringp def)
+ `((template-read ,def nil nil nil t)))
+ ((symbolp def)
+ `((insert (if (stringp ,def) ,def template-string-default))))
+ ((and (consp def) (stringp (car def)))
+ (if (consp (car-safe (cdr def)))
+ `((template-choice ,(car def) (quote ,(cdr def))))
+ `((apply (quote template-read) (quote ,def)))))
+ ((consp (car-safe def))
+ (setq template-secure nil)
+ def)
+ (t
+ (list (template-elisp-in-definition (car def) (cdr def))))))
+
+(defun template-elisp-in-definition (def &optional prefix)
+ "Return valid elisp definition and set `template-secure' accordingly.
+DEF is the elisp form, PREFIX would be the prefix argument if DEF is a
+command."
+ (cond ((consp def)
+ (setq template-secure nil)
+ def)
+ ((or (symbolp def) (vectorp def))
+ (or (and (symbolp def) (get def 'template-secure-command))
+ (setq template-secure nil))
+ (if (and (symbolp def)
+ (functionp (get def 'template-secure-command))
+ (listp prefix)
+ (funcall (get def 'template-secure-command) prefix))
+ `(apply (quote ,def) (quote ,prefix))
+ `(progn (setq prefix-arg (quote ,prefix))
+ (command-execute (quote ,def)))))
+ (t
+ (error "Illegal form"))))
+
+
+;;;===========================================================================
+;;; Compute template name
+;;;===========================================================================
+
+(defun template-all-templates (dirs &optional base)
+ "Read names of template files in DIRS relatively to BASE.
+Insert the names to internal variable `template-all-templates'."
+ (let ((regexp (concat (regexp-quote template-extension) "\\'"))
+ (endpos (- (length template-extension)))
+ dir templates)
+ (while dirs
+ (setq dir (expand-file-name (car dirs) base)
+ dirs (cdr dirs))
+ (cond-emacs-xemacs
+ (and (file-accessible-directory-p dir)
+ (file-readable-p dir)
+ (setq templates (directory-files dir t regexp :XEMACS nil t))
+ (while templates
+ (and :EMACS
+ (not (file-directory-p (car templates)))
+ :BOTH
+ (file-readable-p (car templates))
+ (push (template-split-filename (substring (car templates)
+ 0
+ endpos))
+ template-all-templates))
+ (setq templates (cdr templates))))))))
+
+(defun template-set-template-part (part file-part)
+ "Set template part according to definition PART and FILE-PART.
+See `template-derivation-alist' for details."
+ (when part
+ (cond ((stringp part) part)
+ ((eq part t) file-part)
+ ((null (string= file-part "")) file-part))))
+
+(defun template-default-template (&optional raw num ext regexp)
+ "Return template according to RAW, NUM, EXT and REGEXP.
+See `template-derivation-alist' for details."
+ (if (or (null regexp) (string-match regexp (cadr template-file)))
+ (let ((templates template-all-templates)
+ (file-rne (cddr template-file))
+ result template-rne)
+ (setq raw (template-set-template-part raw (car file-rne))
+ num (template-set-template-part num (cadr file-rne))
+ ext (template-set-template-part ext (caddr file-rne)))
+ (while templates
+ (setq template-rne (cddar templates))
+ (if (and (or (null raw) (string= (car template-rne) raw))
+ (or (null num) (string= (cadr template-rne) num))
+ (or (null ext) (string= (caddr template-rne) ext)))
+ (setq result (car templates)
+ templates nil)
+ (setq templates (cdr templates))))
+ result)))
+
+
+;;;===========================================================================
+;;; File name refinement
+;;;===========================================================================
+
+(defun template-default-file (template &optional raw num ext)
+ "Refine file name according to TEMPLATE, RAW, NUM and EXT.
+The result is in `template-file'. See `template-derivation-alist'."
+ (let ((template-rne (cddr template))
+ (file-rne (cddr template-file)))
+ (if raw
+ (if (eq raw t) (setq raw (car template-rne)))
+ (setq raw (car file-rne)))
+ (if num
+ (if (eq num t) (setq num (cadr template-rne)))
+ (setq num (cadr file-rne)))
+ (if ext
+ (if (eq ext t) (setq ext (caddr template-rne)))
+ (setq ext (caddr file-rne)))
+ (setcdr template-file (list (concat raw num ext) raw num ext))))
+
+(defunx template-unique-file (template &optional raw num ext auto-num)
+ "Refine file name according to TEMPLATE, RAW, NUM, EXT and AUTO-NUM.
+Use auto numbering if NUM is not \"\" or AUTO-NUM is non-nil. The
+result is in `template-file'. See `template-derivation-alist'."
+ (template-default-file template raw num ext)
+ (let* ((dir (car template-file))
+ (full (expand-file-name (cadr template-file) dir)))
+ (when (if (string= (fourth template-file) "")
+ auto-num
+ (setq auto-num
+ (and (or (get-file-buffer full)
+ (file-readable-p full))
+ (string-to-int (fourth template-file)))))
+ (setq auto-num (1- auto-num)
+ raw (third template-file)
+ ext (fifth template-file))
+ (let ((list (buffer-list))
+ file1 dir1)
+ (while list
+ (and (setq file1 (buffer-file-name (car list)))
+ (setq dir1 (file-name-directory file1))
+ (string= dir1 dir)
+ (setq auto-num
+ (max (template-filename-number
+ (cddr (template-split-filename
+ (file-name-nondirectory file1)
+ dir1))
+ raw ext)
+ auto-num)))
+ (setq list (cdr list)))
+ (setq list (directory-files dir nil nil t :XEMACS t))
+ (while list
+ (unless (:EMACS file-directory-p (car list))
+ (setq auto-num
+ (max (template-filename-number
+ (cddr (template-split-filename (car list) dir))
+ raw ext)
+ auto-num)
+ list (cdr list))))
+ (template-default-file template raw
+ (int-to-string (1+ auto-num))
+ ext)))))
+
+(defun template-filename-number (file-rne raw ext)
+ "Return numbering in FILE-RNE if the RAW and EXT parts are equal."
+ (or (and (string= (car file-rne) raw)
+ (string= (caddr file-rne) ext)
+ (string-to-int (cadr file-rne)))
+ 0))
+
+
+;;;===========================================================================
+;;; Safe commands for per-template expansions
+;;;===========================================================================
+
+(defun template-insert-time (&optional format default)
+ "Insert time into current buffer using time format FORMAT.
+If FORMAT is not a string, it uses DEFAULT or `current-time-string'."
+ (interactive)
+ (insert (if (and (stringp format) (fboundp 'format-time-string))
+ (format-time-string format (current-time))
+ (or default (current-time-string)))))
+(put 'template-insert-time 'template-secure-command
+ (lambda (args)
+ (or (null args) (and (stringp (car args)) (null (cdr args))))))
+
+
+;;;===========================================================================
+;;; Functions for the predefined expansions
+;;;===========================================================================
+
+(defun template-register (&optional register)
+ "Set current location in register REGISTER.
+That is, \\[jump-to-register] REGISTER jumps to the current position.
+If REGISTER is nil, use register corresponding to the last character in
+`template-current'."
+ (let* ((char (if register
+ (template-char-or-int-to-char register)
+ (aref template-current (1- (length template-current)))))
+ (elem (assoc char template-register-alist)))
+ (point-to-register char)
+ (if elem
+ (setcdr elem t)
+ (push (list char) template-register-alist))))
+
+(defun template-read (prompt &optional prefix suffix default again-p)
+ "Ask user with PROMPT for a STRING to be inserted.
+If STRING is not \"\", insert PREFIX STRING SUFFIX, otherwise DEFAULT.
+If AGAIN-P is nil, do not ask if `template-current' appears another time
+as key in a expansion form. If AGAIN-P is `expand', the inserted region
+is searched for expansion forms where STRING is marked as a literal
+environment, see `template-literal-environment'."
+ (setq template-modified t)
+ (let ((pos (point))
+ (elem (and (null again-p)
+ (assoc template-current template-string-alist))))
+ (if elem
+ (setq elem (cdr elem))
+ (setq elem (read-from-minibuffer prompt nil nil nil
+ 'template-history)
+ elem (cond ((string= elem "") (or default ""))
+ ((eq again-p 'expand)
+ (concat prefix
+ (format template-expansion-format
+ (car template-literal-environment))
+ elem
+ (format template-expansion-format
+ (cdr template-literal-environment))
+ suffix
+ (format template-expansion-format
+ (car template-literal-environment))
+ (format template-expansion-format
+ (cdr template-literal-environment))))
+ (t
+ (concat prefix elem suffix))))
+ (or again-p (push (cons template-current elem) template-string-alist)))
+ (insert elem)
+ (if (eq again-p 'expand) (goto-char pos))))
+
+(defun template-choice (prompt table)
+ "Ask user with PROMPT for a choice and insert it.
+Each element in TABLE looks like (ANSWER . TEXT). Ask for an input with
+completion over all ANSWERs and insert corresponding TEXT if ANSWER is a
+string, otherwise ask a \"y or n\" question and use the result of
+`y-or-n-p' as ANSWER. Expansion forms in TEXT will be expanded."
+ (setq template-modified t)
+ (let ((pos (point)))
+ (insert (or (cdr (assoc (if (stringp (caar table))
+ (completing-read prompt table nil t nil
+ 'template-choice-history)
+ (y-or-n-p prompt))
+ table))
+ "")
+ (format template-expansion-format
+ (car template-literal-environment))
+ (format template-expansion-format
+ (cdr template-literal-environment)))
+ (goto-char pos)))
+
+
+;;;===========================================================================
+;;; Menu filter
+;;;===========================================================================
+
+(defun template-menu-filter (menu-items)
+ ;; checkdoc-params: (menu-items)
+ "Menu filter for `template-creation-menu'."
+ (let ((alist (append template-expansion-alist
+ template-default-expansion-alist))
+ menu used key)
+ (while alist
+ (unless (member (setq key (car (pop alist))) used)
+ (push key used)
+ (push (vector (concat "Insert " key)
+ (list 'template-insert-form current-prefix-arg key)
+ t)
+ menu)))
+ (append menu-items (nreverse menu))))
+
+
+;;;===========================================================================
+;;; Insert and define forms
+;;;===========================================================================
+
+(defun template-buffer-template-p ()
+ "Return non-nil, if current buffer is likely to be a template file."
+ (and buffer-file-name
+ (string-match (concat (regexp-quote template-extension) "\\'")
+ (file-name-sans-versions buffer-file-name))))
+
+(defun template-open-template ()
+ "If current buffer is no template file, open a new one."
+ (interactive)
+ (if (template-buffer-template-p)
+ (barf-if-buffer-read-only)
+ (let (name
+ (dir (and (car template-subdirectories)
+ (expand-file-name (car template-subdirectories)))))
+ (if (null buffer-file-name)
+ (setq name (concat "TEMPLATE" template-extension))
+ (setq name (file-name-sans-versions
+ (file-name-nondirectory buffer-file-name)))
+ (if (string-match ".\\.[^.]*\\'" name)
+ (setq name (concat "TEMPLATE"
+ (substring name (1+ (match-beginning 0)))
+ template-extension))
+ (setq name (concat name template-extension)
+ ;; dot file => template not specific for directory
+ dir (car template-default-directories))))
+ (setq name (read-file-name "Open template file (empty=none): "
+ dir nil nil name))
+ (or (string= name "")
+ (template-find-template name)))))
+
+(defun template-insert-form (arg key)
+ "Insert an expansion form according to KEY into template.
+When called interactively, allow completion over all keys in
+`template-expansion-alist' and `template-default-expansion-alist'.
+If prefix ARG is nil, run `template-open-template' first."
+ (interactive
+ (list current-prefix-arg
+ (completing-read "Insert key (0-9 for register position): "
+ (append template-expansion-alist
+ template-default-expansion-alist))))
+ (or arg (template-open-template))
+ (insert (format template-expansion-format key))
+ (if (equal key (car template-literal-environment))
+ (let ((pos (point)))
+ (insert (format template-expansion-format
+ (cdr template-literal-environment)))
+ (goto-char pos))))
+
+(defun template-define-start (arg &rest args)
+ "Insert a definition section and definition into template.
+See `template-definition-start'. If ARGS is non-nil, pass ARGS to
+`format' for a new definition. If prefix ARG is nil, run
+`template-open-template' first."
+ (interactive "P")
+ (or arg (template-open-template))
+ (save-excursion
+ (goto-char (point-min))
+ (unless (re-search-forward (concat "^[ \t]*"
+ template-definition-start
+ "[ \t]*$") nil t)
+ (goto-char (point-max))
+ (or (bolp) (insert "\n"))
+ (insert template-definition-start))
+ (goto-char (point-max))
+ (or (bolp) (insert "\n"))
+ (if args (insert (apply 'format args) "\n")))
+ (message "Put definition at the end of the template"))
+
+(defun template-define-message (arg message)
+ "Insert a temporary message MESSAGE definition into template.
+For ARG, see `template-define-start'."
+ (interactive "P\nsTemporary message: ")
+ (template-define-start arg "%S" message))
+
+(defun template-define-prompt (arg key prompt &optional prefix suffix default)
+ "Insert a definition for KEY as PROMPT into template.
+For ARG, see `template-define-start'."
+ (interactive "P\nsExpansion key: \nsExpansion prompt: \nsPrefix for non-empty input: \nsSuffix for non-empty input: \nsDefault for empty input: ")
+ (template-define-start arg "(%S %S %S %S %S)"
+ key prompt prefix suffix default))
+
+(defun template-define-register (arg register)
+ "Insert a setting of REGISTER into template.
+For ARG, see `template-define-start'."
+ (interactive "P\ncDefine register: ")
+ (let* ((old (get-register register))
+ (contents (read-from-minibuffer "Register contents: "
+ (and (stringp old)
+ (not (string-match "\n" old))
+ old)))
+ (comment (read-from-minibuffer "Comment (empty=none): ")))
+ (if (string= comment "")
+ (template-define-start arg "(%S %S)" register contents)
+ (template-define-start arg "(%S %S %S)" register contents comment))))
+
+
+;;;===========================================================================
+;;; Initialization
+;;;===========================================================================
+
+;; easymenu.el is for top-level menus only...
+(defunx template-add-submenu (menu &optional where)
+ "Add the submenu MENU to the end of a menu in WHERE in the menubar.
+WHERE is a list of menus tried to add MENU to. If no such menu exist,
+no menu is added. When using Emacs, always add to the \"Edit\" menu.
+See `easy-menu-define' for the format of MENU."
+ (and menu
+ :EMACS
+ (>= emacs-major-version 21)
+ (boundp 'menu-bar-edit-menu)
+ (let ((keymap (easy-menu-create-menu (car menu) (cdr menu))))
+ ;; `easy-menu-get-map' doesn't get the right one => use hard-coded
+ (define-key-after menu-bar-edit-menu (vector (intern (car menu)))
+ (cons 'menu-item
+ (cons (car menu)
+ (if (not (symbolp keymap))
+ (list keymap)
+ (cons (symbol-function keymap)
+ (get keymap 'menu-prop)))))))
+ :XEMACS
+ (featurep 'menubar)
+ (let ((current-menubar default-menubar) path)
+ (while where
+ (setq path (list (pop where)))
+ (if (find-menu-item default-menubar path)
+ (setq where nil)
+ (setq path nil)))
+ (when path (add-submenu path menu)))))
+
+;;;###autoload
+(defunx template-initialize (&rest dummies)
+ ;; checkdoc-params: (dummies)
+ "Initialized package template. See variable `template-initialize'."
+ (interactive)
+ (setq template-use-package t)
+ (let ((regexp (concat (regexp-quote template-extension) "\\'")))
+ (or (assoc regexp auto-mode-alist)
+ (push (list regexp nil 'template-new-file) auto-mode-alist)))
+ (when (or (eq template-initialize t)
+ (memq 'cc-mode template-initialize))
+ (add-hook 'c-mode-common-hook 'template-c-init-fill-function)
+ (add-hook 'antlr-mode-hook 'template-c-init-fill-function))
+ (when (or (eq template-initialize t)
+ (memq 'de-html-helper template-initialize))
+ (setq html-helper-build-new-buffer nil)
+ (setq html-helper-do-write-file-hooks nil))
+ (when (or (eq template-initialize t)
+ (memq 'keys template-initialize))
+ (condition-case nil ; older Emacses don't understand all
+ (progn
+ (define-key ctl-x-map "t" 'template-new-file)
+ (define-key ctl-x-map [(control =)] 'template-single-comment)
+ (define-key ctl-x-map [(control ?\;)] 'template-block-comment))
+ (error nil)))
+ (when (or (eq template-initialize t)
+ (memq 'menus template-initialize))
+ (template-add-submenu template-comment-menu :XEMACS '("Edit"))
+ (template-add-submenu template-creation-menu :XEMACS '("Cmds" "Edit"))
+ :EMACS
+ (and (boundp 'menu-bar-files-menu)
+ (define-key-after menu-bar-files-menu [template-new-file]
+ '(menu-item "New File Using Template..." template-new-file
+ :enable (not (window-minibuffer-p
+ (frame-selected-window
+ menu-updating-frame)))
+ :help "Create a new file, using a template")
+ 'dired))
+ :XEMACS
+ (and (featurep 'menubar)
+ (find-menu-item default-menubar '("File"))
+ (let ((current-menubar default-menubar))
+ ;; XEmacs-20.4 `add-submenu' does not have 4th arg IN-MENU
+ (add-menu-button '("File")
+ ["New File Using Template..." template-new-file
+ :active t]
+ "Insert File..."))))
+ (if (and (boundp 'init-file-loaded) init-file-loaded)
+ ;; doesn't exist in Emacs
+ (template-after-init)
+ (add-hook 'after-init-hook 'template-after-init t)))
+
+(defun template-after-init ()
+ "Late initialization for package template.
+See function and variable `template-initialize'."
+ (when (or (eq template-initialize t)
+ (memq 'auto template-initialize))
+ (add-hook 'write-file-hooks 'template-update-buffer)
+ (add-hook 'find-file-not-found-hooks 'template-not-found-function t))
+ (when (or (eq template-initialize t)
+ (memq 'ffap template-initialize))
+ (or template-ffap-file-finder
+ (setq template-ffap-file-finder
+ (if (boundp 'ffap-file-finder)
+ ffap-file-finder
+ (or (get 'ffap-file-finder 'saved-value) 'find-file))))
+ (setq ffap-file-finder 'template-ffap-find-file)))
+
+;;; Local IspellPersDict: .ispell_template
+;;; template.el ends here
diff --git a/lisp/themes/color-themes-alex.el b/lisp/themes/color-themes-alex.el
new file mode 100644
index 0000000..3f3795b
--- /dev/null
+++ b/lisp/themes/color-themes-alex.el
@@ -0,0 +1,48 @@
+;; -*- self-compile-mode: t -*-
+
+(eval-when-compile
+ (require 'color-theme))
+
+(defun color-theme-alex ()
+ "Color theme by Alexander Sulfrian, created 2012-03-14."
+ (interactive)
+ (color-theme-install
+ '(color-theme-alex
+ ((foreground-color . "grey90")
+ (background-color . "black")
+ (background-mode . dark))
+ (border ((t (:background "gray50"))))
+ (diff-removed ((t (:inherit diff-changed :foreground "red3"))))
+ (diff-added ((t (:inherit diff-changed :foreground "Lime green"))))
+ (diff-header ((t (:weight bold :background nil))))
+ (fixed-pitch ((t (:family "terminus"))))
+ (font-lock-comment-face ((nil (:foreground "green3"))))
+ (font-lock-constant-face ((nil (:weight bold))))
+ (font-lock-negation-char-face ((t (:foreground "red" :weight bold))))
+ (font-lock-preprocessor-face ((t (:inherit font-lock-builtin-face :foreground "magenta"))))
+ (font-lock-string-face ((nil (:foreground "red2"))))
+ (font-lock-warning-face ((t (:foreground "Red" :weight bold))))
+ (fringe ((t (:background "gray10"))))
+ (highlight ((nil (:background "grey10"))))
+ (linum ((t (:background "gray10" :foreground "gray50" :height 0.8))))
+ (magit-item-highlight ((t (:background "gray10"))))
+ (mode-line ((t (:box (:line-width 1 :color "grey75")))))
+ (mode-line-highlight ((((class color) (min-colors 88)) (:box (:line-width 2 :color "grey40" :style released-button)))))
+ (mode-line-inactive ((default (:inherit mode-line :foreground "gray60")) (nil nil)))
+ (region ((((class color) (min-colors 88) (background dark)) (:inverse-video t))))
+ (scroll-bar ((t (:background "black" :foreground "gray25")))))))
+
+(defun color-theme-alex-console ()
+ "Color theme by Alexander Sulfrian for console, created 2012-03-14."
+ (interactive)
+ (color-theme-alex)
+ (color-theme-install
+ '(color-theme-alex-console
+ ()
+ (default ((t (:background nil :foreground "white"))))
+ (linum ((t (:background nil :foreground "white" :box nil
+ :strike-through nil :overline nil :underline nil
+ :slant normal :weight normal))))
+ (region ((nil (:inverse-video t)))))))
+
+(provide 'color-themes-alex)
diff --git a/lisp/themes/color-themes-monokai-alex.el b/lisp/themes/color-themes-monokai-alex.el
new file mode 100644
index 0000000..21bc4c3
--- /dev/null
+++ b/lisp/themes/color-themes-monokai-alex.el
@@ -0,0 +1,33 @@
+;; -*- self-compile-mode: t -*-
+
+(eval-when-compile
+ (require 'color-theme))
+
+(defun color-theme-monokai-alex ()
+ "Color theme by Alexander Sulfrian base on monokai"
+ (interactive)
+ (color-theme-monokai)
+ (let ((color-theme-is-cumulative t))
+ (color-theme-install
+ '(color-theme-monokai-alex
+ ((background-color . "black")
+ (background-mode . dark))
+ (font-lock-keyword-face ((t (:foreground "#66D9EF"))))
+ (font-lock-type-face ((t (:weight bold :slant italic :foreground "#66D9EF"))))
+ (linum ((t (:height 0.8 :inherit (default)))))
+ (scroll-bar ((t (:foreground "gray20" :background "black"))))
+
+ (mode-line ((((class color) (min-colors 88))
+ (:foreground "black" :background "grey75")
+ (t (:inverse-video t)))))
+ (mode-line-inactive (((default
+ (:inherit (mode-line)))
+ (((class color) (min-colors 88)
+ (background light))
+ (:background "grey90" :foreground "grey20"))
+ (((class color) (min-colors 88)
+ (background dark))
+ (:background "grey30" :foreground "grey80")))))
+ ))))
+
+(provide 'color-themes-monokai-alex)
diff --git a/lisp/winring.el b/lisp/winring.el
new file mode 100644
index 0000000..baac31f
--- /dev/null
+++ b/lisp/winring.el
@@ -0,0 +1,597 @@
+;;; winring.el --- Window configuration rings
+
+;; Copyright (C) 1998 Free Software Foundation, Inc.
+
+;; Author: 1997-1998 Barry A. Warsaw
+;; Maintainer: bwarsaw@python.org
+;; Created: March 1997
+;; Keywords: frames tools
+
+(defconst winring-version "3.5"
+ "winring version number.")
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 package provides lightweight support for circular rings of
+;; window configurations. A window configuration is the layout of
+;; windows and associated buffers within a frame. There is always at
+;; least one configuration on the ring, the current configuration.
+;; You can create new configurations and cycle through the layouts in
+;; either direction. You can also delete configurations from the ring
+;; (except the last one of course!). Window configurations are named,
+;; and you can jump to and delete named configurations. Display of
+;; the current window configuration name in the mode line is only
+;; supported as of Emacs 20.3 and XEmacs 21.0.
+;;
+;; Window configuration rings are frame specific. That is, each frame
+;; has its own ring which can be cycled through independently of other
+;; frames. This is the way I like it.
+;;
+;; You are always looking at the current window configuration for each
+;; frame, which consists of the windows in the frame, the buffers in
+;; those windows, and point in the current buffer. As you run
+;; commands such as "C-x 4 b", "C-x 2", and "C-x 0" you are modifying
+;; the current window configuration. When you jump to a new
+;; configuration, the layout that existed before the jump is captured,
+;; and the ring is rotated to the selected configuration. Window
+;; configurations are captured with `current-window-configuration',
+;; however winring also saves point for the current buffer.
+
+;; To use, make sure this file is on your `load-path' and put the
+;; following in your .emacs file:
+;;
+;; (require 'winring)
+;; (winring-initialize)
+;;
+;; Note that by default, this binds the winring keymap to the C-x 7
+;; prefix, but you can change this by setting the value of
+;; `winring-keymap-prefix', before you call `winring-initialize'.
+;; Note that this is a change from previous versions of winring; the
+;; prefix used to be M-o but was changed on the suggestion of RMS.
+
+;; The following commands are defined:
+;;
+;; C-x 7 n -- Create a new window configuration. The new
+;; configuration will contain a single buffer, the one
+;; named in the variable `winring-new-config-buffer-name'
+;;
+;; With C-u, winring prompts for the name of the new
+;; configuration. If you don't use C-u the function in
+;; `winring-name-generator' will be called to get the
+;; new configuration's name.
+;;
+;; C-x 7 2 -- Create a duplicate of the current window
+;; configuration. C-u has the same semantics as with
+;; "C-x 7 c".
+;;
+;; C-x 7 j -- Jump to a named configuration (prompts for the name).
+;;
+;; C-x 7 0 -- Kill the current window configuration and rotate to the
+;; previous layout on the ring. You cannot delete the
+;; last configuration in the ring. With C-u, prompts
+;; for the name of the configuration to kill.
+;;
+;; C-x 7 o -- Go to the next configuration on the ring.
+;;
+;; C-x 7 p -- Go to the previous configuration on the ring.
+;;
+;; Note that the sequence `C-x 7 o C-x 7 p' is a no-op;
+;; it leaves you in the same configuration you were in
+;; before the sequence.
+;;
+;; C-x 7 r -- Rename the current window configuration.
+;;
+;; C-x 7 b -- Submit a bug report on winring.
+;;
+;; C-x 7 v -- Echo the winring version.
+
+;; As mentioned, window configuration names can be displayed in the
+;; modeline, but this feature only works with Emacs 20.3 and XEmacs
+;; 21.0. A patch for XEmacs 20.4 to support this feature is available
+;; at the URL below. Note that the default value of
+;; `winring-show-names' is currently nil by default because if your
+;; X/Emacs doesn't have the necessary support, ugly things can happen
+;; (no you won't crash your X/Emacs -- it just won't do what you
+;; want).
+;;
+;; If your X/Emacs has the necessary support, you can turn on display
+;; of window configuration names by setting `winring-show-names' to
+;; t. If you don't like the position in the modeline where winring
+;; names are shown, you can change this by passing in your own
+;; modeline hacker function to `winring-initialize'.
+
+;;; Winring on the Web:
+;;
+;; The winring Web page (including the aforementioned XEmacs 20.4
+;; patch) is
+;;
+;; http://www.python.org/emacs/winring/
+
+;;; History:
+;;
+;; A long long time ago there was a package called `wicos' written by
+;; Heikki Suopanki, which was based on yet another earlier package
+;; called `screens' also written by Suopanki. This in turn was based
+;; on the Unix tty session manager `screen' (unrelated to Emacs) by
+;; Oliver Laumann, Juergen Weigert, and Michael Schroeder.
+;;
+;; Wicos essentially provided fancy handling for window
+;; configurations. I liked the basic ideas, but wicos broke with
+;; later versions of Emacs and XEmacs. I re-implemented just the
+;; functionality I wanted, simplifying things in the process, and
+;; porting the code to run with XEmacs 19 and 20, and Emacs 20 (I
+;; don't know if winring works in Emacs 19.34).
+;;
+;; Wicos used the M-o prefix which I've recently changed to C-x 7 as
+;; the default, by suggestion of RMS. Wicos also had some support for
+;; multiple frames, and saving configurations on all visible frames,
+;; but it didn't work too well, and I like frame independent rings
+;; better.
+;;
+;; I know of a few other related packages:
+;;
+;; - `escreen' by Noah Friedman. A much more ambitious package
+;; that does Emacs window session management. Very cool, but I
+;; wanted something more lightweight.
+;;
+;; - `wconfig' by Bob Weiner as part of Hyperbole. I think wconfig
+;; is similar in spirit to winring; it seems to have also have
+;; named window configurations, but not frame-specific window
+;; rings.
+;;
+;; - `winner' by Ivar Rummelhoff. This package comes with Emacs
+;; 20, and appears to differ from winring by providing undo/redo
+;; semantics to window configuration changes. winner is a minor
+;; mode and does seem to support frame-specific window rings.
+;;
+;; - `window-xemacs' by the XEmacs Development Team. It appears
+;; that this package, which is specific to XEmacs (and perhaps
+;; just XEmacs 20) implements stacks of window configurations
+;; which are frame independent.
+
+;; Please feel free to email me if my rendition of history, or my
+;; explanation of the related packages, is inaccurate.
+
+;;; Code:
+
+(require 'ring)
+
+
+(defgroup winring nil
+ "Window configuration rings"
+ :prefix "winring-"
+ :group 'frames)
+
+(defcustom winring-ring-size 7
+ "*Size of the window configuration ring."
+ :type 'integer
+ :group 'winring)
+
+(defcustom winring-prompt-on-create 'usually
+ "*When true, prompt for new configuration name on creation.
+If not t and not nil, prompt for configuration name on creation,
+except when creating the initial configuration on a new frame."
+ :type '(radio
+ (const :tag "Never prompt for configuration name" nil)
+ (const :tag "Always prompt for configuration name" t)
+ (const :tag "Prompt for all but initial configuration name"
+ usually)
+ )
+ :group 'winring)
+
+(defcustom winring-new-config-buffer-name "*scratch*"
+ "*Name of the buffer to switch to when a new configuration is created."
+ :type 'string
+ :group 'winring)
+
+(defcustom winring-show-names nil
+ "*If non-nil, window configuration names are shown in the modeline.
+If nil, the name is echoed in the minibuffer when switching window
+configurations."
+ :type 'boolean
+ :group 'winring)
+
+(defcustom winring-name-generator 'winring-next-name
+ "*Function that generates new automatic window configuration names.
+When a new window configuration is created with `winring-new-configuration',
+and the user did not specify an explicit name, this function is called with
+no arguments to get the new name. It must return a string."
+ :type 'function
+ :group 'winring)
+
+;; Not yet customized
+(defvar winring-keymap-prefix "\C-x7"
+ "*Prefix key that the `winring-map' is placed on in the global keymap.
+If you change this, you must do it before calling `winring-initialize'.")
+
+
+;; Set up keymap
+(defvar winring-map nil
+ "Keymap used for winring, window configuration rings.")
+(if winring-map
+ nil
+ (setq winring-map (make-sparse-keymap))
+ (define-key winring-map "b" 'winring-submit-bug-report)
+ (define-key winring-map "n" 'winring-new-configuration)
+ (define-key winring-map "2" 'winring-duplicate-configuration)
+ (define-key winring-map "j" 'winring-jump-to-configuration)
+ (define-key winring-map "0" 'winring-delete-configuration)
+ (define-key winring-map "o" 'winring-next-configuration)
+ (define-key winring-map "p" 'winring-prev-configuration)
+ (define-key winring-map "r" 'winring-rename-configuration)
+ (define-key winring-map "v" 'winring-version)
+ )
+
+
+
+;; Winring names
+(defvar winring-name nil
+ "The name of the currently displayed window configuration.")
+
+(defvar winring-name-index 1
+ "Index used as a sequence number for new unnamed window configurations.")
+
+(defvar winring-name-history nil
+ "History variable for window configuration name prompts.")
+
+(defun winring-next-name ()
+ (let ((name (format "%03d" winring-name-index)))
+ (setq winring-name-index (1+ winring-name-index))
+ name))
+
+
+
+;; Compatibility
+(defun winring-set-frame-ring (frame ring)
+ (cond
+ ;; XEmacs
+ ((fboundp 'set-frame-property)
+ (set-frame-property frame 'winring-ring ring))
+ ;; Emacs
+ ((fboundp 'modify-frame-parameters)
+ (modify-frame-parameters frame (list (cons 'winring-ring ring))))
+ ;; Not supported
+ (t (error "This version of Emacs is not supported by winring"))))
+
+(defun winring-get-frame-ring (frame)
+ (cond
+ ;; XEmacs
+ ((fboundp 'frame-property)
+ (frame-property frame 'winring-ring))
+ ;; Emacs 20
+ ((fboundp 'frame-parameter)
+ (frame-parameter frame 'winring-ring))
+ ;; Emacs 19.34
+ ((fboundp 'frame-parameters)
+ (cdr (assq 'winring-ring (frame-parameters frame))))
+ ;; Unsupported
+ (t (error "This version of Emacs is not supported by winring"))))
+
+(defun winring-create-frame-hook (frame)
+ ;; generate the name, but specify the newly created frame
+ (winring-set-name (and (eq winring-prompt-on-create t)
+ (read-string "Initial window configuration name? "
+ nil 'winring-name-history))
+ frame))
+
+
+;; Utilities
+(defun winring-set-name (&optional name frame)
+ "Set the window configuration name.
+Optional NAME is the name to use; if not given, then
+`winring-name-generator' is `funcall'd with no arguments to get the
+generated name. Optional FRAME is the frame to set the name for; if
+not given then the currently selected frame is used."
+ (let ((name (or name (funcall winring-name-generator)))
+ (frame (or frame (selected-frame))))
+ (if (fboundp 'add-spec-to-specifier)
+ ;; The XEmacs way. Only supported in hacked 20.4 or 21.0
+ (add-spec-to-specifier winring-name name frame)
+ ;; the Emacs way. Only supported in Emacs 20.3
+ (setq winring-name name)
+ (modify-frame-parameters frame (list (cons 'winring-name name)))
+ ))
+ (if (not winring-show-names)
+ (message "Switching to window configuration: %s" name)))
+
+(defun winring-get-ring ()
+ (let* ((frame (selected-frame))
+ (ring (winring-get-frame-ring frame)))
+ (when (not ring)
+ (setq ring (make-ring winring-ring-size))
+ (winring-set-frame-ring frame ring))
+ ring))
+
+(defsubst winring-name-of (config)
+ (car config))
+
+(defsubst winring-conf-of (config)
+ (car (cdr config)))
+
+(defsubst winring-point-of (config)
+ (nth 2 config))
+
+(defsubst winring-name-of-current ()
+ (if (fboundp 'specifier-instance)
+ ;; In XEmacs, this variable holds a specifier which
+ ;; must be instanced to get the current
+ ;; configuration name.
+ (specifier-instance winring-name)
+ ;; In Emacs, just use the variable's string value
+ ;; directly, since the `displayed' value is kept as a
+ ;; frame parameter
+ winring-name))
+
+(defun winring-save-current-configuration (&optional at-front)
+ (let* ((ring (winring-get-ring))
+ (name (winring-name-of-current))
+ (here (point))
+ (conf (list name (current-window-configuration) here)))
+ (if at-front
+ (ring-insert-at-beginning ring conf)
+ (ring-insert ring conf))))
+
+(defun winring-restore-configuration (item)
+ (let ((conf (winring-conf-of item))
+ (name (winring-name-of item))
+ (here (winring-point-of item)))
+ (set-window-configuration conf)
+ ;; current-window-configuration does not save point in current
+ ;; window. That sucks!
+ (goto-char here)
+ (winring-set-name name))
+ (force-mode-line-update))
+
+(defun winring-complete-name ()
+ (let* ((ring (winring-get-ring))
+ (n (1- (ring-length ring)))
+ (current (winring-name-of-current))
+ (table (list (cons current -1)))
+ name)
+ ;; populate the completion table
+ (while (<= 0 n)
+ (setq table (cons (cons (winring-name-of (ring-ref ring n)) n) table)
+ n (1- n)))
+ (setq name (completing-read
+ (format "Window configuration name (%s): " current)
+ table nil 'must nil 'winring-name-history))
+ (if (string-equal name "")
+ (setq name current))
+ (cdr (assoc name table))))
+
+(defun winring-read-name (prompt)
+ (let* ((ring (winring-get-ring))
+ (n (1- (ring-length ring)))
+ (table (list (winring-name-of-current)))
+ name)
+ ;; get the list of all the names in the ring
+ (while (<= 0 n)
+ (setq table (cons (winring-name-of (ring-ref ring n)) table)
+ n (1- n)))
+ (setq name (read-string prompt nil 'winring-name-history))
+ (if (member name table)
+ (error "Window configuration name already in use: %s" name))
+ name))
+
+
+;; Commands
+
+;;;###autoload
+(defun winring-new-configuration (&optional arg)
+ "Save the current window configuration and create an empty new one.
+The buffer shown in the new empty configuration is defined by
+`winring-new-config-buffer-name'.
+
+With \\[universal-argument] prompt for the new configuration's name.
+Otherwise, the function in `winring-name-generator' will be called to
+get the new configuration's name."
+ (interactive "P")
+ (let ((name (and (or arg winring-prompt-on-create)
+ (winring-read-name "New window configuration name? "))))
+ ;; Empty string is not allowed
+ (if (string-equal name "")
+ (setq name (funcall winring-name-generator)))
+ (winring-save-current-configuration)
+ (delete-other-windows)
+ (switch-to-buffer winring-new-config-buffer-name)
+ (winring-set-name name)))
+
+;;;###autoload
+(defun winring-duplicate-configuration (&optional arg)
+ "Push the current window configuration on the ring, and duplicate it.
+
+With \\[universal-argument] prompt for the new configuration's name.
+Otherwise, the function in `winring-name-generator' will be called to
+get the new configuration's name."
+ (interactive "P")
+ (let ((name (and (or arg winring-prompt-on-create)
+ (winring-read-name "New window configuration name? "))))
+ ;; Empty string is not allowed
+ (if (string-equal name "")
+ (setq name (funcall winring-name-generator)))
+ (winring-save-current-configuration)
+ (winring-set-name name)))
+
+;;;###autoload
+(defun winring-next-configuration ()
+ "Switch to the next window configuration for this frame."
+ (interactive)
+ (let ((next (ring-remove (winring-get-ring))))
+ (winring-save-current-configuration)
+ (winring-restore-configuration next)))
+
+;;;###autoload
+(defun winring-prev-configuration ()
+ "Switch to the previous window configuration for this frame."
+ (interactive)
+ (let ((prev (ring-remove (winring-get-ring) 0)))
+ (winring-save-current-configuration 'at-front)
+ (winring-restore-configuration prev)))
+
+;;;###autoload
+(defun winring-jump-to-configuration ()
+ "Go to the named window configuration."
+ (interactive)
+ (let* ((ring (winring-get-ring))
+ (index (winring-complete-name))
+ item)
+ ;; if the current configuration was chosen, winring-complete-name
+ ;; returns -1
+ (when (<= 0 index)
+ (setq item (ring-remove ring index))
+ (winring-save-current-configuration)
+ (winring-restore-configuration item))
+ ))
+
+;;;###autoload
+(defun winring-delete-configuration (&optional arg)
+ "Delete the current configuration and switch to the next one.
+With \\[universal-argument] prompt for named configuration to delete."
+ (interactive "P")
+ (let ((ring (winring-get-ring))
+ index)
+ (if (or (not arg)
+ (> 0 (setq index (winring-complete-name))))
+ ;; remove the current one, so install the next one
+ (winring-restore-configuration (ring-remove ring))
+ ;; otherwise, remove the named one but don't change the current config
+ (ring-remove ring index)
+ )))
+
+;;;###autoload
+(defun winring-rename-configuration (name)
+ "Rename the current configuration to NAME."
+ (interactive "sNew window configuration name? ")
+ (winring-set-name name))
+
+
+
+(defconst winring-help-address "bwarsaw@python.org"
+ "Address accepting bug report submissions.")
+
+(defun winring-version ()
+ "Echo the current version of winring in the minibuffer."
+ (interactive)
+ (message "Using winring version %s" winring-version)
+ ;;(setq zmacs-region-stays t)
+ )
+
+(defun winring-submit-bug-report (comment-p)
+ "Submit via mail a bug report on winring.
+With \\[universal-argument] just send any type of comment."
+ (interactive
+ (list (not (y-or-n-p
+ "Is this a bug report? (hit `n' to send other comments) "))))
+ (let ((reporter-prompt-for-summary-p (if comment-p
+ "(Very) brief summary: "
+ t)))
+ (require 'reporter)
+ (reporter-submit-bug-report
+ winring-help-address ;address
+ (concat "winring " winring-version) ;pkgname
+ ;; varlist
+ (if comment-p nil
+ '(winring-ring-size
+ winring-new-config-buffer-name
+ winring-show-names
+ winring-name-generator
+ winring-keymap-prefix))
+ nil ;pre-hooks
+ nil ;post-hooks
+ "Dear Barry,") ;salutation
+ (if comment-p nil
+ (set-mark (point))
+ (insert
+"Please replace this text with a description of your problem.\n\
+The more accurately and succinctly you can describe the\n\
+problem you are encountering, the more likely I can fix it\n\
+in a timely way.\n\n")
+ (exchange-point-and-mark)
+ ;;(setq zmacs-region-stays t)
+ )))
+
+
+
+;; Initialization. This is completely different b/w Emacs and XEmacs.
+;; The Emacs 20.3 way is to create a frame-local variable (this is a
+;; new feature with Emacs 20.3), and save the config name as a frame
+;; property.
+;;
+;; In XEmacs 21.0 (a.k.a. 20.5), you create a generic specifier, and
+;; save the config name as an instantiator over the current frame
+;; locale.
+
+;; Be sure to do this only once
+(defvar winring-initialized nil)
+
+(defun winring-initialize (&optional hack-modeline-function)
+ (unless winring-initialized
+ ;;
+ ;; Create the variable that holds the window configuration name
+ ;;
+ (cond
+ ;; The Emacs 20.3 way: frame-local variables
+ ((fboundp 'make-variable-frame-local)
+ (make-variable-frame-local 'winring-name))
+ ;; The XEmacs 21 way: specifiers
+ ((fboundp 'make-specifier)
+ (setq winring-name (make-specifier 'generic)))
+ ;; Not supported in older X/Emacsen
+ (t nil))
+ ;;
+ ;; Glom the configuration name into the mode-line. I've
+ ;; experimented with a couple of different locations, including
+ ;; for Emacs 20.3 mode-line-frame-identification, and for XEmacs,
+ ;; just splicing it before the modeline-buffer-identification.
+ ;; Sticking it on the very left side of the modeline, even before
+ ;; mode-line-modified seems like the most useful and
+ ;; cross-compatible place.
+ ;;
+ ;; Note that you can override the default hacking of the modeline
+ ;; by passing in your own `hack-modeline-function'.
+ ;;
+ (if hack-modeline-function
+ (funcall hack-modeline-function)
+ ;; Else, default insertion hackery
+ (let ((format (list 'winring-show-names
+ '("<" winring-name "> ")))
+ (splice (cdr mode-line-format)))
+ (setcar splice (list format (car splice)))))
+ ;;
+ ;; We need to add a hook so that all newly created frames get
+ ;; initialized properly. Again, different for Emacs and XEmacs.
+ ;;
+ (if (boundp 'create-frame-hook)
+ ;; XEmacs
+ (add-hook 'create-frame-hook 'winring-create-frame-hook)
+ ;; better be Emacs!
+ (add-hook 'after-make-frame-functions 'winring-create-frame-hook))
+ ;;
+ ;; Now set the initial configuration name on the initial frame...
+ (winring-create-frame-hook (selected-frame))
+ ;; ...the keymap...
+ (global-set-key winring-keymap-prefix winring-map)
+ ;; ...and the init fence
+ (setq winring-initialized t)))
+
+
+
+(provide 'winring)
+;;; winring.el ends here
diff --git a/templates/TEMPLATE.py.tpl b/templates/TEMPLATE.py.tpl
new file mode 100644
index 0000000..aa033a1
--- /dev/null
+++ b/templates/TEMPLATE.py.tpl
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+
+(>>>POINT<<<)