| 1 | ;;; sieve-mode.el --- Sieve code editing commands for Emacs |
| 2 | |
| 3 | ;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, |
| 4 | ;; 2010, 2011 Free Software Foundation, Inc. |
| 5 | |
| 6 | ;; Author: Simon Josefsson <simon@josefsson.org> |
| 7 | |
| 8 | ;; This file is part of GNU Emacs. |
| 9 | |
| 10 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
| 11 | ;; it under the terms of the GNU General Public License as published by |
| 12 | ;; the Free Software Foundation, either version 3 of the License, or |
| 13 | ;; (at your option) any later version. |
| 14 | |
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | ;; GNU General Public License for more details. |
| 19 | |
| 20 | ;; You should have received a copy of the GNU General Public License |
| 21 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
| 22 | |
| 23 | ;;; Commentary: |
| 24 | |
| 25 | ;; This file contain editing mode functions and font-lock support for |
| 26 | ;; editing Sieve scripts. It sets up C-mode with support for |
| 27 | ;; sieve-style #-comments and a lightly hacked syntax table. It was |
| 28 | ;; strongly influenced by awk-mode.el. |
| 29 | ;; |
| 30 | ;; Put something similar to the following in your .emacs to use this file: |
| 31 | ;; |
| 32 | ;; (load "~/lisp/sieve") |
| 33 | ;; (setq auto-mode-alist (cons '("\\.siv\\'" . sieve-mode) auto-mode-alist)) |
| 34 | ;; |
| 35 | ;; References: |
| 36 | ;; |
| 37 | ;; RFC 3028, |
| 38 | ;; "Sieve: A Mail Filtering Language", |
| 39 | ;; by Tim Showalter. |
| 40 | ;; |
| 41 | ;; Release history: |
| 42 | ;; |
| 43 | ;; 2001-03-02 version 1.0 posted to gnu.emacs.sources |
| 44 | ;; version 1.1 change file extension into ".siv" (official one) |
| 45 | ;; added keymap and menubar to hook into sieve-manage |
| 46 | ;; 2001-10-31 version 1.2 committed to Oort Gnus |
| 47 | |
| 48 | ;;; Code: |
| 49 | |
| 50 | (autoload 'sieve-manage "sieve") |
| 51 | (autoload 'sieve-upload "sieve") |
| 52 | (eval-when-compile |
| 53 | (require 'font-lock)) |
| 54 | |
| 55 | (defgroup sieve nil |
| 56 | "Sieve." |
| 57 | :group 'languages) |
| 58 | |
| 59 | (defcustom sieve-mode-hook nil |
| 60 | "Hook run in sieve mode buffers." |
| 61 | :group 'sieve |
| 62 | :type 'hook) |
| 63 | |
| 64 | ;; Font-lock |
| 65 | |
| 66 | (defvar sieve-control-commands-face 'sieve-control-commands |
| 67 | "Face name used for Sieve Control Commands.") |
| 68 | |
| 69 | (defface sieve-control-commands |
| 70 | '((((type tty) (class color)) (:foreground "blue" :weight light)) |
| 71 | (((class grayscale) (background light)) (:foreground "LightGray" :bold t)) |
| 72 | (((class grayscale) (background dark)) (:foreground "DimGray" :bold t)) |
| 73 | (((class color) (background light)) (:foreground "Orchid")) |
| 74 | (((class color) (background dark)) (:foreground "LightSteelBlue")) |
| 75 | (t (:bold t))) |
| 76 | "Face used for Sieve Control Commands." |
| 77 | :group 'sieve) |
| 78 | ;; backward-compatibility alias |
| 79 | (put 'sieve-control-commands-face 'face-alias 'sieve-control-commands) |
| 80 | (put 'sieve-control-commands-face 'obsolete-face "22.1") |
| 81 | |
| 82 | (defvar sieve-action-commands-face 'sieve-action-commands |
| 83 | "Face name used for Sieve Action Commands.") |
| 84 | |
| 85 | (defface sieve-action-commands |
| 86 | '((((type tty) (class color)) (:foreground "blue" :weight bold)) |
| 87 | (((class color) (background light)) (:foreground "Blue")) |
| 88 | (((class color) (background dark)) (:foreground "LightSkyBlue")) |
| 89 | (t (:inverse-video t :bold t))) |
| 90 | "Face used for Sieve Action Commands." |
| 91 | :group 'sieve) |
| 92 | ;; backward-compatibility alias |
| 93 | (put 'sieve-action-commands-face 'face-alias 'sieve-action-commands) |
| 94 | (put 'sieve-action-commands-face 'obsolete-face "22.1") |
| 95 | |
| 96 | (defvar sieve-test-commands-face 'sieve-test-commands |
| 97 | "Face name used for Sieve Test Commands.") |
| 98 | |
| 99 | (defface sieve-test-commands |
| 100 | '((((type tty) (class color)) (:foreground "magenta")) |
| 101 | (((class grayscale) (background light)) |
| 102 | (:foreground "LightGray" :bold t :underline t)) |
| 103 | (((class grayscale) (background dark)) |
| 104 | (:foreground "Gray50" :bold t :underline t)) |
| 105 | (((class color) (background light)) (:foreground "CadetBlue")) |
| 106 | (((class color) (background dark)) (:foreground "Aquamarine")) |
| 107 | (t (:bold t :underline t))) |
| 108 | "Face used for Sieve Test Commands." |
| 109 | :group 'sieve) |
| 110 | ;; backward-compatibility alias |
| 111 | (put 'sieve-test-commands-face 'face-alias 'sieve-test-commands) |
| 112 | (put 'sieve-test-commands-face 'obsolete-face "22.1") |
| 113 | |
| 114 | (defvar sieve-tagged-arguments-face 'sieve-tagged-arguments |
| 115 | "Face name used for Sieve Tagged Arguments.") |
| 116 | |
| 117 | (defface sieve-tagged-arguments |
| 118 | '((((type tty) (class color)) (:foreground "cyan" :weight bold)) |
| 119 | (((class grayscale) (background light)) (:foreground "LightGray" :bold t)) |
| 120 | (((class grayscale) (background dark)) (:foreground "DimGray" :bold t)) |
| 121 | (((class color) (background light)) (:foreground "Purple")) |
| 122 | (((class color) (background dark)) (:foreground "Cyan")) |
| 123 | (t (:bold t))) |
| 124 | "Face used for Sieve Tagged Arguments." |
| 125 | :group 'sieve) |
| 126 | ;; backward-compatibility alias |
| 127 | (put 'sieve-tagged-arguments-face 'face-alias 'sieve-tagged-arguments) |
| 128 | (put 'sieve-tagged-arguments-face 'obsolete-face "22.1") |
| 129 | |
| 130 | |
| 131 | (defconst sieve-font-lock-keywords |
| 132 | (eval-when-compile |
| 133 | (list |
| 134 | ;; control commands |
| 135 | (cons (regexp-opt '("require" "if" "else" "elsif" "stop")) |
| 136 | 'sieve-control-commands-face) |
| 137 | ;; action commands |
| 138 | (cons (regexp-opt '("fileinto" "redirect" "reject" "keep" "discard")) |
| 139 | 'sieve-action-commands-face) |
| 140 | ;; test commands |
| 141 | (cons (regexp-opt '("address" "allof" "anyof" "exists" "false" |
| 142 | "true" "header" "not" "size" "envelope")) |
| 143 | 'sieve-test-commands-face) |
| 144 | (cons "\\Sw+:\\sw+" |
| 145 | 'sieve-tagged-arguments-face)))) |
| 146 | |
| 147 | ;; Syntax table |
| 148 | |
| 149 | (defvar sieve-mode-syntax-table nil |
| 150 | "Syntax table in use in sieve-mode buffers.") |
| 151 | |
| 152 | (if sieve-mode-syntax-table |
| 153 | () |
| 154 | (setq sieve-mode-syntax-table (make-syntax-table)) |
| 155 | (modify-syntax-entry ?\\ "\\" sieve-mode-syntax-table) |
| 156 | (modify-syntax-entry ?\n "> " sieve-mode-syntax-table) |
| 157 | (modify-syntax-entry ?\f "> " sieve-mode-syntax-table) |
| 158 | (modify-syntax-entry ?\# "< " sieve-mode-syntax-table) |
| 159 | (modify-syntax-entry ?/ "." sieve-mode-syntax-table) |
| 160 | (modify-syntax-entry ?* "." sieve-mode-syntax-table) |
| 161 | (modify-syntax-entry ?+ "." sieve-mode-syntax-table) |
| 162 | (modify-syntax-entry ?- "." sieve-mode-syntax-table) |
| 163 | (modify-syntax-entry ?= "." sieve-mode-syntax-table) |
| 164 | (modify-syntax-entry ?% "." sieve-mode-syntax-table) |
| 165 | (modify-syntax-entry ?< "." sieve-mode-syntax-table) |
| 166 | (modify-syntax-entry ?> "." sieve-mode-syntax-table) |
| 167 | (modify-syntax-entry ?& "." sieve-mode-syntax-table) |
| 168 | (modify-syntax-entry ?| "." sieve-mode-syntax-table) |
| 169 | (modify-syntax-entry ?_ "_" sieve-mode-syntax-table) |
| 170 | (modify-syntax-entry ?\' "\"" sieve-mode-syntax-table)) |
| 171 | |
| 172 | ;; Key map definition |
| 173 | |
| 174 | (defvar sieve-mode-map |
| 175 | (let ((map (make-sparse-keymap))) |
| 176 | (define-key map "\C-c\C-l" 'sieve-upload) |
| 177 | (define-key map "\C-c\C-c" 'sieve-upload-and-bury) |
| 178 | (define-key map "\C-c\C-m" 'sieve-manage) |
| 179 | map) |
| 180 | "Key map used in sieve mode.") |
| 181 | |
| 182 | ;; Menu definition |
| 183 | |
| 184 | (defvar sieve-mode-menu nil |
| 185 | "Menubar used in sieve mode.") |
| 186 | |
| 187 | ;; Code for Sieve editing mode. |
| 188 | (autoload 'easy-menu-add-item "easymenu") |
| 189 | |
| 190 | ;;;###autoload |
| 191 | (define-derived-mode sieve-mode c-mode "Sieve" |
| 192 | "Major mode for editing Sieve code. |
| 193 | This is much like C mode except for the syntax of comments. Its keymap |
| 194 | inherits from C mode's and it has the same variables for customizing |
| 195 | indentation. It has its own abbrev table and its own syntax table. |
| 196 | |
| 197 | Turning on Sieve mode runs `sieve-mode-hook'." |
| 198 | (set (make-local-variable 'paragraph-start) (concat "$\\|" page-delimiter)) |
| 199 | (set (make-local-variable 'paragraph-separate) paragraph-start) |
| 200 | (set (make-local-variable 'comment-start) "#") |
| 201 | (set (make-local-variable 'comment-end) "") |
| 202 | ;;(set (make-local-variable 'comment-start-skip) "\\(^\\|\\s-\\);?#+ *") |
| 203 | (set (make-local-variable 'comment-start-skip) "#+ *") |
| 204 | (unless (featurep 'xemacs) |
| 205 | (set (make-local-variable 'font-lock-defaults) |
| 206 | '(sieve-font-lock-keywords nil nil ((?_ . "w"))))) |
| 207 | (easy-menu-add-item nil nil sieve-mode-menu)) |
| 208 | |
| 209 | ;; Menu |
| 210 | |
| 211 | (easy-menu-define sieve-mode-menu sieve-mode-map |
| 212 | "Sieve Menu." |
| 213 | '("Sieve" |
| 214 | ["Upload script" sieve-upload t] |
| 215 | ["Manage scripts on server" sieve-manage t])) |
| 216 | |
| 217 | (provide 'sieve-mode) |
| 218 | |
| 219 | ;; sieve-mode.el ends here |