1 ;; nagios-mode: an emacs mode for nagios configuration files
2 ;; Copyright (C) 2024 Michael Orlitzky
4 ;; This program is free software: you can redistribute it and/or modify
5 ;; it under the terms of the GNU Affero General Public License as
6 ;; published by the Free Software Foundation, either version 3 of the
7 ;; License, or (at your option) any later version.
9 ;; This program is distributed in the hope that it will be useful,
10 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ;; GNU Affero General Public License for more details.
14 ;; You should have received a copy of the GNU Affero General Public License
15 ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
23 (defcustom nagios-indent-level 2
24 "Number of spaces in one indentation (tab)."
25 :type 'integer :group 'nagios
32 (defun nagios-indent-line(&optional flag)
33 "Indents a line, taking nesting into account."
35 (nagios-indent-to (nagios-calculate-indent))
39 (defun nagios-beginning-of-line-pos()
40 ;; Return the point position corresponding to the beginning
41 ;; of the current line.
48 (defun nagios-end-of-line-pos()
49 ;; Return the point position corresponding to the end
50 ;; of the current line.
57 (defun nagios-point-offset()
58 ;; How far are we from the beginning of the line?
59 (- (point) (nagios-beginning-of-line-pos))
62 (defun nagios-first-char-offset()
63 ;; How far is the first character on this line
64 ;; from the beginning of the line?
67 (skip-chars-forward " \t")
71 (defun nagios-first-char-pos()
72 ;; What's the position of the first character on this line?
73 (+ (nagios-beginning-of-line-pos) (nagios-first-char-offset))
76 (defun nagios-indent-to(indent-column)
77 "Indent the current line to column indent-column."
78 ;; Store the point in orig-pos.
79 (let ((orig-point (point)))
81 ;; And store the offset of the first character (with respect to the
82 ;; beginning of the line) in orig-first-char-offset.
83 (let ((orig-first-char-offset (nagios-first-char-offset)))
85 ;; Delete any leading whitespace, and move the point to the
86 ;; beginning of the line.
87 (delete-region (nagios-beginning-of-line-pos) (nagios-first-char-pos))
90 ;; Now insert indent-column spaces.
91 (let ((indent-remaining indent-column))
92 (while (< 0 indent-remaining)
94 (setq indent-remaining (- indent-remaining 1)))
97 ;; The text on the current line just moved left/right some amount;
98 ;; call it text-delta. We want to move the point that same distance.
99 (let ((text-delta (- (nagios-first-char-offset) orig-first-char-offset)))
100 (goto-char (+ orig-point text-delta))
103 ;; The point should never wind up to the left of indent-column, so
104 ;; if it's there, move it over to indent-column.
105 (if (< (nagios-point-offset) indent-column)
106 (goto-char (+ (nagios-beginning-of-line-pos) indent-column))
113 (defun nagios-char-is-commented(pos)
114 "True if the character at position pos is commented, nil otherwise."
117 (re-search-backward "\\(#\\|;\\)" (nagios-beginning-of-line-pos) t)
121 (defun nagios-char-is-commented-and-valid(pos)
122 "True if the character at position pos is commented and non-nil.
126 (nagios-char-is-commented pos)
131 (defun nagios-last-opening-brace()
132 "Returns the position of the last opening brace, with
133 respect to the current point. Ignores braces which
136 (let ((lob (re-search-backward "{" nil t)))
138 (while (nagios-char-is-commented-and-valid lob)
140 (setq lob (re-search-backward "{" nil t))
151 (defun nagios-last-closing-brace()
152 "Get the position of the last closing brace, with
153 respect to the current point. Ignores braces which
156 (let ((lcb (re-search-backward "}" nil t)))
158 (while (nagios-char-is-commented-and-valid lcb)
160 (setq lcb (re-search-backward "}" nil t))
170 (defun nagios-in-block()
171 "Determine if the point is inside of a {} block."
173 ;; If the last brace seen in the buffer is an opening brace, we're
174 ;; in a block. Otherwise, we aren't.
175 (if (>= (nagios-last-closing-brace) (nagios-last-opening-brace))
181 (defun nagios-brace-on-line()
182 ;; Is there a curly brace on this line?
185 (re-search-forward "[{}]" (nagios-end-of-line-pos) t)
190 (defun nagios-calculate-indent()
191 "Calculate the level of indentation."
193 ;; We're either inside a block, or we aren't.
194 ;; Initialize the indent variable to either nagios-indent-level
195 ;; or 0 depending on whether or not we're in a block.
196 (let ((indent (if (nagios-in-block)
202 ;; Set the indentation level to 0 if we find either brace on this
204 (if (and (nagios-brace-on-line)
205 (not (nagios-char-is-commented (nagios-brace-on-line))))
215 (defun nagios-insert-right-brace-and-indent()
216 "Insert a '}' character, and indent the line."
223 (defvar nagios-mode-map()
224 "Keymap used in nagios mode.")
226 (when (not nagios-mode-map)
227 (setq nagios-mode-map (make-sparse-keymap))
228 (define-key nagios-mode-map
230 'nagios-insert-right-brace-and-indent)
235 (defconst nagios-directives
237 (concat "^[ \t\r\n]*"
241 "active_checks_enabled"
244 "can_submit_commands"
254 "contactgroup_members"
259 "dependent_description"
261 "dependent_host_name"
262 "dependent_hostgroup"
263 "dependent_hostgroup_name"
264 "dependent_hostgroups"
265 "dependent_service_description"
266 "dependent_servicegroup"
267 "dependent_servicegroup_name"
268 "dependent_servicegroups"
275 "event_handler_enabled"
277 "execution_failure_criteria"
278 "execution_failure_options"
279 "failure_prediction_enabled"
280 "failure_prediction_options"
282 "first_notification_delay"
283 "flap_detection_enabled"
284 "flap_detection_options"
285 "freshness_threshold"
287 "high_flap_threshold"
291 "host_notification_commands"
292 "host_notification_options"
293 "host_notification_period"
294 "host_notifications_enabled"
312 "master_service_description"
318 "normal_check_interval"
321 "notification_failure_criteria"
322 "notification_failure_options"
323 "notification_interval"
324 "notification_options"
325 "notification_period"
326 "notifications_enabled"
329 "obsess_over_service"
333 "passive_checks_enabled"
335 "retain_nonstatus_information"
336 "retain_status_information"
337 "retry_check_interval"
340 "service_description"
342 "service_notification_commands"
343 "service_notification_options"
344 "service_notification_period"
345 "service_notifications_enabled"
347 "servicegroup_members"
365 (defconst nagios-macros
405 "$CONTACTGROUPALIAS$"
406 "$CONTACTGROUPMEMBERS$"
408 "$CONTACTGROUPNAMES$"
414 "$HOSTACKAUTHORALIAS$"
415 "$HOSTACKAUTHORNAME$"
420 "$HOSTANDSERVICESIMPORTANCE$"
429 "$HOSTEXECUTIONTIME$"
430 "$HOSTGROUPACTIONURL$"
432 "$HOSTGROUPMEMBERADDRESSES$"
437 "$HOSTGROUPNOTESURL$"
444 "$HOSTNOTIFICATIONENABLED$"
445 "$HOSTNOTIFICATIONID$"
446 "$HOSTNOTIFICATIONNUMBER$"
447 "$HOSTNOTIFICATIONPERIOD$"
449 "$HOSTPERCENTCHANGE$"
460 "$LASTHOSTPROBLEMID$"
462 "$LASTHOSTSTATECHANGE$"
464 "$LASTHOSTUNREACHABLE$"
467 "$LASTSERVICECRITICAL$"
468 "$LASTSERVICEEVENTID$"
470 "$LASTSERVICEPROBLEMID$"
472 "$LASTSERVICESTATECHANGE$"
473 "$LASTSERVICESTATEID$"
474 "$LASTSERVICEUNKNOWN$"
475 "$LASTSERVICEWARNING$"
479 "$LONGSERVICEOUTPUT$"
482 "$MAXSERVICEATTEMPTS$"
484 "$NOTIFICATIONAUTHOR$"
485 "$NOTIFICATIONAUTHORALIAS$"
486 "$NOTIFICATIONAUTHORNAME$"
487 "$NOTIFICATIONCOMMENT$"
488 "$NOTIFICATIONISESCALATED$"
489 "$NOTIFICATIONNUMBER$"
490 "$NOTIFICATIONRECIPIENTS$"
495 "$RETENTIONDATAFILE$"
497 "$SERVICEACKAUTHORALIAS$"
498 "$SERVICEACKAUTHORNAME$"
499 "$SERVICEACKCOMMENT$"
502 "$SERVICECHECKCOMMAND$"
505 "$SERVICEDISPLAYNAME$"
508 "$SERVICEDURATIONSEC$"
510 "$SERVICEEXECUTIONTIME$"
511 "$SERVICEGROUPACTIONURL$"
512 "$SERVICEGROUPALIAS$"
513 "$SERVICEGROUPMEMBERS$"
515 "$SERVICEGROUPNAMES$"
516 "$SERVICEGROUPNOTES$"
517 "$SERVICEGROUPNOTESURL$"
518 "$SERVICEIMPORTANCE$"
520 "$SERVICEISVOLATILE$"
524 "$SERVICENOTIFICATIONENABLED$"
525 "$SERVICENOTIFICATIONID$"
526 "$SERVICENOTIFICATIONNUMBER$"
527 "$SERVICENOTIFICATIONPERIOD$"
529 "$SERVICEPERCENTCHANGE$"
531 "$SERVICEPERFDATAFILE$"
542 "$TOTALHOSTPROBLEMS$"
543 "$TOTALHOSTPROBLEMSUNHANDLED$"
545 "$TOTALHOSTSDOWNUNHANDLED$"
546 "$TOTALHOSTSERVICES$"
547 "$TOTALHOSTSERVICESCRITICAL$"
548 "$TOTALHOSTSERVICESOK$"
549 "$TOTALHOSTSERVICESUNKNOWN$"
550 "$TOTALHOSTSERVICESWARNING$"
551 "$TOTALHOSTSUNREACHABLE$"
552 "$TOTALHOSTSUNREACHABLEUNHANDLED$"
554 "$TOTALSERVICEPROBLEMS$"
555 "$TOTALSERVICEPROBLEMSUNHANDLED$"
556 "$TOTALSERVICESCRITICAL$"
557 "$TOTALSERVICESCRITICALUNHANDLED$"
559 "$TOTALSERVICESUNKNOWN$"
560 "$TOTALSERVICESUNKNOWNUNHANDLED$"
561 "$TOTALSERVICESWARNING$"
562 "$TOTALSERVICESWARNINGUNHANDLED$"
823 (defconst nagios-definitions
826 (concat "^[ \t\r\n]*"
828 "\\(" ;; Stick parenthesis around whatever comes out
829 ;; of regexp-opt. We use this to match a
830 ;; subexpression during font-lock.
834 "define contactgroup"
836 "define hostdependency"
837 "define hostescalation"
842 "define servicedependency"
843 "define serviceescalation"
844 "define serviceextinfo"
845 "define servicegroup"
846 "define timeperiod"))
847 ;; This closes the parentheses that we opened
848 "\\)" ;; before regexp-opt.
850 ;; These can be "terminated" by either an opening curly
851 ;; brace, or a space.
858 (defconst nagios-special
860 (concat "^[ \t\r\n]*"
863 '("name" "register" "use") t)
870 ;; The One True Font Locking Variable
872 (defvar nagios-font-lock-keywords
874 (cons nagios-special font-lock-keyword-face)
875 (cons nagios-directives font-lock-variable-name-face)
876 (cons nagios-macros font-lock-constant-face)
877 (cons nagios-definitions '(1 font-lock-function-name-face)))
879 "Rules for highlighting Nagios configuration files."
884 (defvar nagios-mode-syntax-table nil
885 "Syntax table used in nagios-mode buffers.")
886 (if nagios-mode-syntax-table
888 (setq nagios-mode-syntax-table (make-syntax-table))
889 (modify-syntax-entry ?# "< b" nagios-mode-syntax-table) ;; Comment style 1
890 (modify-syntax-entry ?\; "< b" nagios-mode-syntax-table) ;; Comment style 2
891 (modify-syntax-entry ?\n "> b" nagios-mode-syntax-table) ;; End comment
895 ;; Main Mode Function
898 "Major mode for editing Nagios configuration files."
901 (kill-all-local-variables)
902 (make-local-variable 'font-lock-defaults)
903 (make-local-variable 'comment-start)
904 (make-local-variable 'comment-start-skip)
905 (make-local-variable 'comment-end)
906 (make-local-variable 'indent-line-function)
908 (set-syntax-table nagios-mode-syntax-table)
910 (setq mode-name "nagios"
911 major-mode 'nagios-mode
912 indent-line-function 'nagios-indent-line
913 font-lock-defaults '(nagios-font-lock-keywords)
915 comment-start-skip "#\|; +"
920 (use-local-map nagios-mode-map)
922 ;; I don't /think/ I need to define this before attempting
923 ;; to run it. Users can define it if they want.
924 (run-hooks 'nagios-mode-hook)
928 (provide 'nagios-mode)