2 ;; nagios-mode, an Emacs mode for Nagios <http://www.nagios.org/>
3 ;; configuration files.
5 ;; Copyright Michael Orlitzky
7 ;; http://michael.orlitzky.com/
9 ;; This program is free software: you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation, either version 3 of the License, or
12 ;; (at your option) any later version.
14 ;; This program is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
19 ;; http://www.fsf.org/licensing/licenses/gpl.html
28 (defcustom nagios-indent-level 2
29 "Number of spaces in one indentation (tab)."
30 :type 'integer :group 'nagios
37 (defun nagios-indent-line(&optional flag)
38 "Indents a line, taking nesting into account."
39 (nagios-indent-to (nagios-calculate-indent))
44 (defun nagios-indent-to(indent-column)
45 "Indent the current line to column indent-column."
49 (setq pos-offset (- pos bol))
51 (setq first-char-offset
52 (skip-chars-forward " \t"))
55 (+ bol first-char-offset))
57 (kill-region bol first-char-pos)
61 (setq pos-change (- indent-column first-char-offset))
62 (setq pos-offset (+ pos-offset pos-change))
64 (if (<= pos-offset indent-column)
65 (setq pos-offset indent-column))
67 (while (< 0 indent-column)
69 (setq indent-column (- indent-column 1)))
71 (goto-char (+ bol pos-offset))
77 (defun nagios-in-block()
78 "Determine if the point is inside of a {} block."
82 ;; Get the position of the last opening and closing braces, with
83 ;; respect to the current point
84 (setq last-opening-brace (re-search-backward "{" nil t))
87 (setq last-closing-brace (re-search-backward "}" nil t))
90 ;; If either is nil (not found) just set it to -1, so the comparison
92 (if (not last-opening-brace)
93 (setq last-opening-brace -1))
95 (if (not last-closing-brace)
96 (setq last-closing-brace -1))
98 ;; If the last brace seen in the buffer is an opening brace, we're
99 ;; in a block. Otherwise, we aren't.
100 (if (>= last-closing-brace last-opening-brace)
107 (defun nagios-calculate-indent()
108 "Calculate the level of indentation."
109 ;; We're either inside a block, or we aren't.
113 (if (nagios-in-block)
114 (setq indent nagios-indent-level))
122 ;; Set the indentation level to 0 if we find either brace on this
124 (if (re-search-forward "[{}]" eol t)
136 (defun nagios-insert-right-brace-and-indent()
137 "Insert a '}' character, and indent the line."
144 (defvar nagios-mode-map()
145 "Keymap used in nagios mode.")
147 (when (not nagios-mode-map)
148 (setq nagios-mode-map (make-sparse-keymap))
149 (define-key nagios-mode-map
151 'nagios-insert-right-brace-and-indent)
156 ;; Regular Expression Transformations
158 (defun regexp-word(regexp)
159 "Takes a regular expression as an argument, and adds the word boundary condition to the beginning and end of it. Newlines are treated as word boundaries."
161 ;; This basically joins two expressions in an alternation.
162 ;; The first allows for a newline followed by our regexp (on
163 ;; a word boundary), and the second checks for any-non-word
164 ;; character followed by our regexp.
166 ;; I consider neither a hyphen nor an underscore to be a word
167 ;; boundary for the purpose of syntax highlighting, so I stick
168 ;; the no-hyphens-or-underscores class on each end of the
172 (concat "\\(^\\<\\(" regexp "\\)\\>[^_-]\\)")
174 (concat "\\([^_-]\\<\\(" regexp "\\)\\>[^_-]\\)")
179 (defun regexp-alt-raw(element-list)
180 "Takes a list of elements, and returns the string '\\(element1\\|element2...\\)'"
182 ;; This is necessary since regexp-opt does not accept regular
183 ;; expressions as arguments. We use regexp-opt when we can, of
186 (let ((regexp "\\("))
187 (mapcar (lambda(elem)
188 (setq regexp (concat regexp "\\(" elem "\\)" "\\|")))
190 (concat (substring regexp 0 -2) ; Cut the last "\\|"
197 ;; Syntax Highlighting Patterns
199 (defconst nagios-comments
207 (defconst nagios-directives
210 '("active_checks_enabled" "address" "alias" "check_command"
211 "check_freshness" "check_interval" "check_period" "checks_enabled"
212 "command_line" "command_name" "contact_groups" "contact_name"
213 "contactgroup_name" "contacts" "dependent_host_name"
214 "dependent_service_description" "email" "event_handler"
215 "event_handler_enabled" "execution_failure_criteria"
216 "failure_prediction_enabled" "first_notification"
217 "flap_detection_enabled" "freshness_threshold" "friday"
218 "high_flap_threshold" "host_name" "host_notification_commands"
219 "host_notification_options" "host_notification_period"
220 "host_notifications_enabled" "hostgroup_name" "hostgroups"
221 "is_volatile" "last_notification" "low_flap_threshold"
222 "max_check_attempts" "members" "monday" "normal_check_interval"
223 "notes" "notification_failure_criteria"
224 "notification_interval" "notification_options"
225 "notification_period" "notifications_enabled"
226 "obsess_over_service" "pager" "parallelize_check"
227 "parents" "passive_checks_enabled"
228 "process_perf_data" "retain_nonstatus_information"
229 "retain_status_information" "retry_check_interval"
230 "retry_interval" "saturday" "service_description"
231 "service_notification_commands" "service_notification_options"
232 "service_notification_period" "service_notifications_enabled"
233 "servicegroup_name" "stalking_options"
234 "sunday" "thursday" "timeperiod_name" "tuesday" "wednesday") t))
239 (defconst nagios-macros
242 '("\\$CONTACT\\(NAME\\|ALIAS\\|EMAIL\\|PAGER\\)\\$"
243 "\\$HOST\\(NAME\\|ALIAS\\|ADDRESS\\|STATE\\)\\$"
244 "\\$\\(ARG\\|USER\\)\\([1-9]\\|[1-2][0-9]\\|3[0-2]\\)\\$"
245 "\\$SERVICE\\(DESC\\|STATE\\)\\$"
246 "\\$\\(OUTPUT\\|PERFDATA\\|EXECUTIONTIME\\|LATENCY\\)\\$"
247 "\\$NOTIFICATION\\(TYPE\\|NUMBER\\)\\$"
248 "\\$\\(\\(SHORT\\)?DATETIME\\|DATE\\|TIME\\|TIMET\\)\\$"
249 "\\$\\(LASTSTATECHANGE\\|STATETYPE\\)\\$"
250 "\\$ADMIN\\(EMAIL\\|PAGER\\)\\$"
251 "\\$\\(SERVICE\\|HOST\\)ATTEMPT\\$")))
256 (defconst nagios-definitions
259 '("define +\\(host\\|service\\|timeperiod\\|contact\\|command\\)"
260 "define +\\(host\\|contact\\|service\\)group"
261 "define +\\(service\\|host\\)dependency"
262 "define +\\(service\\|host\\|hostgroup\\)escalation")))
267 (defconst nagios-special
270 '("name" "register" "use") t))
275 ;; The One True Font Locking Variable
277 (defvar nagios-font-lock-keywords
280 ;; This first bit of ugliness allows us to override any
281 ;; other font-locking with the comment font.
282 (cons nagios-comments '(0 font-lock-comment-delimiter-face t))
284 ;; The rest just map regular expressions to font faces.
285 (cons (regexp-word nagios-directives) font-lock-variable-name-face)
286 (cons (regexp-word nagios-macros) font-lock-constant-face)
287 (cons (regexp-word nagios-definitions) font-lock-function-name-face)
288 (cons (regexp-word nagios-special) font-lock-keyword-face))
290 "Rules for highlighting Nagios configuration files."
295 ;; Main Mode Function
298 "Major mode for editing Nagios configuration files."
302 ;; Initializing. This is actually important to cover
303 ;; up some Emacs stupidity. Font locking won't occur
305 (kill-all-local-variables)
307 ;; Set up indentation handling using the functions
309 (make-local-variable 'indent-line-function)
310 (setq indent-line-function 'nagios-indent-line)
312 ;; Configure font locking. Set the defaults to something
313 ;; sensible, defined earlier.
314 (make-local-variable 'font-lock-defaults)
315 (setq font-lock-defaults '(nagios-font-lock-keywords nil t))
318 (use-local-map nagios-mode-map)
321 (setq mode-name "nagios"
322 major-mode 'nagios-mode)
324 ;; I don't /think/ I need to define this before attempting
325 ;; to run it. Users can define it if they want.
326 (run-hooks 'nagios-mode-hook)
330 (provide 'nagios-mode)