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