;; ;; nagios-mode, an Emacs mode for Nagios ;; configuration files. ;; ;; Copyright Michael Orlitzky ;; ;; http://michael.orlitzky.com/ ;; ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; http://www.fsf.org/licensing/licenses/gpl.html ;; (require 'font-lock) (require 'regexp-opt) ;; Custom Variables (defcustom nagios-indent-level 2 "Number of spaces in one indentation (tab)." :type 'integer :group 'nagios ) ;; Indentation Voodoo (defun nagios-indent-line(&optional flag) "Indents a line, taking nesting into account." (interactive) (nagios-indent-to (nagios-calculate-indent)) ) (defun beginning-of-line-pos() ;; Return the point position corresponding to the beginning ;; of the current line. (save-excursion (beginning-of-line) (point) ) ) (defun end-of-line-pos() ;; Return the point position corresponding to the end ;; of the current line. (save-excursion (end-of-line) (point) ) ) (defun pos-offset() ;; How far are we from the beginning of the line? (- (point) (beginning-of-line-pos)) ) (defun first-char-offset() ;; How far is the first character on this line ;; from the beginning of the line? (save-excursion (+ (pos-offset) (skip-chars-forward " \t")) ) ) (defun first-char-pos() ;; What's the position of the first character on this line? (+ (beginning-of-line-pos) (first-char-offset)) ) (defun nagios-indent-to(indent-column) "Indent the current line to column indent-column." ;; Store the point in orig-pos. (let ((orig-point (point))) ;; And store the offset of the first character (with respect to the ;; beginning of the line) in orig-first-char-offset. (let ((orig-first-char-offset (first-char-offset))) ;; Delete any leading whitespace, and move the point to the ;; beginning of the line. (delete-region (beginning-of-line-pos) (first-char-pos)) (beginning-of-line) ;; Now insert indent-column spaces. (while (< 0 indent-column) (insert " ") (setq indent-column (- indent-column 1))) ;; The text on the current line just moved left/right some amount; ;; call it text-delta. We want to move the point that same distance. (let ((text-delta (- (first-char-offset) orig-first-char-offset))) (goto-char (+ orig-point text-delta)) ) ) ) ) (defun last-opening-brace() ;; Get the position of the last opening brace, with ;; respect to the current point. (save-excursion (let ((lob (re-search-backward "{" nil t))) (if lob lob -1) ) ) ) (defun last-closing-brace() ;; Get the position of the last closing brace, with ;; respect to the current point. (save-excursion (let ((lcb (re-search-backward "}" nil t))) (if lcb lcb -1) ) ) ) (defun nagios-in-block() "Determine if the point is inside of a {} block." ;; If the last brace seen in the buffer is an opening brace, we're ;; in a block. Otherwise, we aren't. (if (>= (last-closing-brace) (last-opening-brace)) nil t) ) (defun brace-on-line() ;; Is there a curly brace on this line? (save-excursion (re-search-forward "[{}]" (end-of-line-pos) t) ) ) (defun nagios-calculate-indent() "Calculate the level of indentation." ;; We're either inside a block, or we aren't. ;; Initialize the indent variable to either nagios-indent-level ;; or 0 depending on whether or not we're in a block. (let ((indent (if (nagios-in-block) (setq indent nagios-indent-level) 0) ) ) ;; Set the indentation level to 0 if we find either brace on this ;; line. (if (brace-on-line) (setq indent 0) ) indent ) ) ;; Keymaps (defun nagios-insert-right-brace-and-indent() "Insert a '}' character, and indent the line." (interactive) (insert "}") (nagios-indent-line) ) (defvar nagios-mode-map() "Keymap used in nagios mode.") (when (not nagios-mode-map) (setq nagios-mode-map (make-sparse-keymap)) (define-key nagios-mode-map (read-kbd-macro "}") 'nagios-insert-right-brace-and-indent) ) (defconst nagios-directives (eval-when-compile (concat "^[ \t\r\n]*" (regexp-opt '("active_checks_enabled" "address" "alias" "check_command" "check_freshness" "check_interval" "check_period" "checks_enabled" "command_line" "command_name" "contactgroups" "contact_groups" "contactgroup_members" "contact_name" "contactgroup_name" "contacts" "dependent_host_name" "dependent_service_description" "email" "event_handler" "event_handler_enabled" "execution_failure_criteria" "failure_prediction_enabled" "first_notification" "first_notification_delay" "flap_detection_enabled" "freshness_threshold" "friday" "high_flap_threshold" "host_name" "host_notification_commands" "host_notification_options" "host_notification_period" "host_notifications_enabled" "hostgroup_name" "hostgroups" "is_volatile" "last_notification" "low_flap_threshold" "max_check_attempts" "members" "monday" "normal_check_interval" "notes" "notification_failure_criteria" "notification_interval" "notification_options" "notification_period" "notifications_enabled" "obsess_over_service" "pager" "parallelize_check" "parents" "passive_checks_enabled" "process_perf_data" "retain_nonstatus_information" "retain_status_information" "retry_check_interval" "retry_interval" "saturday" "service_description" "service_notification_commands" "service_notification_options" "service_notification_period" "service_notifications_enabled" "servicegroup_name" "stalking_options" "sunday" "thursday" "timeperiod_name" "tuesday" "wednesday") t) "[ \r\n\t]+") ) ) (defconst nagios-macros (eval-when-compile (regexp-opt '("$ADMINEMAIL$" "$ADMINPAGER$" "$ARG1$" "$ARG10$" "$ARG11$" "$ARG12$" "$ARG13$" "$ARG14$" "$ARG15$" "$ARG16$" "$ARG17$" "$ARG18$" "$ARG19$" "$ARG2$" "$ARG20$" "$ARG21$" "$ARG22$" "$ARG23$" "$ARG24$" "$ARG25$" "$ARG26$" "$ARG27$" "$ARG28$" "$ARG29$" "$ARG3$" "$ARG30$" "$ARG31$" "$ARG32$" "$ARG4$" "$ARG5$" "$ARG6$" "$ARG7$" "$ARG8$" "$ARG9$" "$COMMANDFILE$" "$CONTACTALIAS$" "$CONTACTEMAIL$" "$CONTACTGROUPALIAS$" "$CONTACTGROUPMEMBERS$" "$CONTACTGROUPNAME$" "$CONTACTGROUPNAMES$" "$CONTACTNAME$" "$CONTACTPAGER$" "$DATE$" "$EVENTSTARTTIME$" "$HOSTACKAUTHOR$" "$HOSTACKAUTHORALIAS$" "$HOSTACKAUTHORNAME$" "$HOSTACKCOMMENT$" "$HOSTACTIONURL$" "$HOSTADDRESS$" "$HOSTALIAS$" "$HOSTATTEMPT$" "$HOSTCHECKCOMMAND$" "$HOSTCHECKTYPE$" "$HOSTDISPLAYNAME$" "$HOSTDOWNTIME$" "$HOSTDURATION$" "$HOSTDURATIONSEC$" "$HOSTEVENTID$" "$HOSTEXECUTIONTIME$" "$HOSTGROUPACTIONURL$" "$HOSTGROUPALIAS$" "$HOSTGROUPMEMBERS$" "$HOSTGROUPNAME$" "$HOSTGROUPNAMES$" "$HOSTGROUPNOTES$" "$HOSTGROUPNOTESURL$" "$HOSTLATENCY$" "$HOSTNAME$" "$HOSTNOTES$" "$HOSTNOTESURL$" "$HOSTNOTIFICATIONID$" "$HOSTNOTIFICATIONNUMBER$" "$HOSTOUTPUT$" "$HOSTPERCENTCHANGE$" "$HOSTPERFDATA$" "$HOSTPERFDATAFILE$" "$HOSTPROBLEMID$" "$HOSTSTATE$" "$HOSTSTATEID$" "$HOSTSTATETYPE$" "$ISVALIDTIME$" "$LASTHOSTCHECK$" "$LASTHOSTDOWN$" "$LASTHOSTEVENTID$" "$LASTHOSTPROBLEMID$" "$LASTHOSTSTATE$" "$LASTHOSTSTATECHANGE$" "$LASTHOSTSTATEID$" "$LASTHOSTUNREACHABLE$" "$LASTHOSTUP$" "$LASTSERVICECHECK$" "$LASTSERVICECRITICAL$" "$LASTSERVICEEVENTID$" "$LASTSERVICEOK$" "$LASTSERVICEPROBLEMID$" "$LASTSERVICESTATE$" "$LASTSERVICESTATECHANGE$" "$LASTSERVICESTATEID$" "$LASTSERVICEUNKNOWN$" "$LASTSERVICEWARNING$" "$LOGFILE$" "$LONGDATETIME$" "$LONGHOSTOUTPUT$" "$LONGSERVICEOUTPUT$" "$MAINCONFIGFILE$" "$MAXHOSTATTEMPTS$" "$MAXSERVICEATTEMPTS$" "$NEXTVALIDTIME$" "$NOTIFICATIONAUTHOR$" "$NOTIFICATIONAUTHORALIAS$" "$NOTIFICATIONAUTHORNAME$" "$NOTIFICATIONCOMMENT$" "$NOTIFICATIONISESCALATED$" "$NOTIFICATIONNUMBER$" "$NOTIFICATIONRECIPIENTS$" "$NOTIFICATIONTYPE$" "$OBJECTCACHEFILE$" "$PROCESSSTARTTIME$" "$RESOURCEFILE$" "$RETENTIONDATAFILE$" "$SERVICEACKAUTHOR$" "$SERVICEACKAUTHORALIAS$" "$SERVICEACKAUTHORNAME$" "$SERVICEACKCOMMENT$" "$SERVICEACTIONURL$" "$SERVICEATTEMPT$" "$SERVICECHECKCOMMAND$" "$SERVICECHECKTYPE$" "$SERVICEDESC$" "$SERVICEDISPLAYNAME$" "$SERVICEDOWNTIME$" "$SERVICEDURATION$" "$SERVICEDURATIONSEC$" "$SERVICEEVENTID$" "$SERVICEEXECUTIONTIME$" "$SERVICEGROUPACTIONURL$" "$SERVICEGROUPALIAS$" "$SERVICEGROUPMEMBERS$" "$SERVICEGROUPNAME$" "$SERVICEGROUPNAMES$" "$SERVICEGROUPNOTES$" "$SERVICEGROUPNOTESURL$" "$SERVICEISVOLATILE$" "$SERVICELATENCY$" "$SERVICENOTES$" "$SERVICENOTESURL$" "$SERVICENOTIFICATIONID$" "$SERVICENOTIFICATIONNUMBER$" "$SERVICEOUTPUT$" "$SERVICEPERCENTCHANGE$" "$SERVICEPERFDATA$" "$SERVICEPERFDATAFILE$" "$SERVICEPROBLEMID$" "$SERVICESTATE$" "$SERVICESTATEID$" "$SERVICESTATETYPE$" "$SHORTDATETIME$" "$STATUSDATAFILE$" "$TEMPFILE$" "$TEMPPATH$" "$TIME$" "$TIMET$" "$TOTALHOSTPROBLEMS$" "$TOTALHOSTPROBLEMSUNHANDLED$" "$TOTALHOSTSDOWN$" "$TOTALHOSTSDOWNUNHANDLED$" "$TOTALHOSTSERVICES$" "$TOTALHOSTSERVICESCRITICAL$" "$TOTALHOSTSERVICESOK$" "$TOTALHOSTSERVICESUNKNOWN$" "$TOTALHOSTSERVICESWARNING$" "$TOTALHOSTSUNREACHABLE$" "$TOTALHOSTSUNREACHABLEUNHANDLED$" "$TOTALHOSTSUP$" "$TOTALSERVICEPROBLEMS$" "$TOTALSERVICEPROBLEMSUNHANDLED$" "$TOTALSERVICESCRITICAL$" "$TOTALSERVICESCRITICALUNHANDLED$" "$TOTALSERVICESOK$" "$TOTALSERVICESUNKNOWN$" "$TOTALSERVICESUNKNOWNUNHANDLED$" "$TOTALSERVICESWARNING$" "$TOTALSERVICESWARNINGUNHANDLED$" "$USER1$" "$USER10$" "$USER100$" "$USER101$" "$USER102$" "$USER103$" "$USER104$" "$USER105$" "$USER106$" "$USER107$" "$USER108$" "$USER109$" "$USER11$" "$USER110$" "$USER111$" "$USER112$" "$USER113$" "$USER114$" "$USER115$" "$USER116$" "$USER117$" "$USER118$" "$USER119$" "$USER12$" "$USER120$" "$USER121$" "$USER122$" "$USER123$" "$USER124$" "$USER125$" "$USER126$" "$USER127$" "$USER128$" "$USER129$" "$USER13$" "$USER130$" "$USER131$" "$USER132$" "$USER133$" "$USER134$" "$USER135$" "$USER136$" "$USER137$" "$USER138$" "$USER139$" "$USER14$" "$USER140$" "$USER141$" "$USER142$" "$USER143$" "$USER144$" "$USER145$" "$USER146$" "$USER147$" "$USER148$" "$USER149$" "$USER15$" "$USER150$" "$USER151$" "$USER152$" "$USER153$" "$USER154$" "$USER155$" "$USER156$" "$USER157$" "$USER158$" "$USER159$" "$USER16$" "$USER160$" "$USER161$" "$USER162$" "$USER163$" "$USER164$" "$USER165$" "$USER166$" "$USER167$" "$USER168$" "$USER169$" "$USER17$" "$USER170$" "$USER171$" "$USER172$" "$USER173$" "$USER174$" "$USER175$" "$USER176$" "$USER177$" "$USER178$" "$USER179$" "$USER18$" "$USER180$" "$USER181$" "$USER182$" "$USER183$" "$USER184$" "$USER185$" "$USER186$" "$USER187$" "$USER188$" "$USER189$" "$USER19$" "$USER190$" "$USER191$" "$USER192$" "$USER193$" "$USER194$" "$USER195$" "$USER196$" "$USER197$" "$USER198$" "$USER199$" "$USER2$" "$USER20$" "$USER200$" "$USER201$" "$USER202$" "$USER203$" "$USER204$" "$USER205$" "$USER206$" "$USER207$" "$USER208$" "$USER209$" "$USER21$" "$USER210$" "$USER211$" "$USER212$" "$USER213$" "$USER214$" "$USER215$" "$USER216$" "$USER217$" "$USER218$" "$USER219$" "$USER22$" "$USER220$" "$USER221$" "$USER222$" "$USER223$" "$USER224$" "$USER225$" "$USER226$" "$USER227$" "$USER228$" "$USER229$" "$USER23$" "$USER230$" "$USER231$" "$USER232$" "$USER233$" "$USER234$" "$USER235$" "$USER236$" "$USER237$" "$USER238$" "$USER239$" "$USER24$" "$USER240$" "$USER241$" "$USER242$" "$USER243$" "$USER244$" "$USER245$" "$USER246$" "$USER247$" "$USER248$" "$USER249$" "$USER25$" "$USER250$" "$USER251$" "$USER252$" "$USER253$" "$USER254$" "$USER255$" "$USER256$" "$USER26$" "$USER27$" "$USER28$" "$USER29$" "$USER3$" "$USER30$" "$USER31$" "$USER32$" "$USER33$" "$USER34$" "$USER35$" "$USER36$" "$USER37$" "$USER38$" "$USER39$" "$USER4$" "$USER40$" "$USER41$" "$USER42$" "$USER43$" "$USER44$" "$USER45$" "$USER46$" "$USER47$" "$USER48$" "$USER49$" "$USER5$" "$USER50$" "$USER51$" "$USER52$" "$USER53$" "$USER54$" "$USER55$" "$USER56$" "$USER57$" "$USER58$" "$USER59$" "$USER6$" "$USER60$" "$USER61$" "$USER62$" "$USER63$" "$USER64$" "$USER65$" "$USER66$" "$USER67$" "$USER68$" "$USER69$" "$USER7$" "$USER70$" "$USER71$" "$USER72$" "$USER73$" "$USER74$" "$USER75$" "$USER76$" "$USER77$" "$USER78$" "$USER79$" "$USER8$" "$USER80$" "$USER81$" "$USER82$" "$USER83$" "$USER84$" "$USER85$" "$USER86$" "$USER87$" "$USER88$" "$USER89$" "$USER9$" "$USER90$" "$USER91$" "$USER92$" "$USER93$" "$USER94$" "$USER95$" "$USER96$" "$USER97$" "$USER98$" "$USER99$"))) ) (defconst nagios-definitions (eval-when-compile (concat "^[ \t\r\n]*" "\\(" ;; Stick parenthesis around whatever comes out ;; of regexp-opt. We use this to match a ;; subexpression during font-lock. (regexp-opt '("define command" "define contact" "define contactgroup" "define host" "define hostdependency" "define hostescalation" "define hostextinfo" "define hostgroup" "define hostgroupescalation" "define null" "define service" "define servicedependency" "define serviceescalation" "define serviceextinfo" "define servicegroup" "define timeperiod")) ;; This closes the parentheses that we opened "\\)" ;; before regexp-opt. ;; These can be "terminated" by either an opening curly ;; brace, or a space. "\\({\\| \\)") ) ) (defconst nagios-special (eval-when-compile (concat "^[ \t\r\n]*" (regexp-opt '("name" "register" "use") t) "[ \r\n\t]+")) ) ;; The One True Font Locking Variable (defvar nagios-font-lock-keywords (list (cons nagios-special font-lock-keyword-face) (cons nagios-directives font-lock-variable-name-face) (cons nagios-macros font-lock-constant-face) (cons nagios-definitions '(1 font-lock-function-name-face))) "Rules for highlighting Nagios configuration files." ) (defvar nagios-mode-syntax-table nil "Syntax table used in nagios-mode buffers.") (if nagios-mode-syntax-table nil (setq nagios-mode-syntax-table (make-syntax-table)) (modify-syntax-entry ?# "< b" nagios-mode-syntax-table) ;; Comment style 1 (modify-syntax-entry ?\; "< b" nagios-mode-syntax-table) ;; Comment style 2 (modify-syntax-entry ?\n "> b" nagios-mode-syntax-table) ;; End comment ) ;; Main Mode Function (defun nagios-mode() "Major mode for editing Nagios configuration files." (interactive) (kill-all-local-variables) (make-local-variable 'font-lock-defaults) (make-local-variable 'comment-start) (make-local-variable 'comment-start-skip) (make-local-variable 'comment-end) (make-local-variable 'indent-line-function) (make-local-variable 'syntax-begin-function) (set-syntax-table nagios-mode-syntax-table) (setq mode-name "nagios" major-mode 'nagios-mode indent-line-function 'nagios-indent-line font-lock-defaults '(nagios-font-lock-keywords) comment-start "#" comment-start-skip "#\|; +" comment-end "" ;; Since comments and strings do not span multiple lines, ;; the syntax parser can safely start parsing at the beginning ;; of any line. syntax-begin-function 'beginning-of-line ) ;; Keyboard Mapping (use-local-map nagios-mode-map) ;; I don't /think/ I need to define this before attempting ;; to run it. Users can define it if they want. (run-hooks 'nagios-mode-hook) ) (provide 'nagios-mode)