From 0786ae76879c18744431ed53aa60e6bba82f137f Mon Sep 17 00:00:00 2001 From: Tom Willemsen Date: Sun, 26 Jun 2011 12:41:49 +0200 Subject: EMACS: New modes, functions and keys Added lua-mode Added muttrc-mode Moved all functions to emacs.d/functions.el Added go-mode Set keys M-left, M-right, M-up and M-down to move to relative windows --- emacs.d/elisp/go-mode.el | 544 ++++++++++++++ emacs.d/elisp/muttrc-mode.el | 1638 ++++++++++++++++++++++++++++++++++++++++++ emacs.d/functions.el | 191 +++++ emacs.el | 235 +----- 4 files changed, 2397 insertions(+), 211 deletions(-) create mode 100644 emacs.d/elisp/go-mode.el create mode 100644 emacs.d/elisp/muttrc-mode.el create mode 100644 emacs.d/functions.el diff --git a/emacs.d/elisp/go-mode.el b/emacs.d/elisp/go-mode.el new file mode 100644 index 0000000..059f783 --- /dev/null +++ b/emacs.d/elisp/go-mode.el @@ -0,0 +1,544 @@ +;;; go-mode.el --- Major mode for the Go programming language + +;;; Commentary: + +;; For installation instructions, see go-mode-load.el + +;;; To do: + +;; * Indentation is *almost* identical to gofmt +;; ** We think struct literal keys are labels and outdent them +;; ** We disagree on the indentation of function literals in arguments +;; ** There are bugs with the close brace of struct literals +;; * Highlight identifiers according to their syntactic context: type, +;; variable, function call, or tag +;; * Command for adding an import +;; ** Check if it's already there +;; ** Factor/unfactor the import line +;; ** Alphabetize +;; * Remove unused imports +;; ** This is hard, since I have to be aware of shadowing to do it +;; right +;; * Format region using gofmt + +;;; Code: + +(eval-when-compile (require 'cl)) + +(defvar go-mode-syntax-table + (let ((st (make-syntax-table))) + ;; Add _ to :word: character class + (modify-syntax-entry ?_ "w" st) + + ;; Operators (punctuation) + (modify-syntax-entry ?+ "." st) + (modify-syntax-entry ?- "." st) + (modify-syntax-entry ?* "." st) + (modify-syntax-entry ?/ "." st) + (modify-syntax-entry ?% "." st) + (modify-syntax-entry ?& "." st) + (modify-syntax-entry ?| "." st) + (modify-syntax-entry ?^ "." st) + (modify-syntax-entry ?! "." st) + (modify-syntax-entry ?= "." st) + (modify-syntax-entry ?< "." st) + (modify-syntax-entry ?> "." st) + + ;; Strings + (modify-syntax-entry ?\" "\"" st) + (modify-syntax-entry ?\' "\"" st) + (modify-syntax-entry ?` "\"" st) + (modify-syntax-entry ?\\ "\\" st) + + ;; Comments + (modify-syntax-entry ?/ ". 124b" st) + (modify-syntax-entry ?* ". 23" st) + (modify-syntax-entry ?\n "> b" st) + (modify-syntax-entry ?\^m "> b" st) + + st) + "Syntax table for Go mode.") + +(defvar go-mode-keywords + '("break" "default" "func" "interface" "select" + "case" "defer" "go" "map" "struct" + "chan" "else" "goto" "package" "switch" + "const" "fallthrough" "if" "range" "type" + "continue" "for" "import" "return" "var") + "All keywords in the Go language. Used for font locking and +some syntax analysis.") + +(defvar go-mode-font-lock-keywords + (let ((builtins '("cap" "close" "closed" "len" "make" "new" + "panic" "panicln" "print" "println")) + (constants '("nil" "true" "false" "iota")) + (type-name "\\s *\\(?:[*(]\\s *\\)*\\(?:\\w+\\s *\\.\\s *\\)?\\(\\w+\\)") + ) + `((,(regexp-opt go-mode-keywords 'words) . font-lock-keyword-face) + (,(regexp-opt builtins 'words) . font-lock-builtin-face) + (,(regexp-opt constants 'words) . font-lock-constant-face) + ;; Function names in declarations + ("\\\\s *\\(\\w+\\)" 1 font-lock-function-name-face) + ;; Function names in methods are handled by function call pattern + ;; Function names in calls + ;; XXX Doesn't match if function name is surrounded by parens + ("\\(\\w+\\)\\s *(" 1 font-lock-function-name-face) + ;; Type names + ("\\\\s *\\(\\w+\\)" 1 font-lock-type-face) + (,(concat "\\\\s *\\w+\\s *" type-name) 1 font-lock-type-face) + ;; Arrays/slices/map value type + ;; XXX Wrong. Marks 0 in expression "foo[0] * x" +;; (,(concat "]" type-name) 1 font-lock-type-face) + ;; Map key type + (,(concat "\\\\s *\\(?:<-\\)?" type-name) 1 font-lock-type-face) + ;; new/make type + (,(concat "\\<\\(?:new\\|make\\)\\>\\(?:\\s \\|)\\)*(" type-name) 1 font-lock-type-face) + ;; Type conversion + (,(concat "\\.\\s *(" type-name) 1 font-lock-type-face) + ;; Method receiver type + (,(concat "\\\\s *(\\w+\\s +" type-name) 1 font-lock-type-face) + ;; Labels + ;; XXX Not quite right. Also marks compound literal fields. + ("^\\s *\\(\\w+\\)\\s *:\\(\\S.\\|$\\)" 1 font-lock-constant-face) + ("\\<\\(goto\\|break\\|continue\\)\\>\\s *\\(\\w+\\)" 2 font-lock-constant-face))) + "Basic font lock keywords for Go mode. Highlights keywords, +built-ins, functions, and some types.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Key map +;; + +(defvar go-mode-map + (let ((m (make-sparse-keymap))) + (define-key m "}" #'go-mode-insert-and-indent) + (define-key m ")" #'go-mode-insert-and-indent) + (define-key m ":" #'go-mode-delayed-electric) + ;; In case we get : indentation wrong, correct ourselves + (define-key m "=" #'go-mode-insert-and-indent) + m) + "Keymap used by Go mode to implement electric keys.") + +(defun go-mode-insert-and-indent (key) + "Invoke the global binding of KEY, then reindent the line." + + (interactive (list (this-command-keys))) + (call-interactively (lookup-key (current-global-map) key)) + (indent-according-to-mode)) + +(defvar go-mode-delayed-point nil + "The point following the previous insertion if the insertion +was a delayed electric key. Used to communicate between +`go-mode-delayed-electric' and `go-mode-delayed-electric-hook'.") +(make-variable-buffer-local 'go-mode-delayed-point) + +(defun go-mode-delayed-electric (p) + "Perform electric insertion, but delayed by one event. + +This inserts P into the buffer, as usual, then waits for another key. +If that second key causes a buffer modification starting at the +point after the insertion of P, reindents the line containing P." + + (interactive "p") + (self-insert-command p) + (setq go-mode-delayed-point (point))) + +(defun go-mode-delayed-electric-hook (b e l) + "An after-change-function that implements `go-mode-delayed-electric'." + + (when (and go-mode-delayed-point + (= go-mode-delayed-point b)) + (save-excursion + (save-match-data + (goto-char go-mode-delayed-point) + (indent-according-to-mode)))) + (setq go-mode-delayed-point nil)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Parser +;; + +(defvar go-mode-mark-cs-end 1 + "The point at which the comment/string cache ends. The buffer +will be marked from the beginning up to this point (that is, up +to and including character (1- go-mode-mark-cs-end)).") +(make-variable-buffer-local 'go-mode-mark-cs-end) + +(defvar go-mode-mark-cs-state nil + "The `parse-partial-sexp' state of the comment/string parser as +of the point `go-mode-mark-cs-end'.") +(make-variable-buffer-local 'go-mode-mark-cs-state) + +(defvar go-mode-mark-nesting-end 1 + "The point at which the nesting cache ends. The buffer will be +marked from the beginning up to this point.") +(make-variable-buffer-local 'go-mode-mark-nesting-end) + +(defun go-mode-mark-clear-cache (b e l) + "An after-change-function that clears the comment/string and +nesting caches from the modified point on." + + (save-restriction + (widen) + (when (< b go-mode-mark-cs-end) + (remove-text-properties b (min go-mode-mark-cs-end (point-max)) '(go-mode-cs nil)) + (setq go-mode-mark-cs-end b + go-mode-mark-cs-state nil)) + + (when (< b go-mode-mark-nesting-end) + (remove-text-properties b (min go-mode-mark-nesting-end (point-max)) '(go-mode-nesting nil)) + (setq go-mode-mark-nesting-end b)))) + +(defmacro go-mode-parser (&rest body) + "Evaluate BODY in an environment set up for parsers that use +text properties to mark text. This inhibits changes to the undo +list or the buffer's modification status and inhibits calls to +the modification hooks. It also saves the excursion and +restriction and widens the buffer, since most parsers are +context-sensitive." + + (let ((modified-var (make-symbol "modified"))) + `(let ((buffer-undo-list t) + (,modified-var (buffer-modified-p)) + (inhibit-modification-hooks t) + (inhibit-read-only t)) + (save-excursion + (save-restriction + (widen) + (unwind-protect + (progn ,@body) + (set-buffer-modified-p ,modified-var))))))) + +(defsubst go-mode-cs (&optional pos) + "Return the comment/string state at point POS. If point is +inside a comment or string (including the delimiters), this +returns a pair (START . END) indicating the extents of the +comment or string." + + (unless pos + (setq pos (point))) + (if (= pos 1) + nil + (when (> pos go-mode-mark-cs-end) + (go-mode-mark-cs pos)) + (get-text-property (- pos 1) 'go-mode-cs))) + +(defun go-mode-mark-cs (end) + "Mark comments and strings up to point END. Don't call this +directly; use `go-mode-cs'." + + (setq end (min end (point-max))) + (go-mode-parser + (let* ((pos go-mode-mark-cs-end) + (state (or go-mode-mark-cs-state (syntax-ppss pos)))) + ;; Mark comments and strings + (when (nth 8 state) + ;; Get to the beginning of the comment/string + (setq pos (nth 8 state) + state nil)) + (while (> end pos) + ;; Find beginning of comment/string + (while (and (> end pos) + (progn + (setq state (parse-partial-sexp pos end nil nil state 'syntax-table) + pos (point)) + (not (nth 8 state))))) + ;; Find end of comment/string + (let ((start (nth 8 state))) + (when start + (setq state (parse-partial-sexp pos (point-max) nil nil state 'syntax-table) + pos (point)) + ;; Mark comment + (put-text-property start (- pos 1) 'go-mode-cs (cons start pos)) + (when nil + (put-text-property start (- pos 1) 'face + `((:background "midnight blue"))))))) + ;; Update state + (setq go-mode-mark-cs-end pos + go-mode-mark-cs-state state)))) + +(defsubst go-mode-nesting (&optional pos) + "Return the nesting at point POS. The nesting is a list +of (START . END) pairs for all braces, parens, and brackets +surrounding POS, starting at the inner-most nesting. START is +the location of the open character. END is the location of the +close character or nil if the nesting scanner has not yet +encountered the close character." + + (unless pos + (setq pos (point))) + (if (= pos 1) + '() + (when (> pos go-mode-mark-nesting-end) + (go-mode-mark-nesting pos)) + (get-text-property (- pos 1) 'go-mode-nesting))) + +(defun go-mode-mark-nesting (pos) + "Mark nesting up to point END. Don't call this directly; use +`go-mode-nesting'." + + (go-mode-cs pos) + (go-mode-parser + ;; Mark depth + (goto-char go-mode-mark-nesting-end) + (let ((nesting (go-mode-nesting)) + (last (point))) + (while (< last pos) + ;; Find the next depth-changing character + (skip-chars-forward "^(){}[]" pos) + ;; Mark everything up to this character with the current + ;; nesting + (put-text-property last (point) 'go-mode-nesting nesting) + (when nil + (let ((depth (length nesting))) + (put-text-property last (point) 'face + `((:background + ,(format "gray%d" (* depth 10))))))) + (setq last (point)) + ;; Update nesting + (unless (eobp) + (let ((ch (unless (go-mode-cs) (char-after)))) + (forward-char 1) + (case ch + ((?\( ?\{ ?\[) + (setq nesting (cons (cons (- (point) 1) nil) + nesting))) + ((?\) ?\} ?\]) + (when nesting + (setcdr (car nesting) (- (point) 1)) + (setq nesting (cdr nesting)))))))) + ;; Update state + (setq go-mode-mark-nesting-end last)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Indentation +;; + +(defvar go-mode-non-terminating-keywords-regexp + (let* ((kws go-mode-keywords) + (kws (remove "break" kws)) + (kws (remove "continue" kws)) + (kws (remove "fallthrough" kws)) + (kws (remove "return" kws))) + (regexp-opt kws 'words)) + "Regular expression matching all Go keywords that *do not* +implicitly terminate a statement.") + +(defun go-mode-semicolon-p () + "True iff point immediately follows either an explicit or +implicit semicolon. Point should immediately follow the last +token on the line." + + ;; #Semicolons + (case (char-before) + ((?\;) t) + ;; String literal + ((?' ?\" ?`) t) + ;; One of the operators and delimiters ++, --, ), ], or } + ((?+) (eq (char-before (1- (point))) ?+)) + ((?-) (eq (char-before (1- (point))) ?-)) + ((?\) ?\] ?\}) t) + ;; An identifier or one of the keywords break, continue, + ;; fallthrough, or return or a numeric literal + (otherwise + (save-excursion + (when (/= (skip-chars-backward "[:word:]_") 0) + (not (looking-at go-mode-non-terminating-keywords-regexp))))))) + +(defun go-mode-indentation () + "Compute the ideal indentation level of the current line. + +To the first order, this is the brace depth of the current line, +plus parens that follow certain keywords. case, default, and +labels are outdented one level, and continuation lines are +indented one level." + + (save-excursion + (back-to-indentation) + (let ((cs (go-mode-cs))) + ;; Treat comments and strings differently only if the beginning + ;; of the line is contained within them + (when (and cs (= (point) (car cs))) + (setq cs nil)) + ;; What type of context am I in? + (cond + ((and cs (save-excursion + (goto-char (car cs)) + (looking-at "\\s\""))) + ;; Inside a multi-line string. Don't mess with indentation. + nil) + (cs + ;; Inside a general comment + (goto-char (car cs)) + (forward-char 1) + (current-column)) + (t + ;; Not in a multi-line string or comment + (let ((indent 0) + (inside-indenting-paren nil)) + ;; Count every enclosing brace, plus parens that follow + ;; import, const, var, or type and indent according to + ;; depth. This simple rule does quite well, but also has a + ;; very large extent. It would be better if we could mimic + ;; some nearby indentation. + (save-excursion + (skip-chars-forward "})") + (let ((first t)) + (dolist (nest (go-mode-nesting)) + (case (char-after (car nest)) + ((?\{) + (incf indent tab-width)) + ((?\() + (goto-char (car nest)) + (forward-comment (- (buffer-size))) + ;; Really just want the token before + (when (looking-back "\\\\|\\\\|\\w+\\s *:\\(\\S.\\|$\\)") + (decf indent tab-width)) + + ;; Continuation lines are indented 1 level + (forward-comment (- (buffer-size))) + (when (case (char-before) + ((nil ?\{ ?:) + ;; At the beginning of a block or the statement + ;; following a label. + nil) + ((?\() + ;; Usually a continuation line in an expression, + ;; unless this paren is part of a factored + ;; declaration. + (not inside-indenting-paren)) + ((?,) + ;; Could be inside a literal. We're a little + ;; conservative here and consider any comma within + ;; curly braces (as opposed to parens) to be a + ;; literal separator. This will fail to recognize + ;; line-breaks in parallel assignments as + ;; continuation lines. + (let ((depth (go-mode-nesting))) + (and depth + (not (eq (char-after (caar depth)) ?\{))))) + (t + ;; We're in the middle of a block. Did the + ;; previous line end with an implicit or explicit + ;; semicolon? + (not (go-mode-semicolon-p)))) + (incf indent tab-width)) + + (max indent 0))))))) + +(defun go-mode-indent-line () + "Indent the current line according to `go-mode-indentation'." + (interactive) + + (let ((col (go-mode-indentation))) + (when col + (let ((offset (- (current-column) (current-indentation)))) + (indent-line-to col) + (when (> offset 0) + (forward-char offset)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Go mode +;; + +;;;###autoload +(define-derived-mode go-mode prog-mode "Go" + "Major mode for editing Go source text. + +This provides basic syntax highlighting for keywords, built-ins, +functions, and some types. It also provides indentation that is +\(almost) identical to gofmt." + + ;; Font lock + (set (make-local-variable 'font-lock-defaults) + '(go-mode-font-lock-keywords nil nil nil nil)) + + ;; Remove stale text properties + (save-restriction + (widen) + (remove-text-properties 1 (point-max) + '(go-mode-cs nil go-mode-nesting nil))) + + ;; Reset the syntax mark caches + (setq go-mode-mark-cs-end 1 + go-mode-mark-cs-state nil + go-mode-mark-nesting-end 1) + (add-hook 'after-change-functions #'go-mode-mark-clear-cache nil t) + + ;; Indentation + (set (make-local-variable 'indent-line-function) + #'go-mode-indent-line) + (add-hook 'after-change-functions #'go-mode-delayed-electric-hook nil t) + + ;; Comments + (set (make-local-variable 'comment-start) "// ") + (set (make-local-variable 'comment-end) "") + + ;; Go style + (setq indent-tabs-mode t)) + +;;;###autoload +(add-to-list 'auto-mode-alist (cons "\\.go$" #'go-mode)) + +(defun go-mode-reload () + "Reload go-mode.el and put the current buffer into Go mode. +Useful for development work." + + (interactive) + (unload-feature 'go-mode) + (require 'go-mode) + (go-mode)) + +;;;###autoload +(defun gofmt () + "Pipe the current buffer through the external tool `gofmt`. +Replace the current buffer on success; display errors on failure." + + (interactive) + (let ((srcbuf (current-buffer))) + (with-temp-buffer + (let ((outbuf (current-buffer)) + (errbuf (get-buffer-create "*Gofmt Errors*")) + (coding-system-for-read 'utf-8) ;; use utf-8 with subprocesses + (coding-system-for-write 'utf-8)) + (with-current-buffer errbuf (erase-buffer)) + (with-current-buffer srcbuf + (save-restriction + (let (deactivate-mark) + (widen) + (if (= 0 (shell-command-on-region (point-min) (point-max) "gofmt" + outbuf nil errbuf)) + ;; gofmt succeeded: replace the current buffer with outbuf, + ;; restore the mark and point, and discard errbuf. + (let ((old-mark (mark t)) (old-point (point))) + (erase-buffer) + (insert-buffer-substring outbuf) + (goto-char (min old-point (point-max))) + (if old-mark (push-mark (min old-mark (point-max)) t)) + (kill-buffer errbuf)) + + ;; gofmt failed: display the errors + (display-buffer errbuf))))) + + ;; Collapse any window opened on outbuf if shell-command-on-region + ;; displayed it. + (delete-windows-on outbuf))))) + +;;;###autoload +(defun gofmt-before-save () + "Add this to .emacs to run gofmt on the current buffer when saving: + (add-hook 'before-save-hook #'gofmt-before-save)" + + (interactive) + (when (eq major-mode 'go-mode) (gofmt))) + +(provide 'go-mode) diff --git a/emacs.d/elisp/muttrc-mode.el b/emacs.d/elisp/muttrc-mode.el new file mode 100644 index 0000000..b3bdd2c --- /dev/null +++ b/emacs.d/elisp/muttrc-mode.el @@ -0,0 +1,1638 @@ +;;; muttrc-mode.el --- Major mode to edit muttrc under Emacs + +;;; Copyright (C) 2000, 2001, 2002 Laurent Pelecq +;;; Copyright (C) 2009 Kumar Appaiah +;;; +;;; Authors: Laurent Pelecq +;;; Kumar Appaiah + +;;; 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. + +;;; Supported Emacs: +;;; ================ +;;; This mode has only been tested on Emacs 21.2. If you +;;; encounter problems with older versions or with Xemacs, let me +;;; know. + +;;; Installation: +;;; ============= +;;; Add this lines to your .emacs: +;;; (autoload 'muttrc-mode "muttrc-mode.el" +;;; "Major mode to edit muttrc files" t) +;;; (setq auto-mode-alist +;;; (append '(("muttrc\\'" . muttrc-mode)) +;;; auto-mode-alist)) +;;; Be sure this file is in a directory that appears in the load-path. +;;; +;;; You mail want to use this mode for other files like the mail +;;; aliases file. In that case just add the following lines at the end +;;; of these files: +;;; ### Local Variables: *** +;;; ### mode: muttrc *** +;;; ### End: *** + +;;; Customization: +;;; ============== +;;; Execute: M-x configure-group RET muttrc RET +;;; +;;; By default, help on command/variable is displayed automatically +;;; while executing a command to modify them. Disable this feature if +;;; you have problems with. + +;;; Description: +;;; ============ +;;; This mode first goal is to provide syntax highlighting with +;;; font-lock. The basic fontification appears on strings, comments, +;;; command names and variables. Additional fontification for commands +;;; arguments can be enabled through the customization buffer. +;;; +;;; Main commands are: +;;; C-x c -- muttrc-insert-command +;;; C-x s -- muttrc-set-variable +;;; C-x S -- muttrc-unset-variable +;;; +;;; Type C-h m for all key bindings. + +;;; BUGS: +;;; ===== +;;; - Multiline commands are not properly handled and can lead to +;;; unexpected result. + + + +;;; Code: + +;;; ------------------------------------------------------------ +;;; Requirement +;;; ------------------------------------------------------------ + +(require 'man) + +(defconst muttrc-mode-version "$Revision: 1.2 $") + +;;; ------------------------------------------------------------ +;;; Configurable stuff +;;; ------------------------------------------------------------ + +(defgroup muttrc nil + "Muttrc editing commands for Emacs." + :group 'files + :prefix "muttrc-") + +(defcustom muttrc-manual-path "/usr/share/doc/mutt/manual.txt.gz" + "Path to the Mutt manual." + :type 'string + :group 'muttrc) + +(defcustom muttrc-display-help t + "Display help for each command/variable modification if set." + :type 'boolean + :group 'muttrc) + +(defcustom muttrc-folder-abbrev ?+ + "Character used to refer to the folder directory." + :type '(choice (const :tag "+" ?+) + (const :tag "=" ?=)) + :group 'muttrc) + +(defcustom muttrc-argument-faces-alist + '((alias . bold) + (address . default) + (face . default) + (color . default) + (command . default) + (path . default) + (function . default) + (header . default) + (hook . default) + (key . default) + (map . default) + (mimetype . default) + (object . default) + (regexp . default) + (sequence . default) + (string . default) + (hook-type . default)) + "List of faces for the Muttrc command arguments. Standard faces are +symbols like 'bold, 'underline, ... Muttrc files must be revisited in +order for the modifications to take effect." + :type '(repeat (cons symbol symbol)) + :group 'muttrc) + +;;; ------------------------------------------------------------ +;;; For backward compatibility +;;; ------------------------------------------------------------ + +(or (functionp 'match-string-no-properties) + (defalias 'match-string-no-properties 'match-string)) + +;;; ------------------------------------------------------------ +;;; Mutt variables and commands +;;; ------------------------------------------------------------ + +(defconst muttrc-arg-handler-alist + '((alias muttrc-get-word "Alias") + (boolean muttrc-get-boolean "Enable") + (number muttrc-get-number "Number") + (address muttrc-get-string "Address") + (face muttrc-get-from-list "Face" muttrc-face-alist t) + (color muttrc-get-from-list "Color" muttrc-color-alist) + (command muttrc-get-command "Command") + (statement muttrc-get-statement "Command") + (assignment muttrc-get-assignment "Variable" t) + (variable muttrc-get-assignment "Variable" nil) + (path muttrc-get-path "Path") + (function muttrc-get-from-list "Function" muttrc-mutt-function-alist) + (header muttrc-get-from-list "Header name" muttrc-header-alist) + (hook-type muttrc-get-from-list "Hook" muttrc-hook-alist t) + (key muttrc-get-string "Key") + (map muttrc-get-from-list "Map" muttrc-map-alist t) + (mimetype muttrc-get-from-list "MIME type" muttrc-mimetype-alist) + (object muttrc-get-from-list "Object" muttrc-object-alist) + (regexp muttrc-get-string "Regular expression") + (sequence muttrc-get-string "Sequence") + (string muttrc-get-string "String") + (alias-sort-order muttrc-get-from-list "Sort order" + muttrc-alias-sort-order-alist) + (aux-sort-order muttrc-get-from-list "Sort order" + muttrc-aux-sort-order-alist) + (browser-sort-order muttrc-get-from-list "Sort order" + muttrc-browser-sort-order-alist) + (pgp-sort-order muttrc-get-from-list "Sort order" + muttrc-pgp-sort-order-alist) + (quadoption muttrc-get-from-list "Option" muttrc-quadoption-alist) + (sort-order muttrc-get-from-list "Sort order" + muttrc-sort-order-alist)) + "List of handler for each type of argument. The format is: +\(ARG-TYPE FACE HANDLER PROMPT HANDLER-ARGS\). +The PROMPT can be overwritten by in command description.") + +(defconst muttrc-face-alist + '(("none" . 1) ("bold" . 2) ("underline" . 3) + ("reverse" . 4) ("standout". 5))) + +(defconst muttrc-color-alist + '(("default" . 0) + ("black" . 1) ("blue" . 2) ("cyan" . 3) ("green" . 4) + ("magenta" . 5) ("red" . 6) ("white" . 7) ("yellow" . 8) + ("brightdefault" . 9) + ("brightblack" . 10) ("brightblue" . 11) ("brightcyan" . 12) + ("brightgreen" . 13) ("brightmagenta" . 14) ("brightred" . 15) + ("brightwhite" . 16) ("brightyellow" . 17))) + +(defconst muttrc-object-alist + '(("attachment" . 0) + ("body" . 1) + ("bold" . 2) + ("error" . 3) + ("hdrdefault" . 4) + ("header" . 5) + ("index" . 6) + ("indicator" . 7) + ("markers" . 8) + ("message" . 9) + ("normal" . 10) + ("quoted" . 11) + ("search" . 12) + ("signature" . 13) + ("status" . 14) + ("tilde" . 15) + ("tree" . 16) + ("underline" . 17)) + "Mutt object on which color apply.") + +(defconst muttrc-header-alist + '(("content-transfer-encoding" . 0) + ("content-type" . 1) + ("date" . 2) + ("from" . 3) + ("message-id" . 4) + ("mime-version" . 5) + ("organization" . 6) + ("received" . 7) + ("reply-to" . 8) + ("resent-from" . 9) + ("subject" . 10) + ("to" . 11) + ("x-accept-language" . 12) + ("x-mailer" . 13) + ("x-mimetrack" . 14) + ("x-sender" . 15))) + +(defconst muttrc-hook-alist + '(("folder-hook" . 0) ("send-hook" . 1) ("save-hook" . 2) + ("mbox-hook" . 3) ("fcc-hook" . 4) ("fcc-save-hook" . 5) + ("message-hook" . 5) ("charset-hook" . 6) ("iconv-hook" . 7) + ("account-hook" . 8) ("append-hook" . 9) ("close-hook" . 10) + ("crypt-hook" . 11) ("send2-hook" . 12) ("reply-hook" . 13) + ("open-hook" . 14))) + +(defconst muttrc-map-alist + '(("alias" . 0) ("attach" . 1) ("browser" . 2) ("compose" . 3) + ("editor" . 4) ("generic" . 5) ("index" . 6) ("pager" . 7) + ("pgp" . 8) ("postpone" . 9) ("query" . 10))) + +(defconst muttrc-mimetype-alist + '(("application/andrew-inset" "ez") + ("application/excel" "xls") + ("application/fractals" "fif") + ("application/java-archive" "jar") + ("application/mac-binhex40" "hqx") + ("application/msword" "doc" "dot") + ("application/octet-stream" "exe" "bin") + ("application/oda" "oda") + ("application/pdf" "pdf") + ("application/pdf") + ("application/pgp" "pgp") + ("application/postscript" "ai" "eps" "ps" "PS") + ("application/pre-encrypted" "enc") + ("application/rtf" "rtf") + ("application/vnd.lotus-wordpro" "lwp" "sam") + ("application/vnd.ms-access" "mdb" "mda" "mde") + ("application/vnd.ms-excel" "xls") + ("application/vnd.ms-powerpoint" "ppt" "pot" "ppa" "pps" "pwz") + ("application/vnd.ms-schedule" "scd" "sch" "sc2") + ("application/wordperfect5.1" "wpd" "wp6") + ("application/x-arj-compressed" "arj") + ("application/x-bcpio" "bcpio") + ("application/x-chess-pgn" "pgn") + ("application/x-cpio" "cpio") + ("application/x-csh" "csh") + ("application/x-debian-package" "deb") + ("application/x-dvi" "dvi") + ("application/x-fortezza-ckl" "ckl") + ("application/x-gtar" "gtar") + ("application/x-gunzip" "gz") + ("application/x-hdf" "hdf") + ("application/x-javascript" "js" "mocha") + ("application/x-javascript-config" "jsc") + ("application/x-latex" "latex") + ("application/x-mif" "mif") + ("application/x-msdos-program" "com" "exe" "bat") + ("application/x-netcdf" "cdf" "nc") + ("application/x-ns-proxy-autoconfig" "pac") + ("application/x-ns-proxy-autoconfig") + ("application/x-perl" "pl" "pm") + ("application/x-pkcs7-crl" "crl") + ("application/x-pkcs7-mime" "p7m" "p7c") + ("application/x-pkcs7-signature" "p7s") + ("application/x-rar-compressed" "rar") + ("application/x-sh" "sh") + ("application/x-shar" "shar") + ("application/x-stuffit" "sit") + ("application/x-sv4cpio" "sv4cpio") + ("application/x-sv4crc" "sv4crc") + ("application/x-tar" "tar") + ("application/x-tar-gz" "tgz" "tar.gz") + ("application/x-tcl" "tcl") + ("application/x-tex" "tex") + ("application/x-texinfo" "texi" "texinfo") + ("application/x-troff" "t" "tr" "roff") + ("application/x-troff-man" "man") + ("application/x-troff-me" "me") + ("application/x-troff-ms" "ms") + ("application/x-ustar" "ustar") + ("application/x-wais-source" "src") + ("application/x-zip-compressed" "zip") + ("audio/basic" "au" "snd") + ("audio/basic" "snd") + ("audio/midi" "mid" "midi") + ("audio/ulaw" "au") + ("audio/x-aiff" "aif" "aifc" "aiff") + ("audio/x-aiff" "aif" "aiff" "aifc") + ("audio/x-wav" "wav") + ("image/gif" "gif") + ("image/ief" "ief") + ("image/jpeg" "jpe" "jpeg" "jpg") + ("image/png" "png") + ("image/tiff" "tif" "tiff") + ("image/tiff") + ("image/x-MS-bmp" "bmp") + ("image/x-cmu-raster" "ras") + ("image/x-photo-cd" "pcd") + ("image/x-portable-anymap" "pnm") + ("image/x-portable-bitmap" "pbm") + ("image/x-portable-graymap" "pgm") + ("image/x-portable-pixmap" "ppm") + ("image/x-rgb" "rgb") + ("image/x-xbitmap" "xbm") + ("image/x-xpixmap" "xpm") + ("image/x-xwindowdump" "xwd") + ("text/html" "html" "htm" "shtml") + ("text/plain" "txt" "text") + ("text/richtext" "rtx") + ("text/tab-separated-values" "tsv") + ("text/x-setext" "etx") + ("text/x-vcard" "vcf") + ("text/x-vcard") + ("video/dl" "dl") + ("video/fli" "fli") + ("video/gl" "gl") + ("video/mpeg" "mpeg" "mpg" "mpe" "mpv" "vbs" "mpegv") + ("video/quicktime" "qt" "mov" "moov") + ("video/x-msvideo" "avi") + ("video/x-sgi-movie" "movie") + ("x-world/x-vrml" "vrm" "vrml" "wrl"))) + +(defconst muttrc-command-alist + '( + ("folder-hook" ((string) (statement)) nil nil) + ("alias" ((alias) (address)) t nil) + ("unalias" ((alias) (address)) t nil) + ("alternative_order" ((mimetype)) t nil) + ("auto_view" ((mimetype)) t nil) + ("bind" ((map) (key) (function)) nil t) + ("color" ((object) + (color "Foreground") + (color "Background") + (regexp)) nil t) + ("charset-hook" ((string "Alias") + (string "Charset")) nil nil) + ("fcc-hook" ((regexp) (path)) nil nil) + ("fcc-save-hook" ((regexp) (path)) nil nil) + ("folder-hook" ((regexp) (statement)) nil nil) + ("ignore" ((header)) t nil) + ("iconv-hook" ((string "Charset") + (string "Local charset")) nil nil) + ("unignore" ((header)) t nil) + ("hdr_order" ((header)) t nil) + ("unhdr_order" ((header)) t nil) + ("lists" ((address)) t nil) + ("unlists" ((address)) t nil) + ("macro" ((map) (key) (sequence) + (string "Description")) nil t) + ("mailboxes" ((path)) t nil) + ("mono" ((object) (face) (regexp)) nil t) + ("mbox-hook" ((regexp) (path)) nil nil) + ("message-hook" ((regexp) (statement)) nil nil) + ("my_hdr" ((string "Header")) nil nil) + ("unmy_hdr" ((header)) t nil) + ("push" ((string)) nil nil) + ("pgp-hook" ((regexp) + (string "Keyid")) nil nil) + ("save-hook" ((regexp) (path)) nil nil) + ("score" ((regexp) + (number "Value")) nil nil) + ("unscore" ((regexp)) t nil) + ("send-hook" ((regexp) (statement)) nil nil) + ("source" ((path)) nil nil) + ("subscribe" ((address)) t nil) + ("unsubscribe" ((address)) t nil) + ("unhook" ((hook-type)) nil nil) + ("alternates" ((regexp)) nil nil) + ("unalternates" ((regexp)) nil nil)) + "List of muttrc commands with their arguments. Format is: +COMMAND '\(ARG1 ARG2 ...\) REPEAT OPTIONAL +REPEAT and OPTIONAL apply to the last argument. +ARGn is the list of arguments for muttrc-call-arg-handler. Each args +is a list \(ARGTYPE \[ARGNAME\]\).") + +(defconst muttrc-statement-alist + (append + '(("set" ((assignment)) t nil) + ("unset" ((variable)) t nil)) + muttrc-command-alist) + "Additional muttrc commands with their arguments that are handled +differently. See muttrc-command-alist") + + +(defconst muttrc-variables-alist + '(("abort_nosubject" quadoption "ask-yes") + ("abort_unmodified" quadoption "yes") + ("alias_file" path "~/.muttrc") + ("alias_format" string "%4n %2f %t %-10a %r") + ("allow_8bit" boolean t) + ("allow_ansi" boolean nil) + ("arrow_cursor" boolean nil) + ("ascii_chars" boolean nil) + ("askbcc" boolean nil) + ("askcc" boolean nil) + ("assumed_charset" string "us-ascii") + ("attach_format" string "%u%D%I %t%4n %T%.40d%> [%.7m/%.10M, %.6e%?C?, %C?, %s] ") + ("attach_sep" string "\\n") + ("attach_split" boolean t) + ("attribution" string "On %d, %n wrote:") + ("autoedit" boolean nil) + ("auto_tag" boolean nil) + ("beep" boolean t) + ("beep_new" boolean nil) + ("bounce" quadoption "ask-yes") + ("bounce_delivered" boolean t) + ("braille_friendly" boolean nil) + ("charset" string "") + ("check_new" boolean t) + ("collapse_unread" boolean t) + ("uncollapse_jump" boolean nil) + ("compose_format" string "-- Mutt: Compose [Approx. msg size: %l Atts: %a]%>-") + ("config_charset" string "") + ("confirmappend" boolean t) + ("confirmcreate" boolean t) + ("connect_timeout" number 30) + ("content_type" string "text/plain") + ("copy" quadoption "yes") + ("crypt_use_gpgme" boolean nil) + ("crypt_autopgp" boolean t) + ("crypt_autosmime" boolean t) + ("date_format" string "!%a, %b %d, %Y at %I:%M:%S%p %Z") + ("default_hook" string "~f %s !~P | (~P ~C %s)") + ("delete" quadoption "ask-yes") + ("delete_untag" boolean t) + ("digest_collapse" boolean t) + ("display_filter" path "") + ("dotlock_program" path "/usr/bin/mutt_dotlock") + ("dsn_notify" string "") + ("dsn_return" string "") + ("duplicate_threads" boolean t) + ("edit_headers" boolean nil) + ("editor" path "") + ("encode_from" boolean nil) + ("envelope_from_address" e-mail "") + ("escape" string "~") + ("fast_reply" boolean nil) + ("fcc_attach" boolean t) + ("fcc_clear" boolean nil) + ("file_charset" string "") + ("folder" path "~/Mail") + ("folder_format" string "%2C %t %N %F %2l %-8.8u %-8.8g %8s %d %f") + ("followup_to" boolean t) + ("force_name" boolean nil) + ("forward_decode" boolean t) + ("forward_edit" quadoption "yes") + ("forward_format" string "[%a: %s]") + ("forward_quote" boolean nil) + ("from" e-mail "") + ("gecos_mask" regular "^[^,]*") + ("hdrs" boolean t) + ("header" boolean nil) + ("help" boolean t) + ("hidden_host" boolean nil) + ("hide_limited" boolean nil) + ("hide_missing" boolean t) + ("hide_thread_subject" boolean t) + ("hide_top_limited" boolean nil) + ("hide_top_missing" boolean t) + ("history" number 10) + ("honor_followup_to" quadoption "yes") + ("hostname" string "") + ("ignore_list_reply_to" boolean nil) + ("imap_authenticators" string "") + ("imap_check_subscribed" boolean nil) + ("imap_delim_chars" string "/.") + ("imap_headers" string "") + ("imap_home_namespace" string "") + ("imap_idle" boolean nil) + ("imap_keepalive" number 900) + ("imap_list_subscribed" boolean nil) + ("imap_login" string "") + ("imap_pass" string "") + ("imap_passive" boolean t) + ("imap_peek" boolean t) + ("imap_servernoise" boolean t) + ("imap_user" string "") + ("implicit_autoview" boolean nil) + ("include" quadoption "ask-yes") + ("include_onlyfirst" boolean nil) + ("indent_string" string "> ") + ("index_format" string "%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s") + ("hdr_format" string "%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s") + ("ispell" path "ispell") + ("keep_flagged" boolean nil) + ("locale" string "C") + ("mail_check" number 5) + ("mailcap_path" string "") + ("mailcap_sanitize" boolean t) + ("maildir_mtime" boolean nil) + ("header_cache" path "") + ("maildir_header_cache_verify" boolean t) + ("header_cache_pagesize" string "16384") + ("maildir_trash" boolean nil) + ("mark_old" boolean t) + ("markers" boolean t) + ("mask" regular "!^\.[^.]") + ("mbox" path "~/mbox") + ("mbox_type" folder mbox) + ("metoo" boolean nil) + ("menu_context" number 0) + ("menu_move_off" boolean t) + ("menu_scroll" boolean nil) + ("meta_key" boolean nil) + ("mh_purge" boolean nil) + ("mh_seq_flagged" string "flagged") + ("mh_seq_replied" string "replied") + ("mh_seq_unseen" string "unseen") + ("mime_forward" quadoption "no") + ("mime_forward_decode" boolean nil) + ("mime_forward_rest" quadoption "yes") + ("pgp_mime_signature_filename" string "signature.asc") + ("pgp_mime_signature_description" string "Digital signature") + ("mix_entry_format" string "%4n %c %-16s %a") + ("mixmaster" path "mixmaster") + ("move" quadoption "ask-no") + ("message_cachedir" path "") + ("message_format" string "%s") + ("narrow_tree" boolean nil) + ("net_inc" number 10) + ("pager" path "builtin") + ("pager_context" number 0) + ("pager_format" string "-%Z- %C/%m: %-20.20n %s") + ("pager_index_lines" number 0) + ("pager_stop" boolean nil) + ("crypt_autosign" boolean nil) + ("crypt_autoencrypt" boolean nil) + ("pgp_ignore_subkeys" boolean t) + ("crypt_replyencrypt" boolean t) + ("crypt_replysign" boolean nil) + ("crypt_replysignencrypted" boolean nil) + ("crypt_timestamp" boolean t) + ("pgp_use_gpg_agent" boolean nil) + ("crypt_verify_sig" quadoption "yes") + ("pgp_verify_sig" quadoption "yes") + ("smime_is_default" boolean nil) + ("smime_ask_cert_label" boolean t) + ("smime_decrypt_use_default_key" boolean t) + ("pgp_entry_format" string "%4n %t%f %4l/0x%k %-4a %2c %u") + ("pgp_good_sign" regular "") + ("pgp_check_exit" boolean t) + ("pgp_long_ids" boolean nil) + ("pgp_retainable_sigs" boolean nil) + ("pgp_autoinline" boolean nil) + ("pgp_replyinline" boolean nil) + ("pgp_show_unusable" boolean t) + ("pgp_sign_as" string "") + ("pgp_strict_enc" boolean t) + ("pgp_timeout" number 300) + ("pgp_sort_keys" sort address) + ("pgp_mime_auto" quadoption "ask-yes") + ("pgp_auto_decode" boolean nil) + ("pgp_decode_command" string "") + ("pgp_getkeys_command" string "") + ("pgp_verify_command" string "") + ("pgp_decrypt_command" string "") + ("pgp_clearsign_command" string "") + ("pgp_sign_command" string "") + ("pgp_encrypt_sign_command" string "") + ("pgp_encrypt_only_command" string "") + ("pgp_import_command" string "") + ("pgp_export_command" string "") + ("pgp_verify_key_command" string "") + ("pgp_list_secring_command" string "") + ("pgp_list_pubring_command" string "") + ("forward_decrypt" boolean t) + ("smime_timeout" number 300) + ("smime_encrypt_with" string "") + ("smime_keys" path "") + ("smime_ca_location" path "") + ("smime_certificates" path "") + ("smime_decrypt_command" string "") + ("smime_verify_command" string "") + ("smime_verify_opaque_command" string "") + ("smime_sign_command" string "") + ("smime_sign_opaque_command" string "") + ("smime_encrypt_command" string "") + ("smime_pk7out_command" string "") + ("smime_get_cert_command" string "") + ("smime_get_signer_cert_command" string "") + ("smime_import_cert_command" string "") + ("smime_get_cert_email_command" string "") + ("smime_default_key" string "") + ("ssl_force_tls" boolean nil) + ("ssl_starttls" quadoption "yes") + ("certificate_file" path "~/.mutt_certificates") + ("ssl_use_sslv3" boolean t) + ("ssl_use_tlsv1" boolean t) + ("ssl_min_dh_prime_bits" number 0) + ("ssl_ca_certificates_file" path "") + ("pipe_split" boolean nil) + ("pipe_decode" boolean nil) + ("pipe_sep" string "\\n") + ("pop_authenticators" string "") + ("pop_auth_try_all" boolean t) + ("pop_checkinterval" number 60) + ("pop_delete" quadoption "ask-no") + ("pop_host" string "") + ("pop_last" boolean nil) + ("pop_reconnect" quadoption "ask-yes") + ("pop_user" string "") + ("pop_pass" string "") + ("post_indent_string" string "") + ("postpone" quadoption "ask-yes") + ("postponed" path "~/postponed") + ("preconnect" string "") + ("print" quadoption "ask-no") + ("print_command" path "lpr") + ("print_decode" boolean t) + ("print_split" boolean nil) + ("prompt_after" boolean t) + ("query_command" path "") + ("quit" quadoption "yes") + ("quote_regexp" regular "^([ \t]*[|>:}#])+") + ("read_inc" number 10) + ("read_only" boolean nil) + ("realname" string "") + ("recall" quadoption "ask-yes") + ("record" path "~/sent") + ("reply_regexp" regular "^(re([\[0-9\]+])*|aw):[ \t]*") + ("reply_self" boolean nil) + ("reply_to" quadoption "ask-yes") + ("resolve" boolean t) + ("reverse_alias" boolean nil) + ("reverse_name" boolean nil) + ("reverse_realname" boolean t) + ("rfc2047_parameters" boolean nil) + ("save_address" boolean nil) + ("save_empty" boolean t) + ("save_name" boolean nil) + ("score" boolean t) + ("score_threshold_delete" number -1) + ("score_threshold_flag" number 9999) + ("score_threshold_read" number -1) + ("send_charset" string "us-ascii:iso-8859-1:utf-8") + ("sendmail" path "/usr/sbin/sendmail -oem -oi") + ("sendmail_wait" number 0) + ("shell" path "") + ("sig_dashes" boolean t) + ("sig_on_top" boolean nil) + ("signature" path "~/.signature") + ("simple_search" string "~f %s | ~s %s") + ("smart_wrap" boolean t) + ("smileys" regular "(>From )|(:[-^]?[][)(><}{|/DP])") + ("sleep_time" number 1) + ("sort" sort date) + ("sort_alias" sort alias) + ("sort_aux" sort date) + ("sort_browser" sort alpha) + ("sort_re" boolean t) + ("spam_separator" string ",") + ("spoolfile" path "") + ("status_chars" string "-*%A") + ("status_format" string "-%r-Mutt: %f [Msgs:%?M?%M/?%m%?n? New:%n?%?o? Old:%o?%?d? Del:%d?%?F? Flag:%F?%?t? Tag:%t?%?p? Post:%p?%?b? Inc:%b?%?l? %l?]---(%s/%S)-%>-(%P)---") + ("status_on_top" boolean nil) + ("strict_mime" boolean t) + ("strict_threads" boolean nil) + ("suspend" boolean t) + ("text_flowed" boolean nil) + ("thread_received" boolean nil) + ("thorough_search" boolean nil) + ("tilde" boolean nil) + ("timeout" number 600) + ("tmpdir" path "") + ("to_chars" string " +TCFL") + ("tunnel" string "") + ("use_8bitmime" boolean nil) + ("use_domain" boolean t) + ("use_envelope_from" boolean nil) + ("use_from" boolean t) + ("use_idn" boolean t) + ("use_ipv6" boolean t) + ("user_agent" boolean t) + ("visual" path "") + ("wait_key" boolean t) + ("weed" boolean t) + ("wrap_search" boolean t) + ("wrapmargin" number 0) + ("write_inc" number 10) + ("write_bcc" boolean t) + ("xterm_icon" string "M%?n?AIL&ail?") + ("xterm_set_titles" boolean nil) + ("xterm_title" string "Mutt with %?m?%m messages&no messages?%?n? [%n NEW]?")) + "List of muttrc variables. Format is: +VARIABLE TYPE DEFAULT" + ) + +(defconst muttrc-mutt-function-alist + '(("attach-file" . 0) + ("attach-key" . 1) + ("attach-message" . 2) + ("backspace" . 3) + ("backward-char" . 4) + ("bol" . 5) + ("bottom-page" . 6) + ("bounce-message" . 7) + ("buffy-cycle" . 8) + ("change-dir" . 9) + ("change-folder" . 10) + ("change-folder-readonly" . 11) + ("check-new" . 12) + ("clear-flag" . 13) + ("complete" . 14) + ("complete-query" . 15) + ("copy-file" . 16) + ("copy-message" . 17) + ("create-alias" . 18) + ("current-bottom" . 19) + ("current-middle" . 20) + ("current-top" . 21) + ("decode-copy" . 22) + ("decode-save" . 23) + ("delete-char" . 24) + ("delete-entry" . 25) + ("delete-message" . 26) + ("delete-pattern" . 27) + ("delete-subthread" . 28) + ("delete-thread" . 29) + ("detach-file" . 30) + ("display-address" . 31) + ("display-message" . 32) + ("display-toggle-weed" . 33) + ("edit" . 34) + ("edit-bcc" . 35) + ("edit-cc" . 36) + ("edit-description" . 37) + ("edit-encoding" . 38) + ("edit-fcc" . 39) + ("edit-file" . 40) + ("edit-from" . 41) + ("edit-headers" . 42) + ("edit-message" . 43) + ("edit-mime" . 44) + ("edit-reply-to" . 45) + ("edit-subject" . 46) + ("edit-to" . 47) + ("edit-type" . 48) + ("enter-command" . 49) + ("enter-mask" . 50) + ("eol" . 51) + ("exit" . 52) + ("extract-keys" . 53) + ("fetch-mail" . 54) + ("filter-entry" . 55) + ("first-entry" . 56) + ("flag-message" . 57) + ("forget-passphrase" . 58) + ("forward-char" . 59) + ("forward-message" . 60) + ("group-reply" . 61) + ("half-down" . 62) + ("half-up" . 63) + ("help" . 64) + ("history-down" . 65) + ("history-up" . 66) + ("ispell" . 67) + ("jump" . 68) + ("kill-eol" . 69) + ("kill-line" . 70) + ("kill-word" . 71) + ("last-entry" . 72) + ("limit" . 73) + ("list-reply" . 74) + ("mail" . 75) + ("mail-key" . 76) + ("mark-as-new" . 77) + ("middle-page" . 78) + ("new-mime" . 79) + ("next-entry" . 80) + ("next-line" . 81) + ("next-new" . 82) + ("next-page" . 83) + ("next-subthread" . 84) + ("next-thread" . 85) + ("next-undeleted" . 86) + ("next-unread" . 87) + ("parent-message" . 88) + ("pgp-menu" . 89) + ("pipe-entry" . 90) + ("pipe-message" . 91) + ("postpone-message" . 92) + ("previous-entry" . 93) + ("previous-line" . 94) + ("previous-new" . 95) + ("previous-page" . 96) + ("previous-subthread" . 97) + ("previous-thread" . 98) + ("previous-undeleted" . 99) + ("previous-unread" . 100) + ("print-entry" . 101) + ("print-message" . 102) + ("query" . 103) + ("query-append" . 104) + ("quit" . 105) + ("quote-char" . 106) + ("read-subthread" . 107) + ("read-thread" . 108) + ("recall-message" . 109) + ("redraw-screen" . 110) + ("refresh" . 111) + ("rename-file" . 112) + ("reply" . 113) + ("save-entry" . 114) + ("save-message" . 115) + ("search" . 116) + ("search-next" . 117) + ("search-opposite" . 118) + ("search-reverse" . 119) + ("search-toggle" . 120) + ("select-entry" . 121) + ("select-new" . 122) + ("send-message" . 123) + ("set-flag" . 124) + ("shell-escape" . 125) + ("show-limit" . 126) + ("show-version" . 127) + ("skip-quoted" . 128) + ("sort" . 129) + ("sort-mailbox" . 130) + ("sort-reverse" . 131) + ("subscribe" . 132) + ("sync-mailbox" . 133) + ("tag-entry" . 134) + ("tag-message" . 135) + ("tag-pattern" . 136) + ("tag-prefix" . 137) + ("tag-thread" . 138) + ("toggle-mailboxes" . 139) + ("toggle-new" . 140) + ("toggle-quoted" . 141) + ("toggle-subscribed" . 142) + ("toggle-unlink" . 143) + ("toggle-write" . 144) + ("top" . 145) + ("top-page" . 146) + ("undelete-entry" . 147) + ("undelete-message" . 148) + ("undelete-pattern" . 149) + ("undelete-subthread" . 150) + ("undelete-thread" . 151) + ("unsubscribe" . 152) + ("untag-pattern" . 153) + ("verify-key" . 154) + ("view-attach" . 155) + ("view-attachments" . 156) + ("view-file" . 157) + ("view-mailcap" . 158) + ("view-name" . 159) + ("view-text" . 160) + ("write-fcc" . 161)) + "List of Mutt command (not muttrc!)") + +(defconst muttrc-alias-sort-order-alist + '(("address" . 0) ("alias" . 1) ("unsorted" . 2))) + +(defconst muttrc-aux-sort-order-alist + '(("date-sent" . 0) ("reverse-date-sent" . 1) ("last-date-sent" . 2) + ("date-received" . 3) ("reverse-date-received" . 4) + ("last-date-received" . 5) + ("from" . 6) ("reverse-from" . 7) ("last-from" . 8) + ("mailbox-order" . 9) ("reverse-mailbox-order" . 10) + ("last-mailbox-order" . 11) + ("score" . 12) ("reverse-score" . 13) ("last-score" . 14) + ("size" . 15) ("reverse-size" . 16) ("last-size" . 17) + ("subject" . 18) ("reverse-subject" . 19) ("last-subject" . 20) + ("threads" . 21) ("reverse-threads" . 22) ("last-threads" . 23) + ("to" . 24) ("reverse-to" . 25) ("last-to" . 26))) + +(defconst muttrc-browser-sort-order-alist + '(("alpha" . 0) ("date" . 1) ("size" . 2) ("unsorted" . 3))) + +(defconst muttrc-pgp-sort-order-alist + '(("address" . 0) ("date" . 1) ("keyid" . 2) + ("reverse-address" . 3) ("reverse-date" . 4) + ("reverse-keyid" . 5) ("reverse-trust" . 6) + ("trust" . 7))) + +(defconst muttrc-quadoption-alist + '(("yes" .0) ("no" .1) ("ask-yes" .2) ("ask-no" .3))) + +(defconst muttrc-sort-order-alist + '(("date-sent" . 0) ("reverse-date-sent" . 1) + ("date-received" . 2) ("reverse-date-received" . 3) + ("from" . 4) ("reverse-from" . 5) + ("mailbox-order" . 6) ("reverse-mailbox-order" . 7) + ("score" . 8) ("reverse-score" . 9) + ("size" . 10) ("reverse-size" . 11) + ("subject" . 12) ("reverse-subject" . 13) + ("threads" . 14) ("reverse-threads" . 15) + ("to" . 16) ("reverse-to" . 17))) + +;;; ------------------------------------------------------------ +;;; Font-lock definitions +;;; ------------------------------------------------------------ + +(defun muttrc-string-regexp (quote-char) + (let ((c (char-to-string quote-char))) + (format "%s\\([^\n%s]\\|[\\].\\)*%s" c c c))) + +(defvar muttrc-generic-arg-regexp + (concat "\\(" + (muttrc-string-regexp ?\") + "\\|" + "'\\([^']*\\)'" + "\\|" + (muttrc-string-regexp ?\`) + "\\|" + "\\([^\n\t \"'`#;\\]\\|[\\].\\)+" + "\\)")) + +(defvar muttrc-generic-arg-sequence-regexp + (concat "\\(\\s-*" muttrc-generic-arg-regexp "+\\)*")) + +(defvar muttrc-non-command-keyword-regexp + "\\(^\\|;\\)\\s-*\\<\\(set\\|unset\\|toggle\\|reset\\)\\>") + +(defvar muttrc-variable-regexp + (concat "\\<\\(\\(no\\|inv\\)?\\(" + (mapconcat 'car muttrc-variables-alist "\\|") + "\\)\\)\\>")) + +(defvar muttrc-assignement-regexp + (concat muttrc-variable-regexp + "\\s-*\\(=\\s-*" muttrc-generic-arg-regexp "\\)?")) + +(defun muttrc-search-command-forward (command &optional limit) + (let ((cmd-desc (assoc command muttrc-command-alist))) + (if cmd-desc + (let ((cmd-match-data '()) + (cmd-args (cadr cmd-desc)) + (origin (point)) + beg-0 end-0) + (catch 'done + (while (and (not cmd-match-data) + (re-search-forward + (concat "\\(;\\|^\\)\\s-*\\(" command "\\)") + limit t)) + (let ((beg (nth 4 (match-data))) + (end (nth 5 (match-data)))) + (setq beg-0 beg) + (setq cmd-match-data (list beg end))) + (let ((args cmd-args)) + (while args + (let ((arg-type (caar args)) + (arg-re (if (null (cdr args)) + muttrc-generic-arg-sequence-regexp + muttrc-generic-arg-regexp))) + (skip-syntax-forward "-") + (if (looking-at arg-re) + (let ((beg (nth 0 (match-data))) + (end (nth 1 (match-data)))) + (goto-char end) + (setq cmd-match-data (append cmd-match-data + (list beg end))) + (setq end-0 end) + (setq args (cdr args))) + (progn + (setq args nil) + (setq cmd-match-data nil))))) + (when cmd-match-data + (set-match-data (cons beg-0 + (cons end-0 + cmd-match-data))) + (throw 'done t)))) + (goto-char origin) + nil))))) + + +(defun muttrc-font-lock-keywords () + (let ((command-alist muttrc-command-alist) + keywords) + (while command-alist + (let* ((cmd (caar command-alist)) + (args (cadr (car command-alist))) + (regexp (eval ; Simulate a closure + (list + 'lambda '(&optional limit) + (list 'muttrc-search-command-forward cmd 'limit)))) + (hilighters '((1 font-lock-keyword-face))) + (n 2)) + (while args + (let ((arg-type (caar args)) + (last-arg-p (null (cdr args)))) + (setq hilighters + (append hilighters + (let ((face + (or (cdr-safe + (assoc arg-type + muttrc-argument-faces-alist)) + 'default))) + (list (append (list n (list 'quote face)) + (if last-arg-p '(nil t)))))))) + (setq n (1+ n)) + (setq args (cdr args))) + (setq keywords (append keywords (list (cons regexp hilighters)))) + (setq command-alist (cdr command-alist)))) + (append keywords + (list + (list muttrc-non-command-keyword-regexp 2 + font-lock-keyword-face) + (list muttrc-assignement-regexp 1 + font-lock-variable-name-face))) + )) + +;;; ------------------------------------------------------------ +;;; Mode specific customization +;;; ------------------------------------------------------------ + +(defconst muttrc-mode-map nil + "The keymap that is used in Muttrc mode.") +(if (null muttrc-mode-map) + (setq muttrc-mode-map + (let ((map (make-sparse-keymap)) + (help-map (make-sparse-keymap)) + (ctrl-c-map (make-sparse-keymap))) + (define-key map "\C-c" ctrl-c-map) + (define-key ctrl-c-map "c" 'muttrc-insert-command) + (define-key ctrl-c-map "C" 'comment-region) + (define-key ctrl-c-map "s" 'muttrc-set-variable) + (define-key ctrl-c-map "S" 'muttrc-unset-variable) + (define-key ctrl-c-map "f" 'muttrc-find-variable-in-buffer) + (define-key ctrl-c-map "h" help-map) + (define-key help-map "m" 'muttrc-find-manual-file) + (define-key help-map "v" 'muttrc-find-variable-help) + (define-key help-map "c" 'muttrc-find-command-help) + map))) + +(defvar muttrc-mode-syntax-table nil) +(when (null muttrc-mode-syntax-table) + (setq muttrc-mode-syntax-table (make-syntax-table)) + (modify-syntax-entry ?# "< " muttrc-mode-syntax-table) + (modify-syntax-entry ?\n "> " muttrc-mode-syntax-table) + (modify-syntax-entry ?\' "$ " muttrc-mode-syntax-table) + (modify-syntax-entry ?\' "$ " muttrc-mode-syntax-table) + (modify-syntax-entry ?_ "w " muttrc-mode-syntax-table) + (modify-syntax-entry ?- "w " muttrc-mode-syntax-table) + ) + +;;; ------------------------------------------------------------ +;;; The mode function itself. +;;; ------------------------------------------------------------ + +;;;###autoload +(defun muttrc-mode () + "Major mode for editing Muttrc files. +This function ends by invoking the function(s) `muttrc-mode-hook'. + +\\{muttrc-mode-map} +" + + (interactive) + (kill-all-local-variables) + + ;; Font lock. + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults + '('muttrc-font-lock-keywords + nil nil nil nil + (font-lock-syntactic-keywords . (("'[^'\n]*'" 0 "\""))))) + + ;; Comment stuff. + (make-local-variable 'comment-start) + (setq comment-start "#") + (make-local-variable 'comment-end) + (setq comment-end "") + (make-local-variable 'comment-start-skip) + (setq comment-start-skip "#+[ \t]*") + + ;; become the current major mode + (setq major-mode 'muttrc-mode) + (setq mode-name "Muttrc") + + ;; Activate keymap and syntax table. + (use-local-map muttrc-mode-map) + (set-syntax-table muttrc-mode-syntax-table) + + (run-hooks 'muttrc-mode-hook)) + + + +;;; ------------------------------------------------------------ +;;; Other functions +;;; ------------------------------------------------------------ + +(defun muttrc-perform-nonreg-test () + (interactive) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "^# Begin\\s-+\\(.*\\)$" nil t) + (let ((test-name (match-string-no-properties 1)) + (expr "")) + (catch 'loop + (while t + (or (= (forward-line 1) 0) + (throw 'loop t)) + (if (looking-at (format "^# End\\s-+%s\\s-*" + (regexp-quote test-name))) + (throw 'loop t)) + (if (looking-at "^# End\\s-+\\(.*\\)$") + (error "Found end of %s before %s" + (match-string-no-properties 1) test-name)) + (if (looking-at "^[^#]") + (error "End of %s not found" test-name)) + (if (looking-at "^#\\s-*\\(.*\\)$") + (setq expr (concat expr (match-string-no-properties 1)))))) + (if (eval (read expr)) + (message "Passed: %s" test-name) + (error "Failed: %s" test-name)))))) + +(defun muttrc-quote-string (s) + "Add a backslash on quotes and surround by quotes if needed." + (save-match-data + (cond ((or (not s) (equal s "")) "''") + ((string-match "^[^']*\\s-[^']*$" s) (format "'%s'" s)) + ((string-match "\\s-" s) + (concat "\"" + (mapconcat (lambda (c) + (if (eq c ?\") "\\\"" + (char-to-string c))) + s "") + "\"")) + (t s)))) + +(defun muttrc-prompt-string (prompt-base &optional default) + (if default + (format "%s [%s]: " prompt-base default) + (format "%s: " prompt-base))) + +(defun muttrc-token-around-point (alist &optional strip-fun) + (let ((word (and (functionp 'thing-at-point) + (funcall (or strip-fun 'identity) + (funcall 'thing-at-point 'word))))) + (if (and word (assoc word alist)) + word))) + +(defun muttrc-assignement (varname modifier &optional value) + (concat (format "%s%s" (or modifier "") varname) + (if (stringp value) + (format "=%s" + (muttrc-quote-string value)) + ""))) + +(defun muttrc-split-next-set-line () + "Returns the current line splitted into tokens. The result is a list +of tokens like: +\((CMD START END) ((VAR1 MODIFIER1 ASSIGNMENT1 START END) ... REST)). +Last element REST is one string that is the rest of the line." + (if (re-search-forward + "^\\s-*\\(set\\|unset\\|toggle\\|reset\\)\\s-+" nil t) + (let ((line (list (list (match-string-no-properties 1) + (match-beginning 1) + (match-end 1)))) + (limit (save-excursion + (end-of-line) + (point)))) + (catch 'done + (while (< (point) limit) + (or (looking-at + (format "\\<\\(inv\\|no\\)?\\([a-z][a-z_]*\\)\\>")) + (throw 'done t)) + (let ((modifier (match-string-no-properties 1)) + (varname (match-string-no-properties 2)) + (assignment nil)) + (goto-char (match-end 0)) + (skip-syntax-forward "-" limit) + (if (or (looking-at ; Set without quote + "=\\s-*\\([^'\" \t\n#]+\\)") + (looking-at ; Set with double quote (") + "=\\s-*\"\\(\\([^\"\\]\\|\\\\.\\)*\\)\"") + (looking-at ; Set with single quote (') + "=\\s-*'\\([^']*\\)'")) + (let ((type (let ((desc (assoc varname + muttrc-variables-alist))) + (if desc (cadr desc))))) + (if type + (and (eq type 'boolean) + (message "%s: can't assign a boolean" varname)) + (message "%s: unknown Muttrc variable" + varname)) + (setq assignment (match-string-no-properties 1)) + (goto-char (match-end 0)))) + (nconc line (list (list varname modifier + assignment + (match-beginning 0) + (match-end 0)))) + (skip-syntax-forward "-" limit)))) + (skip-syntax-backward "-") + (if (looking-at ".+$") + (nconc line (list (list (match-string-no-properties 0))))) + (end-of-line) + line))) + +(defun muttrc-splice-assignment (line varname) + "Returns a list where assignements for VARNAME are separated from +assignment for other variables." + (let ((l (cdr line)) + (in '()) + (out '())) + (while (and l (consp (car l))) + (let ((arg (car l))) + (if (string= (car arg) varname) + (setq in (append in (list arg))) + (setq out (append out (list arg))))) + (setq l (cdr l))) + (list in out))) + +(defun muttrc-new-value (cmd varname type modifier value default) + (if (eq type 'boolean) + (cond ((string= cmd "set") + (cond ((null modifier) t) + ((string= modifier "no") nil) + ((string= modifier "inv") (not value)))) + ((string= cmd "unset") + (cond ((null modifier) nil) + ((string= modifier "no") t) + ((string= modifier "inv") value))) + ((string= cmd "toggle") (not value)) + ((string= cmd "reset") + (cond ((null modifier) default) + ((string= modifier "no") (not default)) + ((string= modifier "inv") (not default))))) + (cond ((string= cmd "set") value) + ((string= cmd "unset") default) + ((string= cmd "toggle") + (error "%s: can't toggle non boolean" varname)) + ((string= cmd "reset") default)))) + +(defun muttrc-get-value-and-point (varname) + "Fetch the value of VARIABLE from the current buffer. It returns a +cons (VALUE . POINT) where POINT is the beginning of the line defining +VARNAME." + (save-excursion + (let ((var-descriptor (assoc varname muttrc-variables-alist))) + (or var-descriptor + (error "%s: unknown variable." varname)) + (goto-char (point-min)) + (let ((type (nth 0 (cdr var-descriptor))) + (default (nth 1 (cdr var-descriptor))) + (pos nil)) + (let ((value default)) + ;; We search all the definitions in the buffer because some + ;; users may use toggle or set inv... + (catch 'done + (while t + (let ((line (muttrc-split-next-set-line))) + (or line (throw 'done t)) + (let ((cmd (caar line)) + (assignments + (car (muttrc-splice-assignment line varname)))) + (if assignments + (setq pos (save-excursion + (beginning-of-line) + (point)))) + (while assignments + (let ((modifier (nth 1 (car assignments))) + (new-value (nth 2 (car assignments)))) + (setq value + (muttrc-new-value cmd varname type modifier + (or new-value value) + default))) + (setq assignments (cdr assignments))))))) + (cons value pos)))))) + +(defun muttrc-get-value (varname) + "Fetch the value of VARIABLE from the current buffer." + (let ((value (muttrc-get-value-and-point varname))) + (and value (car value)))) + +;;; ------------------------------------------------------------ +;;; Viewing manual +;;; ------------------------------------------------------------ + +(defvar muttrc-manual-buffer-name "*Mutt Manual*") + +(defun muttrc-find-manual-file-no-select () + "Convert overstriking and underlining to the correct fonts in a +file. The buffer does not visit the file." + (interactive) + (or (file-readable-p muttrc-manual-path) + (error "%s: file not found" muttrc-manual-path)) + (let ((buf (get-buffer-create muttrc-manual-buffer-name))) + (save-excursion + (set-buffer buf) + (if (not buffer-read-only) + (let ((insert-contents-fun + (condition-case nil + (and (require 'jka-compr) + 'jka-compr-insert-file-contents) + (error 'insert-file-contents)))) + (funcall insert-contents-fun muttrc-manual-path nil nil nil t) + (buffer-disable-undo buf) + (Man-fontify-manpage) + (set-buffer-modified-p nil) + (toggle-read-only) + (goto-char (point-min)))) + buf))) + +(defun muttrc-find-manual-file () + "Convert overstriking and underlining to the correct fonts in a +file. The buffer does not visit the file." + (interactive) + (switch-to-buffer-other-window + (muttrc-find-manual-file-no-select) t)) + +(defun muttrc-search-command-help-forward (command) + (when (re-search-forward + (format "^[ \t]*Usage:\\s-*\\(\\[un\\]\\)?%s" command) + nil t) + (goto-char (match-beginning 0)) + (forward-line -2) + (point))) + +(defun muttrc-search-variable-help-forward (command) + (when (and (re-search-forward + (format "^[ \t]*%s\\.?\\s-*%s\\s-*$" + "\\([1-9][0-9.]*\\)" + (regexp-quote variable)) + nil t) + (re-search-forward + (format "^[ \t]*%s\\.?\\s-*%s\\s-*$" + "\\([1-9][0-9.]*\\)" + (regexp-quote variable)) + nil t) + (re-search-forward + (format "^[ \t]*%s\\.?\\s-*%s\\s-*$" + (regexp-quote (match-string-no-properties 1)) + (regexp-quote variable)) + nil t)) + (goto-char (match-beginning 0)) + (point))) + +(defun muttrc-find-help (search-fun topic) + "Find an help topic in the manual and display it. Returns the manual +buffer." + (let ((buf (muttrc-find-manual-file-no-select))) + (let ((win (get-buffer-window buf)) + help-start) + (save-excursion + (set-buffer buf) + (goto-char (point-min)) + (or (funcall search-fun topic) + (error "%s: entry not found in Mutt manual." command)) + (setq help-start (point)) + (unless (get-buffer-window buf) + (switch-to-buffer-other-window buf t)) + (set-window-start win help-start))) + buf)) + +(defun muttrc-find-command-help (&optional command) + (interactive + (let ((word (muttrc-token-around-point muttrc-command-alist))) + (list (muttrc-get-from-list "Command" word 'muttrc-command-alist t)))) + (muttrc-find-help 'muttrc-search-command-help-forward + (if (string-match "^un\\(.*\\)$" command) + (match-string-no-properties 1 command) + command))) + +(defun muttrc-find-variable-help (&optional variable) + (interactive + (list + (let ((word (muttrc-token-around-point + muttrc-variables-alist + (function + (lambda (word) + (if (and word + (string-match "^\\(no\\|inv\\)\\(.*\\)$" word)) + (match-string-no-properties 2 word) + word)))))) + (muttrc-get-from-list "Variable" word 'muttrc-variables-alist)))) + (muttrc-find-help 'muttrc-search-variable-help-forward variable)) + +(defun muttrc-bury-manual-buffer () + (let ((buf (get-buffer muttrc-manual-buffer-name))) + (if buf (bury-buffer buf)))) + +;;; ------------------------------------------------------------ +;;; Argument handlers +;;; ------------------------------------------------------------ + +(defun muttrc-call-arg-handler (key default &optional prompt) + "Call the function that properly prompts for an argument type." + (let ((handler-args (assoc key muttrc-arg-handler-alist))) + (or handler-args + (error "%s: unknown argument type." (symbol-name key))) + (let ((cmd (nth 0 (cdr handler-args))) + (default-prompt (nth 1 (cdr handler-args))) + (args (cdr (cddr handler-args)))) + (apply cmd (or prompt default-prompt) default args)))) + +(defun muttrc-get-boolean (prompt &optional default) + "Prompt for a boolean." + (y-or-n-p (format "%s? " prompt))) + +(defun muttrc-get-number (prompt default) + "Prompt for a string and return DEFAULT if the string is empty" + (or (read-from-minibuffer (muttrc-prompt-string prompt default)) + default)) + +(defun muttrc-get-string (prompt default) + "Prompt for a string and return DEFAULT if the string is empty" + (let ((s (read-from-minibuffer (muttrc-prompt-string prompt default)))) + (if (> (length s) 0) s default))) + +(defun muttrc-get-word (prompt default) + "Prompt for a word and return DEFAULT if it is empty" + (let ((s (read-from-minibuffer (muttrc-prompt-string prompt default)))) + (or (string-match "^\\w*$" s) + (error "%s: invalid entry, expecting a word" s)) + (if (> (length s) 0) s default))) + +(defun muttrc-get-from-list (prompt default list &optional require-match) + "Prompt for a string from list and return DEFAULT if the string is empty" + (let ((s (completing-read (muttrc-prompt-string prompt default) + (symbol-value list) + nil require-match))) + (if (> (length s) 0) s default))) + +(defun muttrc-get-path (prompt default) + "Prompt for a path and return DEFAULT if the string is empty. The +muttrc folder prefix is replaced by MUTTRC-FOLDER-ABBREV." + (let* ((folder (muttrc-get-value "folder")) + (path (read-file-name (muttrc-prompt-string prompt default) + folder folder))) + (let ((compacted-path + (if (string-match (format "^%s/?\\(.*\\)$" (regexp-quote folder)) + path) + (format "%s%s" + (char-to-string muttrc-folder-abbrev) + (match-string-no-properties 1 path)) + path))) + (if (not (string= compacted-path + (char-to-string muttrc-folder-abbrev))) + compacted-path + default)))) + +(defun muttrc-get-assignment (&optional prompt default + with-value-p) + (let ((varname (completing-read (muttrc-prompt-string prompt default) + muttrc-variables-alist))) + (if (assoc varname muttrc-variables-alist) + (let* ((type (cadr (assoc varname muttrc-variables-alist))) + (default (car-safe (muttrc-get-value-and-point varname))) + (value (if with-value-p + (muttrc-call-arg-handler type default "Value")))) + (if with-value-p + (muttrc-assignement varname + (and (eq type 'boolean) + (not value) + "no") + value) + varname)) + default))) + +;;; ------------------------------------------------------------ +;;; Commands insertion +;;; ------------------------------------------------------------ + +(defun muttrc-get-command (&optional prompt default) + "Prompts the usr for a command to enter and asks for all the arguments." + (let* ((cmd (muttrc-get-from-list "Command" nil 'muttrc-command-alist t)) + (cmd-descriptor (cdr (assoc cmd muttrc-command-alist))) + (arg-list-type (nth 0 cmd-descriptor)) + (repeat-p (nth 1 cmd-descriptor)) + (optional-p (nth 2 cmd-descriptor)) + (arg-list-value (list cmd))) + (save-window-excursion + (if (and muttrc-display-help) + (save-excursion + (muttrc-find-command-help cmd))) + (while arg-list-type + (let* ((arg-type (caar arg-list-type)) + (arg (apply 'muttrc-call-arg-handler + (append (list arg-type nil) + (cdar arg-list-type))))) + (if arg + (progn + (nconc arg-list-value + (list (if (eq arg-type 'assignment) + arg ; assignment are quoted by handler + (muttrc-quote-string arg)))) + (if (and repeat-p + (null (cdr arg-list-type))) + (setq optional-p t) + (setq arg-list-type (cdr arg-list-type)))) + (if (and (null (cdr arg-list-type)) + optional-p) + (setq arg-list-type nil) + (error "Argument required")))))) + (muttrc-bury-manual-buffer) + (mapconcat 'identity arg-list-value " "))) + +(defun muttrc-get-statement (&optional prompt default) + (let ((muttrc-command-alist muttrc-statement-alist)) + (muttrc-get-command prompt default))) + +(defun muttrc-insert-command () + "Insert a muttrc command on the current line." + (interactive) + (let ((cmd-line (muttrc-get-command))) + (beginning-of-line) + (or (eolp) (forward-line 1)) + (insert cmd-line) + (newline))) + +;;; ------------------------------------------------------------ +;;; Setting variables +;;; ------------------------------------------------------------ + +(defun muttrc-update-current-line (varname type &optional value) + "Rewrites the current line by setting VARNAME to VALUE. If the +statement is not \"set\", the variable is removed. In set statement, +it is removed if the value is NIL and the variable is not a boolean. +The function returns t is the variable is really assigned in the line." + (let* ((line (muttrc-split-next-set-line)) + (cmd (caar line)) + (kill-whole-line t) + (args "") + (set-p nil)) + (beginning-of-line) + (kill-line) + (let ((l (cdr line))) + (while l + (let ((elt (car l))) + (if (consp elt) + (let ((this-var (nth 0 elt)) + (this-modifier (nth 1 elt)) + (this-value (nth 2 elt))) + (let ((assignement + (if (string= this-var varname) + (when (string= cmd "set") + (setq set-p t) + (cond ((eq type 'boolean) + (muttrc-assignement varname + (if (not value) "no") + value)) + (value + (muttrc-assignement varname nil value)) + (t (setq set-p nil)))) + (muttrc-assignement this-var + this-modifier + this-value)))) + (if assignement + (setq args (concat args " " assignement))))) + (setq args (concat args elt)))) + (setq l (cdr l)))) + (when (not (string= args "")) + (insert cmd) + (insert args) + (newline)) + (backward-char 1) + set-p)) + +(defun muttrc-update-variable (varname type value pos) + (catch 'done + (when pos + (goto-char pos) + (if (muttrc-update-current-line varname type value) + (throw 'done t))) + (end-of-line) + (let ((cr-after-p (bolp)) + (cmd (if (or value (eq type 'boolean)) "set" "unset")) + (modifier (if (and (not value) (eq type 'boolean)) "no"))) + (or cr-after-p (newline)) + (insert cmd " " + (muttrc-assignement varname modifier value)) + (if cr-after-p (newline)))) + t) + +(defun muttrc-set-variable (&optional varname type value pos) + (interactive + (let* ((varname (muttrc-get-from-list "Variable" nil + 'muttrc-variables-alist t)) + (type (cadr (assoc varname muttrc-variables-alist))) + (default (muttrc-get-value-and-point varname))) + (list varname type + (save-window-excursion + (if muttrc-display-help + (save-excursion + (muttrc-find-variable-help varname))) + (muttrc-call-arg-handler type (car default))) + (cdr default)))) + (muttrc-bury-manual-buffer) + (muttrc-update-variable varname type value pos)) + +(defun muttrc-unset-variable (&optional varname type pos) + (interactive + (let* ((varname (muttrc-get-from-list "Variable" nil + 'muttrc-variables-alist t)) + (type (cadr (assoc varname muttrc-variables-alist))) + (default (muttrc-get-value-and-point varname))) + (list varname type (cdr default)))) + (muttrc-update-variable varname type nil pos)) + +(defun muttrc-find-variable-in-buffer (&optional varname) + (interactive + (list (muttrc-get-from-list "Variable" nil + 'muttrc-variables-alist t))) + (let* ((var-info (muttrc-get-value-and-point varname)) + (value (car var-info)) + (pos (cdr-safe var-info))) + (if pos + (goto-char pos) + (progn + (message "%s: variable not set (default: %s)" varname value))))) + +;;; ------------------------------------------------------------ +;;; Almost the end +;;; ------------------------------------------------------------ + +(provide 'muttrc-mode) + +;;; muttrc-mode.el ends here diff --git a/emacs.d/functions.el b/emacs.d/functions.el new file mode 100644 index 0000000..6d2a5e5 --- /dev/null +++ b/emacs.d/functions.el @@ -0,0 +1,191 @@ +(defun quote-region () + (interactive) + (let ((beginning (region-beginning)) + (end (region-end))) + (save-excursion + (goto-char end) + (insert ?') + (goto-char beginning) + (insert ?')))) + +(defun what-face (pos) + "Find out which face the current position uses" + (interactive "d") + (let ((face (or (get-char-property (point) 'read-face-name) + (get-char-property (point) 'face)))) + (if face + (message "Face: %s" face) + (message "No face at %d" pos)))) + +(defun my-comp-finish-function (buf str) + "Don't show compilation window if everything went ok" + (if (string-match "exited abnormally" str) + ;; there were errors + (message "compilation errors, press C-x ` to visit") + ;; no errors, make the compilation window go away in 0.5 seconds + (run-at-time 0.5 nil 'delete-windows-on buf) + (message "NO COMPILATION ERRORS!"))) + +(defun fullscreen () + "Fill the entire screen with emacs" + (interactive) + (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 + '(2 "_NET_WM_STATE_MAXIMIZED_VERT" 0)) + (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 + '(2 "_NET_WM_STATE_MAXIMIZED_HORZ" 0))) + +(defun c-toggle-header-source () + "Toggle between a C source and header file" + (interactive) + (let ((ext (file-name-extension (buffer-file-name))) + (noext (file-name-sans-extension (buffer-file-name)))) + (if (string= (substring ext 0 1) "c") + (find-file (concat noext ".h")) + (find-file (concat noext ".c"))))) + +(defun browse-to-current-file () + "Show current file in browser" + (interactive) + (browse-url buffer-file-name)) + +(defun comment-line () + "Toggle comment on a line" + (interactive) + (save-excursion + (beginning-of-line) + (insert "//"))) + +(defun add-php-keywords () + "Designed for c and c-style languages + +Currently adds | & ! . + = - / % * , < > ? : ->" + ;; Add ! at the beginning of font lock + (font-lock-add-keywords + 'php-mode + '(("\\([!]\\|\\=>\\)" 1 font-lock-operator-face))) + ;; Add the rest at the end of font lock + (font-lock-add-keywords + 'php-mode + '(("\\(->\\|[|.+=&/%*,:?<>-]\\)" 1 font-lock-operator-face) + ("\\(;\\)" 1 font-lock-end-statement)) 1)) + +(defun add-html-keywords () + "Designed for html, show some smarty tags" + (font-lock-add-keywords + 'html-mode + '(("{\\(\\*.*\\*\\)}" 1 font-comment-face) + ("{\\/?\\(extends\\|block\\|foreach\\|if\\)" + 1 font-lock-builtin-face) + ("\\$\\(\\(?:\\sw\\|\\s_\\)+\\)\\(?:|\\(\\(?:\\sw\\|\\s_\\)+\\):\\)" + (1 font-lock-variable-name-face) + (2 font-lock-function-name-face)) + ("\\$\\(\\(?:\\sw\\|\\s_\\)+\\)" + 1 font-lock-variable-name-face) + ("{\\(\\(?:\\sw\\|\\s_\\)+\\).*}" + 1 font-lock-function-name-face)))) + +(defun buffer-major-mode (buffer-or-string) + "Find out which major-mode is currently used" + (with-current-buffer buffer-or-string major-mode)) + +(defun set-column-marker () + "Default column markers" + (column-marker-1 73) + (column-marker-2 81)) + +(defun setup-system-frame-colours (&rest frame) + (let ((f (if (car frame) + (car frame) + (selected-frame)))) + (progn + (set-frame-font "-*-tamsyn-medium-*-*-*-15-*-*-*-*-80-*-*")))) + +(defun show-init-sections () + (interactive) + (occur ";;\s +.*\s +;;") + (other-window 1)) + +(defun list-functions () + (interactive) + (occur + "\\(?:\\(?:private\\|protected\\|public\\) \\)?function \\(?:\\sw\\)+(\\sw*)")) + +(defun insert-init-title (title width) + (interactive "stitle: \nnwidth: ") + (insert-char ?\; width) + (insert "\n;;") + (insert-char ?\s (floor (/ (- (- width 4.0) (length title)) 2))) + (insert title) + (insert-char ?\s (ceiling (/ (- (- width 4.0) (length title)) 2))) + (insert ";;\n") + (insert-char ?\; width)) + +(defun x-init () + "Start ide-skel and set some keys") + +(defun cli-init () + "Add a space to the linum column" + (setq linum-format "%d ")) + +(defun replace-occurrences (from to) + (save-excursion + (goto-char (point-min)) + (while (search-forward from nil t) + (replace-match to)))) + +(defun replace-html-special-chars () + (replace-occurrences "é" "é")) + +(defun on-before-save () + (if (eq (buffer-major-mode (current-buffer)) 'html-mode) + (replace-html-special-chars)) + (if (not (eq (buffer-major-mode (current-buffer)) 'markdown-mode)) + (delete-trailing-whitespace))) + +(defun on-after-save () + (let ((fname (buffer-file-name))) + (let ((suffix (file-name-extension fname))) + (if (string-equal suffix "el") + (byte-compile-file fname))))) + +(defun on-prog-mode () + (font-lock-add-keywords + nil + '(("\\b\\(0[xX][0-9a-fA-F]+[lL]?\\|[0-9]+\\.?[0-9]*\\([eE][-+]?[0-9]+\\)?\\([lL]\\|[fF]\\|[dD]\\)?\\)\\b" + 0 font-lock-constant-face) + ("\\b\\(\\.[0-9]+\\([eE][-+]?[0-9]+\\)?\\([lL]\\|[fF]\\|[dD]\\)?\\)\\b" + 0 font-lock-constant-face))) + (set-column-marker) + (rainbow-delimiters-mode)) + +(defun on-c-mode () + (local-set-key [f8] 'c-toggle-header-source) + (local-set-key [f9] 'compile) + (local-set-key [C-m] 'newline-and-indent) + (local-set-key [C-return] 'newline)) + +(defun on-html-mode () + (local-set-key [f9] 'browse-to-current-file) + (auto-fill-mode) + (set-column-marker)) + +(defun on-markdown-mode () + (whitespace-mode) + (auto-fill-mode)) + +(defun on-org-mode () + (flyspell-mode 1) + (auto-fill-mode 1)) + +(defun on-php-mode () + (defvar php-warn-if-mumamo-off nil) + (setq case-fold-search t) + (c-set-offset 'arglist-intro '+) + (c-set-offset 'arglist-close '0) + (column-marker-1 76) + (column-marker-2 81) + (local-set-key [f6] 'comment-line)) + +(defun on-mail-mode () + (turn-on-auto-fill) + (search-forward "\n\n")) diff --git a/emacs.el b/emacs.el index 5b744e3..ef5ceb2 100644 --- a/emacs.el +++ b/emacs.el @@ -6,6 +6,7 @@ (add-to-list 'load-path "~/.emacs.d/naquadah-theme") (add-to-list 'load-path "~/.emacs.d/elisp/markdown-mode") (add-to-list 'load-path "~/.emacs.d/elisp/git-commit-mode") +(add-to-list 'load-path "~/.emacs.d/elisp/lua-mode") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; REQUIRES ;; @@ -20,217 +21,28 @@ (require 'server) (require 'org-publish) (require 'htmlize) +(require 'muttrc-mode) +(load-file "~/.emacs.d/functions.el") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; AUTOLOADS ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(autoload 'vala-mode "vala-mode" - "A Major mode for editing Vala files" t) -(autoload 'csharp-mode "csharp-mode" - "A Major mode for editing C# files" t) -(autoload 'sqlplus-mode "sqlplus" - "A Major mode for communicating with Oracle" t) -(autoload 'batch-mode "batch-mode" - "A Major mode for editing Batch files" t) -(autoload 'lua-mode "lua-mode" - "A Major mode for editing Lua files" t) -(autoload 'php-mode "php-mode-improved" - "A Major mode for editing PHP files" t) -(autoload 'graphviz-dot-mode "graphviz-dot-mode" - "A Major mode for editing graphviz dot files" t) -(autoload 'cmake-mode "cmake-mode" - "A major-mode for editing CMake sources" t) -(autoload 'markdown-mode "markdown-mode" - "Major mode for editing Markdown files" t) -(autoload 'rainbow-mode "rainbow-mode" - "A Minor mode for showing colors inline" t) -(autoload 'stumpwm-mode "stumpwm-mode" - "Special lisp mode for evaluating code into running stumpwm" t) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; DEFUNS ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(defun what-face (pos) - "Find out which face the current position uses" - (interactive "d") - (let ((face (or (get-char-property (point) 'read-face-name) - (get-char-property (point) 'face)))) - (if face - (message "Face: %s" face) - (message "No face at %d" pos)))) - -(defun my-comp-finish-function (buf str) - "Don't show compilation window if everything went ok" - (if (string-match "exited abnormally" str) - ;; there were errors - (message "compilation errors, press C-x ` to visit") - ;; no errors, make the compilation window go away in 0.5 seconds - (run-at-time 0.5 nil 'delete-windows-on buf) - (message "NO COMPILATION ERRORS!"))) - -(defun fullscreen () - "Fill the entire screen with emacs" - (interactive) - (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 - '(2 "_NET_WM_STATE_MAXIMIZED_VERT" 0)) - (x-send-client-message nil 0 nil "_NET_WM_STATE" 32 - '(2 "_NET_WM_STATE_MAXIMIZED_HORZ" 0))) - -(defun c-toggle-header-source () - "Toggle between a C source and header file" - (interactive) - (let ((ext (file-name-extension (buffer-file-name))) - (noext (file-name-sans-extension (buffer-file-name)))) - (if (string= (substring ext 0 1) "c") - (find-file (concat noext ".h")) - (find-file (concat noext ".c"))))) - -(defun browse-to-current-file () - "Show current file in browser" - (interactive) - (browse-url buffer-file-name)) - -(defun comment-line () - "Toggle comment on a line" - (interactive) - (save-excursion - (beginning-of-line) - (insert "//"))) - -(defun add-php-keywords () - "Designed for c and c-style languages - -Currently adds | & ! . + = - / % * , < > ? : ->" - ;; Add ! at the beginning of font lock - (font-lock-add-keywords - 'php-mode - '(("\\([!]\\|\\=>\\)" 1 font-lock-operator-face))) - ;; Add the rest at the end of font lock - (font-lock-add-keywords - 'php-mode - '(("\\(->\\|[|.+=&/%*,:?<>-]\\)" 1 font-lock-operator-face) - ("\\(;\\)" 1 font-lock-end-statement)) 1)) - -(defun add-html-keywords () - "Designed for html, show some smarty tags" - (font-lock-add-keywords - 'html-mode - '(("{\\(\\*.*\\*\\)}" 1 font-comment-face) - ("{\\/?\\(extends\\|block\\|foreach\\|if\\)" - 1 font-lock-builtin-face) - ("\\$\\(\\(?:\\sw\\|\\s_\\)+\\)\\(?:|\\(\\(?:\\sw\\|\\s_\\)+\\):\\)" - (1 font-lock-variable-name-face) - (2 font-lock-function-name-face)) - ("\\$\\(\\(?:\\sw\\|\\s_\\)+\\)" - 1 font-lock-variable-name-face) - ("{\\(\\(?:\\sw\\|\\s_\\)+\\).*}" - 1 font-lock-function-name-face)))) - -(defun buffer-major-mode (buffer-or-string) - "Find out which major-mode is currently used" - (with-current-buffer buffer-or-string major-mode)) - -(defun set-column-marker () - "Default column markers" - (column-marker-1 73) - (column-marker-2 81)) - -(defun setup-system-frame-colours (&rest frame) - (let ((f (if (car frame) - (car frame) - (selected-frame)))) - (progn - (set-frame-font "-*-tamsyn-medium-*-*-*-15-*-*-*-*-80-*-*")))) - -(defun show-init-sections () - (interactive) - (occur ";;\s +.*\s +;;") - (other-window 1)) - -(defun list-functions () - (interactive) - (occur - "\\(?:\\(?:private\\|protected\\|public\\) \\)?function \\(?:\\sw\\)+(\\sw*)")) - -(defun insert-init-title (title width) - (interactive "stitle: \nnwidth: ") - (insert-char ?\; width) - (insert "\n;;") - (insert-char ?\s (floor (/ (- (- width 4.0) (length title)) 2))) - (insert title) - (insert-char ?\s (ceiling (/ (- (- width 4.0) (length title)) 2))) - (insert ";;\n") - (insert-char ?\; width)) - -(defun x-init () - "Start ide-skel and set some keys") - -(defun cli-init () - "Add a space to the linum column" - (setq linum-format "%d ")) - -(defun replace-occurrences (from to) - (save-excursion - (goto-char (point-min)) - (while (search-forward from nil t) - (replace-match to)))) - -(defun replace-html-special-chars () - (replace-occurrences "é" "é")) - -(defun on-before-save () - (if (eq (buffer-major-mode (current-buffer)) 'html-mode) - (replace-html-special-chars)) - (if (not (eq (buffer-major-mode (current-buffer)) 'markdown-mode)) - (delete-trailing-whitespace))) - -(defun on-after-save () - (let ((fname (buffer-file-name))) - (let ((suffix (file-name-extension fname))) - (if (string-equal suffix "el") - (byte-compile-file fname))))) - -(defun on-prog-mode () - (font-lock-add-keywords - nil - '(("\\b\\(0[xX][0-9a-fA-F]+[lL]?\\|[0-9]+\\.?[0-9]*\\([eE][-+]?[0-9]+\\)?\\([lL]\\|[fF]\\|[dD]\\)?\\)\\b" - 0 font-lock-constant-face) - ("\\b\\(\\.[0-9]+\\([eE][-+]?[0-9]+\\)?\\([lL]\\|[fF]\\|[dD]\\)?\\)\\b" - 0 font-lock-constant-face))) - (set-column-marker) - (rainbow-delimiters-mode)) - -(defun on-c-mode () - (local-set-key [f8] 'c-toggle-header-source) - (local-set-key [f9] 'compile) - (local-set-key [C-m] 'newline-and-indent) - (local-set-key [C-return] 'newline)) - -(defun on-html-mode () - (local-set-key [f9] 'browse-to-current-file) - (auto-fill-mode) - (set-column-marker)) - -(defun on-markdown-mode () - (whitespace-mode) - (auto-fill-mode)) - -(defun on-org-mode () - (flyspell-mode 1) - (auto-fill-mode 1)) - -(defun on-php-mode () - (defvar php-warn-if-mumamo-off nil) - (setq case-fold-search t) - (c-set-offset 'arglist-intro '+) - (c-set-offset 'arglist-close '0) - (column-marker-1 76) - (column-marker-2 81) - (local-set-key [f6] 'comment-line)) - -(defun on-mail-mode () - (turn-on-auto-fill) - (search-forward "\n\n")) +(autoload 'vala-mode "vala-mode" "Major mode for Vala" t) +(autoload 'csharp-mode "csharp-mode" "Major mode for C#" t) +(autoload 'sqlplus-mode "sqlplus" "Major mode for PL/SQL" t) +(autoload 'batch-mode "batch-mode" "Major mode for Batch" t) +(autoload 'lua-mode "lua-mode" "A Major mode for Lua" t) +(autoload 'php-mode "php-mode-improved" "Major mode for PHP" t) +(autoload 'graphviz-dot-mode "graphviz-dot-mode" "Major mode for dot" t) +(autoload 'cmake-mode "cmake-mode" "Major mode for CMake" t) +(autoload 'markdown-mode "markdown-mode" "Major mode for Markdown" t) +(autoload 'rainbow-mode "rainbow-mode" "Minor mode for colors" t) +(autoload 'stumpwm-mode "stumpwm-mode" "Major mode for stumpwm" t) +(autoload 'muttrc-mode "muttrc-mode" "Major mode for muttrc" t) +;; Go +(autoload 'go-mode "go-mode" "Major mode for google go" t) +(autoload 'gofmt "go-mode" "" t) +(autoload 'go-fmt-before-save "go-mode" "" t) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; VARIABLES ;; @@ -260,6 +72,7 @@ Currently adds | & ! . + = - / % * , < > ? : ->" (add-to-list 'auto-mode-alist '("\\.css$" . css-mode)) (add-to-list 'auto-mode-alist '("mutt-cloud-" . mail-mode)) (add-to-list 'auto-mode-alist '("stumpwmrc" . stumpwm-mode)) +(add-to-list 'auto-mode-alist '("\\.go$" . go-mode)) (add-to-list 'file-coding-system-alist '("\\.vala$" . utf-8)) (add-to-list 'file-coding-system-alist '("\\.vapi$" . utf-8)) @@ -275,7 +88,10 @@ Currently adds | & ! . + = - / % * , < > ? : ->" (global-set-key [f5] '(lambda () (interactive) (revert-buffer nil t nil))) - +(global-set-key [M-left] 'windmove-left) +(global-set-key [M-right] 'windmove-right) +(global-set-key [M-up] 'windmove-up) +(global-set-key [M-down] 'windmove-down) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; THEME SETTINGS ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -437,9 +253,6 @@ Currently adds | & ! . + = - / % * , < > ? : ->" " characters */" '(fill-paragraph)) -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; AUTORUN ;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (org-crypt-use-before-save-magic) (ad-activate 'server-create-window-system-frame) (add-php-keywords) -- cgit v1.2.3-54-g00ecf