]> gitweb.michael.orlitzky.com - nagios-mode.git/blob - nagios-mode.el
Remove the slashes from around the macro definitions, and use regexp-opt instead...
[nagios-mode.git] / nagios-mode.el
1 ;;
2 ;; nagios-mode, an Emacs mode for Nagios <http://www.nagios.org/>
3 ;; configuration files.
4 ;;
5 ;; Copyright Michael Orlitzky
6 ;;
7 ;; http://michael.orlitzky.com/
8 ;;
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.
13 ;;
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.
18 ;;
19 ;; http://www.fsf.org/licensing/licenses/gpl.html
20 ;;
21
22 (require 'font-lock)
23 (require 'regexp-opt)
24
25
26 ;; Custom Variables
27
28 (defcustom nagios-indent-level 2
29 "Number of spaces in one indentation (tab)."
30 :type 'integer :group 'nagios
31 )
32
33
34
35 ;; Indentation Voodoo
36
37 (defun nagios-indent-line(&optional flag)
38 "Indents a line, taking nesting into account."
39 (nagios-indent-to (nagios-calculate-indent))
40 )
41
42
43
44 (defun nagios-indent-to(indent-column)
45 "Indent the current line to column indent-column."
46 (setq pos (point))
47 (beginning-of-line)
48 (setq bol (point))
49 (setq pos-offset (- pos bol))
50
51 (setq first-char-offset
52 (skip-chars-forward " \t"))
53
54 (setq first-char-pos
55 (+ bol first-char-offset))
56
57 (delete-region bol first-char-pos)
58
59 (beginning-of-line)
60
61 (setq pos-change (- indent-column first-char-offset))
62 (setq pos-offset (+ pos-offset pos-change))
63
64 (if (<= pos-offset indent-column)
65 (setq pos-offset indent-column))
66
67 (while (< 0 indent-column)
68 (insert " ")
69 (setq indent-column (- indent-column 1)))
70
71 (goto-char (+ bol pos-offset))
72
73 )
74
75
76
77 (defun nagios-in-block()
78 "Determine if the point is inside of a {} block."
79
80 (setq pos (point))
81
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))
85 (goto-char pos)
86
87 (setq last-closing-brace (re-search-backward "}" nil t))
88 (goto-char pos)
89
90 ;; If either is nil (not found) just set it to -1, so the comparison
91 ;; doesn't die.
92 (if (not last-opening-brace)
93 (setq last-opening-brace -1))
94
95 (if (not last-closing-brace)
96 (setq last-closing-brace -1))
97
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)
101 nil
102 t)
103 )
104
105
106
107 (defun nagios-calculate-indent()
108 "Calculate the level of indentation."
109 ;; We're either inside a block, or we aren't.
110
111 (setq indent 0)
112
113 (if (nagios-in-block)
114 (setq indent nagios-indent-level))
115
116 (setq pos (point))
117 (end-of-line)
118 (setq eol (point))
119 (beginning-of-line)
120 (setq bol (point))
121
122 ;; Set the indentation level to 0 if we find either brace on this
123 ;; line.
124 (if (re-search-forward "[{}]" eol t)
125 (setq indent 0))
126
127 (goto-char pos)
128
129 indent
130 )
131
132
133
134 ;; Keymaps
135
136 (defun nagios-insert-right-brace-and-indent()
137 "Insert a '}' character, and indent the line."
138 (interactive)
139 (insert "}")
140 (nagios-indent-line)
141 )
142
143
144 (defvar nagios-mode-map()
145 "Keymap used in nagios mode.")
146
147 (when (not nagios-mode-map)
148 (setq nagios-mode-map (make-sparse-keymap))
149 (define-key nagios-mode-map
150 (read-kbd-macro "}")
151 'nagios-insert-right-brace-and-indent)
152 )
153
154
155
156 ;; Regular Expression Transformations
157
158 (defun regexp-alt-raw(element-list)
159 "Takes a list of elements, and returns the string '\\(element1\\|element2...\\)'"
160
161 ;; This is necessary since regexp-opt does not accept regular
162 ;; expressions as arguments. We use regexp-opt when we can, of
163 ;; course.
164
165 (let ((regexp "\\("))
166 (mapcar (lambda(elem)
167 (setq regexp (concat regexp "\\(" elem "\\)" "\\|")))
168 element-list)
169 (concat (substring regexp 0 -2) ; Cut the last "\\|"
170 "\\)")
171 )
172 )
173
174
175
176 (defconst nagios-directives
177 (eval-when-compile
178 (concat "^[ \t\r\n]*"
179
180 (regexp-opt
181 '("active_checks_enabled" "address" "alias" "check_command"
182 "check_freshness" "check_interval" "check_period" "checks_enabled"
183 "command_line" "command_name" "contactgroups" "contact_groups"
184 "contactgroup_members" "contact_name" "contactgroup_name" "contacts"
185 "dependent_host_name" "dependent_service_description" "email"
186 "event_handler" "event_handler_enabled" "execution_failure_criteria"
187 "failure_prediction_enabled" "first_notification"
188 "first_notification_delay" "flap_detection_enabled" "freshness_threshold"
189 "friday" "high_flap_threshold" "host_name" "host_notification_commands"
190 "host_notification_options" "host_notification_period"
191 "host_notifications_enabled" "hostgroup_name" "hostgroups"
192 "is_volatile" "last_notification" "low_flap_threshold"
193 "max_check_attempts" "members" "monday" "normal_check_interval"
194 "notes" "notification_failure_criteria"
195 "notification_interval" "notification_options"
196 "notification_period" "notifications_enabled"
197 "obsess_over_service" "pager" "parallelize_check"
198 "parents" "passive_checks_enabled"
199 "process_perf_data" "retain_nonstatus_information"
200 "retain_status_information" "retry_check_interval"
201 "retry_interval" "saturday" "service_description"
202 "service_notification_commands" "service_notification_options"
203 "service_notification_period" "service_notifications_enabled"
204 "servicegroup_name" "stalking_options"
205 "sunday" "thursday" "timeperiod_name" "tuesday" "wednesday") t)
206
207 "[ \r\n\t]+")
208 )
209 )
210
211
212
213 (defconst nagios-macros
214 (eval-when-compile
215 (regexp-opt
216 '("$ADMINEMAIL$"
217 "$ADMINPAGER$"
218 "$ARG1$"
219 "$ARG10$"
220 "$ARG11$"
221 "$ARG12$"
222 "$ARG13$"
223 "$ARG14$"
224 "$ARG15$"
225 "$ARG16$"
226 "$ARG17$"
227 "$ARG18$"
228 "$ARG19$"
229 "$ARG2$"
230 "$ARG20$"
231 "$ARG21$"
232 "$ARG22$"
233 "$ARG23$"
234 "$ARG24$"
235 "$ARG25$"
236 "$ARG26$"
237 "$ARG27$"
238 "$ARG28$"
239 "$ARG29$"
240 "$ARG3$"
241 "$ARG30$"
242 "$ARG31$"
243 "$ARG32$"
244 "$ARG4$"
245 "$ARG5$"
246 "$ARG6$"
247 "$ARG7$"
248 "$ARG8$"
249 "$ARG9$"
250 "$COMMANDFILE$"
251 "$CONTACTALIAS$"
252 "$CONTACTEMAIL$"
253 "$CONTACTGROUPALIAS$"
254 "$CONTACTGROUPMEMBERS$"
255 "$CONTACTGROUPNAME$"
256 "$CONTACTGROUPNAMES$"
257 "$CONTACTNAME$"
258 "$CONTACTPAGER$"
259 "$DATE$"
260 "$EVENTSTARTTIME$"
261 "$HOSTACKAUTHOR$"
262 "$HOSTACKAUTHORALIAS$"
263 "$HOSTACKAUTHORNAME$"
264 "$HOSTACKCOMMENT$"
265 "$HOSTACTIONURL$"
266 "$HOSTADDRESS$"
267 "$HOSTALIAS$"
268 "$HOSTATTEMPT$"
269 "$HOSTCHECKCOMMAND$"
270 "$HOSTCHECKTYPE$"
271 "$HOSTDISPLAYNAME$"
272 "$HOSTDOWNTIME$"
273 "$HOSTDURATION$"
274 "$HOSTDURATIONSEC$"
275 "$HOSTEVENTID$"
276 "$HOSTEXECUTIONTIME$"
277 "$HOSTGROUPACTIONURL$"
278 "$HOSTGROUPALIAS$"
279 "$HOSTGROUPMEMBERS$"
280 "$HOSTGROUPNAME$"
281 "$HOSTGROUPNAMES$"
282 "$HOSTGROUPNOTES$"
283 "$HOSTGROUPNOTESURL$"
284 "$HOSTLATENCY$"
285 "$HOSTNAME$"
286 "$HOSTNOTES$"
287 "$HOSTNOTESURL$"
288 "$HOSTNOTIFICATIONID$"
289 "$HOSTNOTIFICATIONNUMBER$"
290 "$HOSTOUTPUT$"
291 "$HOSTPERCENTCHANGE$"
292 "$HOSTPERFDATA$"
293 "$HOSTPERFDATAFILE$"
294 "$HOSTPROBLEMID$"
295 "$HOSTSTATE$"
296 "$HOSTSTATEID$"
297 "$HOSTSTATETYPE$"
298 "$ISVALIDTIME$"
299 "$LASTHOSTCHECK$"
300 "$LASTHOSTDOWN$"
301 "$LASTHOSTEVENTID$"
302 "$LASTHOSTPROBLEMID$"
303 "$LASTHOSTSTATE$"
304 "$LASTHOSTSTATECHANGE$"
305 "$LASTHOSTSTATEID$"
306 "$LASTHOSTUNREACHABLE$"
307 "$LASTHOSTUP$"
308 "$LASTSERVICECHECK$"
309 "$LASTSERVICECRITICAL$"
310 "$LASTSERVICEEVENTID$"
311 "$LASTSERVICEOK$"
312 "$LASTSERVICEPROBLEMID$"
313 "$LASTSERVICESTATE$"
314 "$LASTSERVICESTATECHANGE$"
315 "$LASTSERVICESTATEID$"
316 "$LASTSERVICEUNKNOWN$"
317 "$LASTSERVICEWARNING$"
318 "$LOGFILE$"
319 "$LONGDATETIME$"
320 "$LONGHOSTOUTPUT$"
321 "$LONGSERVICEOUTPUT$"
322 "$MAINCONFIGFILE$"
323 "$MAXHOSTATTEMPTS$"
324 "$MAXSERVICEATTEMPTS$"
325 "$NEXTVALIDTIME$"
326 "$NOTIFICATIONAUTHOR$"
327 "$NOTIFICATIONAUTHORALIAS$"
328 "$NOTIFICATIONAUTHORNAME$"
329 "$NOTIFICATIONCOMMENT$"
330 "$NOTIFICATIONISESCALATED$"
331 "$NOTIFICATIONNUMBER$"
332 "$NOTIFICATIONRECIPIENTS$"
333 "$NOTIFICATIONTYPE$"
334 "$OBJECTCACHEFILE$"
335 "$PROCESSSTARTTIME$"
336 "$RESOURCEFILE$"
337 "$RETENTIONDATAFILE$"
338 "$SERVICEACKAUTHOR$"
339 "$SERVICEACKAUTHORALIAS$"
340 "$SERVICEACKAUTHORNAME$"
341 "$SERVICEACKCOMMENT$"
342 "$SERVICEACTIONURL$"
343 "$SERVICEATTEMPT$"
344 "$SERVICECHECKCOMMAND$"
345 "$SERVICECHECKTYPE$"
346 "$SERVICEDESC$"
347 "$SERVICEDISPLAYNAME$"
348 "$SERVICEDOWNTIME$"
349 "$SERVICEDURATION$"
350 "$SERVICEDURATIONSEC$"
351 "$SERVICEEVENTID$"
352 "$SERVICEEXECUTIONTIME$"
353 "$SERVICEGROUPACTIONURL$"
354 "$SERVICEGROUPALIAS$"
355 "$SERVICEGROUPMEMBERS$"
356 "$SERVICEGROUPNAME$"
357 "$SERVICEGROUPNAMES$"
358 "$SERVICEGROUPNOTES$"
359 "$SERVICEGROUPNOTESURL$"
360 "$SERVICEISVOLATILE$"
361 "$SERVICELATENCY$"
362 "$SERVICENOTES$"
363 "$SERVICENOTESURL$"
364 "$SERVICENOTIFICATIONID$"
365 "$SERVICENOTIFICATIONNUMBER$"
366 "$SERVICEOUTPUT$"
367 "$SERVICEPERCENTCHANGE$"
368 "$SERVICEPERFDATA$"
369 "$SERVICEPERFDATAFILE$"
370 "$SERVICEPROBLEMID$"
371 "$SERVICESTATE$"
372 "$SERVICESTATEID$"
373 "$SERVICESTATETYPE$"
374 "$SHORTDATETIME$"
375 "$STATUSDATAFILE$"
376 "$TEMPFILE$"
377 "$TEMPPATH$"
378 "$TIME$"
379 "$TIMET$"
380 "$TOTALHOSTPROBLEMS$"
381 "$TOTALHOSTPROBLEMSUNHANDLED$"
382 "$TOTALHOSTSDOWN$"
383 "$TOTALHOSTSDOWNUNHANDLED$"
384 "$TOTALHOSTSERVICES$"
385 "$TOTALHOSTSERVICESCRITICAL$"
386 "$TOTALHOSTSERVICESOK$"
387 "$TOTALHOSTSERVICESUNKNOWN$"
388 "$TOTALHOSTSERVICESWARNING$"
389 "$TOTALHOSTSUNREACHABLE$"
390 "$TOTALHOSTSUNREACHABLEUNHANDLED$"
391 "$TOTALHOSTSUP$"
392 "$TOTALSERVICEPROBLEMS$"
393 "$TOTALSERVICEPROBLEMSUNHANDLED$"
394 "$TOTALSERVICESCRITICAL$"
395 "$TOTALSERVICESCRITICALUNHANDLED$"
396 "$TOTALSERVICESOK$"
397 "$TOTALSERVICESUNKNOWN$"
398 "$TOTALSERVICESUNKNOWNUNHANDLED$"
399 "$TOTALSERVICESWARNING$"
400 "$TOTALSERVICESWARNINGUNHANDLED$"
401 "$USER1$"
402 "$USER10$"
403 "$USER100$"
404 "$USER101$"
405 "$USER102$"
406 "$USER103$"
407 "$USER104$"
408 "$USER105$"
409 "$USER106$"
410 "$USER107$"
411 "$USER108$"
412 "$USER109$"
413 "$USER11$"
414 "$USER110$"
415 "$USER111$"
416 "$USER112$"
417 "$USER113$"
418 "$USER114$"
419 "$USER115$"
420 "$USER116$"
421 "$USER117$"
422 "$USER118$"
423 "$USER119$"
424 "$USER12$"
425 "$USER120$"
426 "$USER121$"
427 "$USER122$"
428 "$USER123$"
429 "$USER124$"
430 "$USER125$"
431 "$USER126$"
432 "$USER127$"
433 "$USER128$"
434 "$USER129$"
435 "$USER13$"
436 "$USER130$"
437 "$USER131$"
438 "$USER132$"
439 "$USER133$"
440 "$USER134$"
441 "$USER135$"
442 "$USER136$"
443 "$USER137$"
444 "$USER138$"
445 "$USER139$"
446 "$USER14$"
447 "$USER140$"
448 "$USER141$"
449 "$USER142$"
450 "$USER143$"
451 "$USER144$"
452 "$USER145$"
453 "$USER146$"
454 "$USER147$"
455 "$USER148$"
456 "$USER149$"
457 "$USER15$"
458 "$USER150$"
459 "$USER151$"
460 "$USER152$"
461 "$USER153$"
462 "$USER154$"
463 "$USER155$"
464 "$USER156$"
465 "$USER157$"
466 "$USER158$"
467 "$USER159$"
468 "$USER16$"
469 "$USER160$"
470 "$USER161$"
471 "$USER162$"
472 "$USER163$"
473 "$USER164$"
474 "$USER165$"
475 "$USER166$"
476 "$USER167$"
477 "$USER168$"
478 "$USER169$"
479 "$USER17$"
480 "$USER170$"
481 "$USER171$"
482 "$USER172$"
483 "$USER173$"
484 "$USER174$"
485 "$USER175$"
486 "$USER176$"
487 "$USER177$"
488 "$USER178$"
489 "$USER179$"
490 "$USER18$"
491 "$USER180$"
492 "$USER181$"
493 "$USER182$"
494 "$USER183$"
495 "$USER184$"
496 "$USER185$"
497 "$USER186$"
498 "$USER187$"
499 "$USER188$"
500 "$USER189$"
501 "$USER19$"
502 "$USER190$"
503 "$USER191$"
504 "$USER192$"
505 "$USER193$"
506 "$USER194$"
507 "$USER195$"
508 "$USER196$"
509 "$USER197$"
510 "$USER198$"
511 "$USER199$"
512 "$USER2$"
513 "$USER20$"
514 "$USER200$"
515 "$USER201$"
516 "$USER202$"
517 "$USER203$"
518 "$USER204$"
519 "$USER205$"
520 "$USER206$"
521 "$USER207$"
522 "$USER208$"
523 "$USER209$"
524 "$USER21$"
525 "$USER210$"
526 "$USER211$"
527 "$USER212$"
528 "$USER213$"
529 "$USER214$"
530 "$USER215$"
531 "$USER216$"
532 "$USER217$"
533 "$USER218$"
534 "$USER219$"
535 "$USER22$"
536 "$USER220$"
537 "$USER221$"
538 "$USER222$"
539 "$USER223$"
540 "$USER224$"
541 "$USER225$"
542 "$USER226$"
543 "$USER227$"
544 "$USER228$"
545 "$USER229$"
546 "$USER23$"
547 "$USER230$"
548 "$USER231$"
549 "$USER232$"
550 "$USER233$"
551 "$USER234$"
552 "$USER235$"
553 "$USER236$"
554 "$USER237$"
555 "$USER238$"
556 "$USER239$"
557 "$USER24$"
558 "$USER240$"
559 "$USER241$"
560 "$USER242$"
561 "$USER243$"
562 "$USER244$"
563 "$USER245$"
564 "$USER246$"
565 "$USER247$"
566 "$USER248$"
567 "$USER249$"
568 "$USER25$"
569 "$USER250$"
570 "$USER251$"
571 "$USER252$"
572 "$USER253$"
573 "$USER254$"
574 "$USER255$"
575 "$USER256$"
576 "$USER26$"
577 "$USER27$"
578 "$USER28$"
579 "$USER29$"
580 "$USER3$"
581 "$USER30$"
582 "$USER31$"
583 "$USER32$"
584 "$USER33$"
585 "$USER34$"
586 "$USER35$"
587 "$USER36$"
588 "$USER37$"
589 "$USER38$"
590 "$USER39$"
591 "$USER4$"
592 "$USER40$"
593 "$USER41$"
594 "$USER42$"
595 "$USER43$"
596 "$USER44$"
597 "$USER45$"
598 "$USER46$"
599 "$USER47$"
600 "$USER48$"
601 "$USER49$"
602 "$USER5$"
603 "$USER50$"
604 "$USER51$"
605 "$USER52$"
606 "$USER53$"
607 "$USER54$"
608 "$USER55$"
609 "$USER56$"
610 "$USER57$"
611 "$USER58$"
612 "$USER59$"
613 "$USER6$"
614 "$USER60$"
615 "$USER61$"
616 "$USER62$"
617 "$USER63$"
618 "$USER64$"
619 "$USER65$"
620 "$USER66$"
621 "$USER67$"
622 "$USER68$"
623 "$USER69$"
624 "$USER7$"
625 "$USER70$"
626 "$USER71$"
627 "$USER72$"
628 "$USER73$"
629 "$USER74$"
630 "$USER75$"
631 "$USER76$"
632 "$USER77$"
633 "$USER78$"
634 "$USER79$"
635 "$USER8$"
636 "$USER80$"
637 "$USER81$"
638 "$USER82$"
639 "$USER83$"
640 "$USER84$"
641 "$USER85$"
642 "$USER86$"
643 "$USER87$"
644 "$USER88$"
645 "$USER89$"
646 "$USER9$"
647 "$USER90$"
648 "$USER91$"
649 "$USER92$"
650 "$USER93$"
651 "$USER94$"
652 "$USER95$"
653 "$USER96$"
654 "$USER97$"
655 "$USER98$"
656 "$USER99$")))
657 )
658
659
660
661 (defconst nagios-definitions
662 (eval-when-compile
663
664 (concat "^[ \t\r\n]*"
665
666 (regexp-alt-raw
667 '("define command"
668 "define contact"
669 "define contactgroup"
670 "define host"
671 "define hostdependency"
672 "define hostescalation"
673 "define hostextinfo"
674 "define hostgroup"
675 "define hostgroupescalation"
676 "define null"
677 "define service"
678 "define servicedependency"
679 "define serviceescalation"
680 "define serviceextinfo"
681 "define servicegroup"
682 "define timeperiod"))
683
684 ;; These can be "terminated" by either an opening curly
685 ;; brace, or a space.
686 "\\({\\| \\)")
687 )
688 )
689
690
691
692 (defconst nagios-special
693 (eval-when-compile
694 (concat "^[ \t\r\n]*"
695
696 (regexp-opt
697 '("name" "register" "use") t)
698
699 "[ \r\n\t]+"))
700 )
701
702
703
704 ;; The One True Font Locking Variable
705
706 (defvar nagios-font-lock-keywords
707 (list
708 (cons nagios-special font-lock-keyword-face)
709 (cons nagios-directives font-lock-variable-name-face)
710 (cons nagios-macros font-lock-constant-face)
711 (cons nagios-definitions '(1 font-lock-function-name-face)))
712
713 "Rules for highlighting Nagios configuration files."
714 )
715
716
717
718 (defvar nagios-mode-syntax-table nil
719 "Syntax table used in nagios-mode buffers.")
720 (if nagios-mode-syntax-table
721 nil
722 (setq nagios-mode-syntax-table (make-syntax-table))
723 (modify-syntax-entry ?# "< b" nagios-mode-syntax-table) ;; Comment style 1
724 (modify-syntax-entry ?\; "< b" nagios-mode-syntax-table) ;; Comment style 2
725 (modify-syntax-entry ?\n "> b" nagios-mode-syntax-table) ;; End comment
726 )
727
728
729 ;; Main Mode Function
730
731 (defun nagios-mode()
732 "Major mode for editing Nagios configuration files."
733
734 (interactive)
735 (kill-all-local-variables)
736 (make-local-variable 'font-lock-defaults)
737 (make-local-variable 'comment-start)
738 (make-local-variable 'comment-start-skip)
739 (make-local-variable 'comment-end)
740 (make-local-variable 'indent-line-function)
741 (make-local-variable 'syntax-begin-function)
742
743 (set-syntax-table nagios-mode-syntax-table)
744
745 (setq mode-name "nagios"
746 major-mode 'nagios-mode
747 indent-line-function 'nagios-indent-line
748 font-lock-defaults '(nagios-font-lock-keywords)
749 comment-start "#"
750 comment-start-skip "#\|; +"
751 comment-end ""
752
753 ;; Since comments and strings do not span multiple lines,
754 ;; the syntax parser can safely start parsing at the beginning
755 ;; of any line.
756 syntax-begin-function 'beginning-of-line
757 )
758
759 ;; Keyboard Mapping
760 (use-local-map nagios-mode-map)
761
762 ;; I don't /think/ I need to define this before attempting
763 ;; to run it. Users can define it if they want.
764 (run-hooks 'nagios-mode-hook)
765 )
766
767
768 (provide 'nagios-mode)