| 1 | ;;; snmp-mode.el --- SNMP & SNMPv2 MIB major mode. |
| 2 | |
| 3 | ;; Copyright (C) 1995,1998 Free Software Foundation, Inc. |
| 4 | |
| 5 | ;; Author: Paul D. Smith <psmith@BayNetworks.com> |
| 6 | ;; Keywords: data |
| 7 | |
| 8 | ;; This file is part of GNU Emacs. |
| 9 | |
| 10 | ;; GNU Emacs is free software; you can redistribute it and/or modify |
| 11 | ;; it under the terms of the GNU General Public License as published by |
| 12 | ;; the Free Software Foundation; either version 2, or (at your option) |
| 13 | ;; any later version. |
| 14 | |
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 | ;; GNU General Public License for more details. |
| 19 | |
| 20 | ;; You should have received a copy of the GNU General Public License |
| 21 | ;; along with GNU Emacs; see the file COPYING. If not, write to the |
| 22 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| 23 | ;; Boston, MA 02111-1307, USA. |
| 24 | |
| 25 | ;; INTRODUCTION |
| 26 | ;; ------------ |
| 27 | ;; This package provides a major mode for editing SNMP MIBs. It |
| 28 | ;; provides all the modern Emacs 19 bells and whistles: default |
| 29 | ;; fontification via font-lock, imenu search functions, etc. |
| 30 | ;; |
| 31 | ;; SNMP mode also uses tempo, a textual boilerplate insertion package |
| 32 | ;; distributed with Emacs, to add in boilerplate SNMP MIB structures. |
| 33 | ;; See tempo.el for more details about tempo. |
| 34 | ;; |
| 35 | ;; If you want to change or add new tempo templates, use the tempo tag |
| 36 | ;; list `snmp-tempo-tags' (or `snmpv2-tempo-tags'): this list is |
| 37 | ;; automatically installed when snmp-mode (or snmpv2-mode) is entered. |
| 38 | ;; |
| 39 | ;; The SNMPv2 mode in this version has been enhanced thanks to popular |
| 40 | ;; demand. |
| 41 | ;; |
| 42 | ;; I'm very interested in new tempo macros for both v1 and v2, and any |
| 43 | ;; other suggestions for enhancements (different syntax table items, new |
| 44 | ;; keybindings, etc.) |
| 45 | ;; |
| 46 | ;; |
| 47 | ;; USAGE |
| 48 | ;; ----- |
| 49 | ;; Mostly, use it as you would any other mode. There's a very |
| 50 | ;; simplistic auto-indent feature; hopefully it'll help more than get in |
| 51 | ;; your way. For the most part it tries to indent to the same level as |
| 52 | ;; the previous line. It will try to recognize some very simple tokens |
| 53 | ;; on the previous line that tell it to use extra indent or outdent. |
| 54 | ;; |
| 55 | ;; Templates |
| 56 | ;; --------- |
| 57 | ;; To use the Tempo templates, type the Tempo tag (or a unique prefix) |
| 58 | ;; and use C-c C-i (C-c TAB) to complete it; if you don't have |
| 59 | ;; tempo-interactive set to nil it will ask you to fill in values. |
| 60 | ;; Fields with predefined values (SYNTAX, STATUS, etc.) will do |
| 61 | ;; completing-reads on a list of valid values; use the normal SPC or TAB |
| 62 | ;; to complete. |
| 63 | ;; |
| 64 | ;; Currently the following templates are available: |
| 65 | ;; |
| 66 | ;; objectType -- Defines an OBJECT-TYPE macro. |
| 67 | ;; |
| 68 | ;; tableType -- Defines both a Table and Entry OBJECT-TYPE, and a |
| 69 | ;; SEQUENCE for the ASN.1 Entry definition. |
| 70 | ;; |
| 71 | ;; Once the template is done, you can use C-cC-f and C-cC-b to move back |
| 72 | ;; and forth between the Tempo sequence points to fill in the rest of |
| 73 | ;; the information. |
| 74 | ;; |
| 75 | ;; Font Lock |
| 76 | ;; ------------ |
| 77 | ;; |
| 78 | ;; If you want font-lock in your MIB buffers, add this: |
| 79 | ;; |
| 80 | ;; (add-hook 'snmp-common-mode-hook 'turn-on-font-lock) |
| 81 | ;; |
| 82 | ;; Enabling global-font-lock-mode is also sufficient. |
| 83 | ;; |
| 84 | |
| 85 | ;;;---------------------------------------------------------------------------- |
| 86 | ;; |
| 87 | ;; Customize these: |
| 88 | ;; |
| 89 | ;;;---------------------------------------------------------------------------- |
| 90 | |
| 91 | (defgroup snmp nil |
| 92 | "Mode for editing SNMP MIB files." |
| 93 | :group 'data |
| 94 | :version "20.4") |
| 95 | |
| 96 | (defcustom snmp-special-indent t |
| 97 | "*If non-nil, use a simple heuristic to try to guess the right indentation. |
| 98 | If nil, then no special indentation is attempted." |
| 99 | :type 'boolean |
| 100 | :group 'snmp) |
| 101 | |
| 102 | (defcustom snmp-indent-level 4 |
| 103 | "*Indentation level for SNMP MIBs." |
| 104 | :type 'integer |
| 105 | :group 'snmp) |
| 106 | |
| 107 | (defcustom snmp-tab-always-indent nil |
| 108 | "*Non-nil means TAB should always reindent the current line. |
| 109 | A value of nil means reindent if point is within the initial line indentation; |
| 110 | otherwise insert a TAB." |
| 111 | :type 'boolean |
| 112 | :group 'snmp) |
| 113 | |
| 114 | (defcustom snmp-completion-ignore-case t |
| 115 | "*Non-nil means that case differences are ignored during completion. |
| 116 | A value of nil means that case is significant. |
| 117 | This is used during Tempo template completion." |
| 118 | :type 'boolean |
| 119 | :group 'snmp) |
| 120 | |
| 121 | (defcustom snmp-common-mode-hook nil |
| 122 | "*Hook(s) evaluated when a buffer enters either SNMP or SNMPv2 mode." |
| 123 | :type 'hook |
| 124 | :group 'snmp) |
| 125 | |
| 126 | (defcustom snmp-mode-hook nil |
| 127 | "*Hook(s) evaluated when a buffer enters SNMP mode." |
| 128 | :type 'hook |
| 129 | :group 'snmp) |
| 130 | |
| 131 | (defcustom snmpv2-mode-hook nil |
| 132 | "*Hook(s) evaluated when a buffer enters SNMPv2 mode." |
| 133 | :type 'hook |
| 134 | :group 'snmp) |
| 135 | |
| 136 | (defvar snmp-tempo-tags nil |
| 137 | "*Tempo tags for SNMP mode.") |
| 138 | |
| 139 | (defvar snmpv2-tempo-tags nil |
| 140 | "*Tempo tags for SNMPv2 mode.") |
| 141 | |
| 142 | |
| 143 | ;; Enable fontification for SNMP MIBs |
| 144 | ;; |
| 145 | |
| 146 | ;; These are pretty basic fontifications. Note we assume these macros |
| 147 | ;; are first on a line (except whitespace), to speed up fontification. |
| 148 | ;; |
| 149 | (defvar snmp-font-lock-keywords-1 |
| 150 | (list |
| 151 | ;; OBJECT-TYPE, TRAP-TYPE, and OBJECT-IDENTIFIER macros |
| 152 | '("^[ \t]*\\([a-z][-a-zA-Z0-9]+\\)[ \t]+\\(\\(MODULE-\\(COMPLIANCE\\|IDENTITY\\)\\|OBJECT-\\(COMPLIANCE\\|GROUP\\|IDENTITY\\|TYPE\\)\\|TRAP-\\(GROUP\\|TYPE\\)\\)\\|\\(OBJECT\\)[ \t]+\\(IDENTIFIER\\)[ \t]*::=\\)" |
| 153 | (1 font-lock-variable-name-face) (3 font-lock-keyword-face nil t) |
| 154 | (7 font-lock-keyword-face nil t) (8 font-lock-keyword-face nil t)) |
| 155 | |
| 156 | ;; DEFINITIONS clause |
| 157 | '("^[ \t]*\\([A-Z][-a-zA-Z0-9]+\\)[ \t]+\\(DEFINITIONS\\)[ \t]*::=" |
| 158 | (1 font-lock-function-name-face) (2 font-lock-keyword-face)) |
| 159 | ) |
| 160 | "Basic SNMP MIB mode expression highlighting.") |
| 161 | |
| 162 | (defvar snmp-font-lock-keywords-2 |
| 163 | (append |
| 164 | '(("ACCESS\\|BEGIN\\|DE\\(FVAL\\|SCRIPTION\\)\\|END\\|FROM\\|I\\(MPORTS\\|NDEX\\)\\|S\\(TATUS\\|YNTAX\\)" |
| 165 | (0 font-lock-keyword-face))) |
| 166 | snmp-font-lock-keywords-1) |
| 167 | "Medium SNMP MIB mode expression highlighting.") |
| 168 | |
| 169 | (defvar snmp-font-lock-keywords-3 |
| 170 | (append |
| 171 | '(("\\([^\n]+\\)[ \t]+::=[ \t]+\\(SEQUENCE\\)[ \t]+{" |
| 172 | (1 font-lock-reference-face) (2 font-lock-keyword-face)) |
| 173 | ("::=[ \t]*{[ \t]*\\([a-z0-9].*[ \t]+\\)?\\([0-9]+\\)[ \t]*}" |
| 174 | (1 font-lock-reference-face nil t) (2 font-lock-variable-name-face))) |
| 175 | snmp-font-lock-keywords-2) |
| 176 | "Gaudy SNMP MIB mode expression highlighting.") |
| 177 | |
| 178 | (defvar snmp-font-lock-keywords snmp-font-lock-keywords-1 |
| 179 | "Default SNMP MIB mode expression highlighting.") |
| 180 | |
| 181 | |
| 182 | ;; These lists are used for the completion capabilities in the tempo |
| 183 | ;; templates. |
| 184 | ;; |
| 185 | |
| 186 | (defvar snmp-mode-syntax-list nil |
| 187 | "Predefined types for SYNTAX clauses.") |
| 188 | |
| 189 | (defvar snmp-rfc1155-types |
| 190 | '(("INTEGER") ("OCTET STRING") ("OBJECT IDENTIFIER") ("NULL") ("IpAddress") |
| 191 | ("NetworkAddress") ("Counter") ("Gauge") ("TimeTicks") ("Opaque")) |
| 192 | "Types from RFC 1155 v1 SMI.") |
| 193 | |
| 194 | (defvar snmp-rfc1213-types |
| 195 | '(("DisplayString")) |
| 196 | "Types from RFC 1213 MIB-II.") |
| 197 | |
| 198 | (defvar snmp-rfc1902-types |
| 199 | '(("INTEGER") ("OCTET STRING") ("OBJECT IDENTIFIER") ("Integer32") |
| 200 | ("IpAddress") ("Counter32") ("Gauge32") ("Unsigned32") ("TimeTicks") |
| 201 | ("Opaque") ("Counter64")) |
| 202 | "Types from RFC 1902 v2 SMI.") |
| 203 | |
| 204 | (defvar snmp-rfc1903-types |
| 205 | '(("DisplayString") ("PhysAddress") ("MacAddress") ("TruthValue") |
| 206 | ("TestAndIncr") ("AutonomousType") ("InstancePointer") |
| 207 | ("VariablePointer") ("RowPointer") ("RowStatus") ("TimeStamp") |
| 208 | ("TimeInterval") ("DateAndTime") ("StorageType") ("TDomain") |
| 209 | ("TAddress")) |
| 210 | "Types from RFC 1903 Textual Conventions.") |
| 211 | |
| 212 | |
| 213 | (defvar snmp-mode-access-list nil |
| 214 | "Predefined values for ACCESS clauses.") |
| 215 | |
| 216 | (defvar snmp-rfc1155-access |
| 217 | '(("read-only") ("read-write") ("write-only") ("not-accessible")) |
| 218 | "ACCESS values from RFC 1155 v1 SMI.") |
| 219 | |
| 220 | (defvar snmp-rfc1902-access |
| 221 | '(("read-only") ("read-write") ("read-create") ("not-accessible") |
| 222 | ("accessible-for-notify")) |
| 223 | "ACCESS values from RFC 1155 v1 SMI.") |
| 224 | |
| 225 | |
| 226 | (defvar snmp-mode-status-list nil |
| 227 | "Predefined values for STATUS clauses.") |
| 228 | |
| 229 | (defvar snmp-rfc1212-status |
| 230 | '(("mandatory") ("obsolete") ("deprecated")) |
| 231 | "STATUS values from RFC 1212 v1 SMI.") |
| 232 | |
| 233 | (defvar snmp-rfc1902-status |
| 234 | '(("current") ("obsolete") ("deprecated")) |
| 235 | "STATUS values from RFC 1902 v2 SMI.") |
| 236 | |
| 237 | |
| 238 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 239 | ;;;---------------------------------------------------------------------------- |
| 240 | ;; |
| 241 | ;; Nothing to customize below here. |
| 242 | ;; |
| 243 | ;;;---------------------------------------------------------------------------- |
| 244 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 245 | |
| 246 | |
| 247 | ;; Need this stuff when compiling for imenu macros, etc. |
| 248 | ;; |
| 249 | (eval-when-compile |
| 250 | (require 'cl) |
| 251 | (require 'imenu)) |
| 252 | |
| 253 | |
| 254 | ;; Create abbrev table for SNMP MIB mode |
| 255 | ;; |
| 256 | (defvar snmp-mode-abbrev-table nil |
| 257 | "Abbrev table in use in SNMP mode.") |
| 258 | (define-abbrev-table 'snmp-mode-abbrev-table ()) |
| 259 | |
| 260 | |
| 261 | ;; Create abbrev table for SNMPv2 mode |
| 262 | ;; |
| 263 | (defvar snmpv2-mode-abbrev-table nil |
| 264 | "Abbrev table in use in SNMPv2 mode.") |
| 265 | (define-abbrev-table 'snmpv2-mode-abbrev-table ()) |
| 266 | |
| 267 | |
| 268 | ;; Set up our keymap |
| 269 | ;; |
| 270 | (defvar snmp-mode-map (make-sparse-keymap) |
| 271 | "Keymap used in SNMP mode.") |
| 272 | |
| 273 | (define-key snmp-mode-map "\t" 'snmp-indent-command) |
| 274 | (define-key snmp-mode-map "\177" 'backward-delete-char-untabify) |
| 275 | |
| 276 | (define-key snmp-mode-map "\C-c\C-i" 'tempo-complete-tag) |
| 277 | (define-key snmp-mode-map "\C-c\C-f" 'tempo-forward-mark) |
| 278 | (define-key snmp-mode-map "\C-c\C-b" 'tempo-backward-mark) |
| 279 | |
| 280 | |
| 281 | ;; Set up our syntax table |
| 282 | ;; |
| 283 | (defvar snmp-mode-syntax-table nil |
| 284 | "Syntax table used for buffers in SNMP mode.") |
| 285 | |
| 286 | (if snmp-mode-syntax-table |
| 287 | () |
| 288 | (setq snmp-mode-syntax-table (make-syntax-table)) |
| 289 | (modify-syntax-entry ?\\ "\\" snmp-mode-syntax-table) |
| 290 | (modify-syntax-entry ?- "_ 1234" snmp-mode-syntax-table) |
| 291 | (modify-syntax-entry ?\n ">" snmp-mode-syntax-table) |
| 292 | (modify-syntax-entry ?\^m ">" snmp-mode-syntax-table) |
| 293 | (modify-syntax-entry ?_ "." snmp-mode-syntax-table) |
| 294 | (modify-syntax-entry ?: "." snmp-mode-syntax-table) |
| 295 | (modify-syntax-entry ?= "." snmp-mode-syntax-table)) |
| 296 | |
| 297 | ;; Set up the stuff that's common between snmp-mode and snmpv2-mode |
| 298 | ;; |
| 299 | (defun snmp-common-mode (name mode abbrev font-keywords imenu-index tempo-tags) |
| 300 | (kill-all-local-variables) |
| 301 | |
| 302 | ;; Become the current major mode |
| 303 | (setq mode-name name) |
| 304 | (setq major-mode mode) |
| 305 | |
| 306 | ;; Activate keymap, syntax table, and abbrev table |
| 307 | (use-local-map snmp-mode-map) |
| 308 | (set-syntax-table snmp-mode-syntax-table) |
| 309 | (setq local-abbrev-table abbrev) |
| 310 | |
| 311 | ;; Set up paragraphs (?) |
| 312 | (make-local-variable 'paragraph-start) |
| 313 | (setq paragraph-start (concat "$\\|" page-delimiter)) |
| 314 | (make-local-variable 'paragraph-separate) |
| 315 | (setq paragraph-separate paragraph-start) |
| 316 | (make-local-variable 'paragraph-ignore-fill-prefix) |
| 317 | (setq paragraph-ignore-fill-prefix t) |
| 318 | |
| 319 | ;; Set up comments |
| 320 | (make-local-variable 'comment-start) |
| 321 | (setq comment-start "-- ") |
| 322 | (make-local-variable 'comment-start-skip) |
| 323 | (setq comment-start-skip "--+[ \t]*") |
| 324 | (make-local-variable 'comment-column) |
| 325 | (setq comment-column 40) |
| 326 | (make-local-variable 'parse-sexp-ignore-comments) |
| 327 | (setq parse-sexp-ignore-comments t) |
| 328 | |
| 329 | ;; Set up indentation |
| 330 | (make-local-variable 'indent-line-function) |
| 331 | (setq indent-line-function (if snmp-special-indent |
| 332 | 'snmp-indent-line |
| 333 | 'indent-to-left-margin)) |
| 334 | |
| 335 | ;; Font Lock |
| 336 | (make-local-variable 'font-lock-defaults) |
| 337 | (setq font-lock-defaults (cons font-keywords '(nil nil ((?- . "w 1234"))))) |
| 338 | |
| 339 | ;; Imenu |
| 340 | (make-local-variable 'imenu-create-index-function) |
| 341 | (setq imenu-create-index-function imenu-index) |
| 342 | |
| 343 | ;; Tempo |
| 344 | (tempo-use-tag-list tempo-tags) |
| 345 | (make-local-variable 'tempo-match-finder) |
| 346 | (setq tempo-match-finder "\\b\\(.+\\)\\=") |
| 347 | (make-local-variable 'tempo-interactive) |
| 348 | (setq tempo-interactive t) |
| 349 | |
| 350 | ;; Miscellaneous customization |
| 351 | (make-local-variable 'require-final-newline) |
| 352 | (setq require-final-newline t)) |
| 353 | |
| 354 | |
| 355 | ;; SNMPv1 MIB Editing Mode. |
| 356 | ;; |
| 357 | ;;;###autoload |
| 358 | (defun snmp-mode () |
| 359 | "Major mode for editing SNMP MIBs. |
| 360 | Expression and list commands understand all C brackets. |
| 361 | Tab indents for C code. |
| 362 | Comments start with -- and end with newline or another --. |
| 363 | Delete converts tabs to spaces as it moves back. |
| 364 | \\{snmp-mode-map} |
| 365 | Turning on snmp-mode runs the hooks in `snmp-common-mode-hook', then |
| 366 | `snmp-mode-hook'." |
| 367 | (interactive) |
| 368 | |
| 369 | (snmp-common-mode "SNMP" 'snmp-mode |
| 370 | snmp-mode-abbrev-table |
| 371 | '(snmp-font-lock-keywords |
| 372 | snmp-font-lock-keywords-1 |
| 373 | snmp-font-lock-keywords-2 |
| 374 | snmp-font-lock-keywords-3) |
| 375 | 'snmp-mode-imenu-create-index |
| 376 | 'snmp-tempo-tags) |
| 377 | |
| 378 | ;; Completion lists |
| 379 | (make-local-variable 'snmp-mode-syntax-list) |
| 380 | (setq snmp-mode-syntax-list (append snmp-rfc1155-types |
| 381 | snmp-rfc1213-types |
| 382 | snmp-mode-syntax-list)) |
| 383 | (make-local-variable 'snmp-mode-access-list) |
| 384 | (setq snmp-mode-access-list snmp-rfc1155-access) |
| 385 | (make-local-variable 'snmp-mode-status-list) |
| 386 | (setq snmp-mode-status-list snmp-rfc1212-status) |
| 387 | |
| 388 | ;; Run hooks |
| 389 | (run-hooks 'snmp-common-mode-hook) |
| 390 | (run-hooks 'snmp-mode-hook)) |
| 391 | |
| 392 | |
| 393 | ;;;###autoload |
| 394 | (defun snmpv2-mode () |
| 395 | "Major mode for editing SNMPv2 MIBs. |
| 396 | Expression and list commands understand all C brackets. |
| 397 | Tab indents for C code. |
| 398 | Comments start with -- and end with newline or another --. |
| 399 | Delete converts tabs to spaces as it moves back. |
| 400 | \\{snmp-mode-map} |
| 401 | Turning on snmp-mode runs the hooks in `snmp-common-mode-hook', |
| 402 | then `snmpv2-mode-hook'." |
| 403 | (interactive) |
| 404 | |
| 405 | (snmp-common-mode "SNMPv2" 'snmpv2-mode |
| 406 | snmpv2-mode-abbrev-table |
| 407 | '(snmp-font-lock-keywords |
| 408 | snmp-font-lock-keywords-1 |
| 409 | snmp-font-lock-keywords-2 |
| 410 | snmp-font-lock-keywords-3) |
| 411 | 'snmp-mode-imenu-create-index |
| 412 | 'snmpv2-tempo-tags) |
| 413 | |
| 414 | ;; Completion lists |
| 415 | (make-local-variable 'snmp-mode-syntax-list) |
| 416 | (setq snmp-mode-syntax-list (append snmp-rfc1902-types |
| 417 | snmp-rfc1903-types |
| 418 | snmp-mode-syntax-list)) |
| 419 | (make-local-variable 'snmp-mode-access-list) |
| 420 | (setq snmp-mode-access-list snmp-rfc1902-access) |
| 421 | (make-local-variable 'snmp-mode-status-list) |
| 422 | (setq snmp-mode-status-list snmp-rfc1902-status) |
| 423 | |
| 424 | ;; Run hooks |
| 425 | (run-hooks 'snmp-common-mode-hook) |
| 426 | (run-hooks 'snmpv2-mode-hook)) |
| 427 | |
| 428 | |
| 429 | ;;;---------------------------------------------------------------------------- |
| 430 | ;; |
| 431 | ;; Indentation Setup |
| 432 | ;; |
| 433 | ;;;---------------------------------------------------------------------------- |
| 434 | |
| 435 | (defvar snmp-macro-open |
| 436 | "[a-zA-Z][-a-zA-Z0-9]*[ \t]*\\(OBJECT\\|TRAP\\)-\\(TYPE\\|GROUP\\)\ |
| 437 | \\|DESCRIPTION\\|IMPORTS\\|MODULE\\(-IDENTITY\\|-COMPLIANCE\\)\ |
| 438 | \\|.*::=[ \t]*\\(BEGIN\\|TEXTUAL-CONVENTION\\)[ \t]*$") |
| 439 | |
| 440 | (defvar snmp-macro-close |
| 441 | "::=[ \t]*{\\|\\(END\\|.*[;\"]\\)[ \t]*$") |
| 442 | |
| 443 | (defun snmp-calculate-indent () |
| 444 | "Calculate the current line indentation in SNMP MIB code. |
| 445 | |
| 446 | We use a very simple scheme: if the previous non-empty line was a \"macro |
| 447 | open\" string, add `snmp-indent-level' to it. If it was a \"macro close\" |
| 448 | string, subtract `snmp-indent-level'. Otherwise, use the same indentation |
| 449 | as the previous non-empty line. Note comments are considered empty |
| 450 | lines for the purposes of this function." |
| 451 | (let ((empty (concat "\\([ \t]*\\)\\(" comment-start-skip "\\|$\\)")) |
| 452 | (case-fold-search nil)) ; keywords must be in uppercase |
| 453 | (save-excursion |
| 454 | (while (and (>= (forward-line -1) 0) |
| 455 | (looking-at empty))) |
| 456 | (skip-chars-forward " \t") |
| 457 | (+ (current-column) |
| 458 | ;; Are we looking at a macro open string? If so, add more. |
| 459 | (cond ((looking-at snmp-macro-open) |
| 460 | snmp-indent-level) |
| 461 | ;; macro close string? If so, remove some. |
| 462 | ((looking-at snmp-macro-close) |
| 463 | (- snmp-indent-level)) |
| 464 | ;; Neither; just stay here. |
| 465 | (t 0)))))) |
| 466 | |
| 467 | (defun snmp-indent-line () |
| 468 | "Indent current line as SNMP MIB code." |
| 469 | (let ((indent (snmp-calculate-indent)) |
| 470 | (pos (- (point-max) (point))) |
| 471 | shift-amt beg end) |
| 472 | (beginning-of-line) |
| 473 | (setq beg (point)) |
| 474 | (skip-chars-forward " \t") |
| 475 | (setq shift-amt (- indent (current-column))) |
| 476 | (if (zerop shift-amt) |
| 477 | nil |
| 478 | (delete-region beg (point)) |
| 479 | (indent-to indent)) |
| 480 | ;; If initial point was within line's indentation, |
| 481 | ;; position after the indentation. Else stay at same point in text. |
| 482 | (if (> (- (point-max) pos) (point)) |
| 483 | (goto-char (- (point-max) pos))))) |
| 484 | |
| 485 | (defun snmp-indent-command () |
| 486 | "Indent current line as SNMP MIB code, or sometimes insert a TAB. |
| 487 | If `snmp-tab-always-indent' is t, always reindent the current line when |
| 488 | this command is run. |
| 489 | If `snmp-tab-always-indent' is nil, reindent the current line if point is |
| 490 | in the initial indentation. Otherwise, insert a TAB." |
| 491 | (interactive) |
| 492 | (if (and (not snmp-tab-always-indent) |
| 493 | (save-excursion |
| 494 | (skip-chars-backward " \t") |
| 495 | (not (bolp)))) |
| 496 | (insert-tab) |
| 497 | (snmp-indent-line))) |
| 498 | |
| 499 | |
| 500 | ;;;---------------------------------------------------------------------------- |
| 501 | ;; |
| 502 | ;; Imenu Setup |
| 503 | ;; |
| 504 | ;;;---------------------------------------------------------------------------- |
| 505 | |
| 506 | (defvar snmp-clause-regexp |
| 507 | "^[ \t]*\\([a-zA-Z][-a-zA-Z0-9]*\\)[ \t\n]*\ |
| 508 | \\(TRAP-TYPE\\|::=\\|OBJECT\\(-TYPE[ \t\n]+SYNTAX\\|[ \t\n]+IDENTIFIER[ \t\n]*::=\\)\\)") |
| 509 | |
| 510 | (defun snmp-mode-imenu-create-index () |
| 511 | (let ((index-alist '()) |
| 512 | (index-oid-alist '()) |
| 513 | (index-tc-alist '()) |
| 514 | (index-table-alist '()) |
| 515 | (index-trap-alist '()) |
| 516 | (case-fold-search nil) ; keywords must be uppercase |
| 517 | prev-pos token marker end) |
| 518 | (goto-char (point-min)) |
| 519 | (imenu-progress-message prev-pos 0) |
| 520 | ;; Search for a useful MIB item (that's not in a comment) |
| 521 | (save-match-data |
| 522 | (while (re-search-forward snmp-clause-regexp nil t) |
| 523 | (imenu-progress-message prev-pos) |
| 524 | (setq |
| 525 | end (match-end 0) |
| 526 | token (cons (buffer-substring (match-beginning 1) (match-end 1)) |
| 527 | (set-marker (make-marker) (match-beginning 1)))) |
| 528 | (goto-char (match-beginning 2)) |
| 529 | (cond ((looking-at "OBJECT-TYPE[ \t\n]+SYNTAX") |
| 530 | (push token index-alist)) |
| 531 | ((looking-at "OBJECT[ \t\n]+IDENTIFIER[ \t\n]*::=") |
| 532 | (push token index-oid-alist)) |
| 533 | ((looking-at "::=[ \t\n]*SEQUENCE[ \t\n]*{") |
| 534 | (push token index-table-alist)) |
| 535 | ((looking-at "TRAP-TYPE") |
| 536 | (push token index-trap-alist)) |
| 537 | ((looking-at "::=") |
| 538 | (push token index-tc-alist))) |
| 539 | (goto-char end))) |
| 540 | ;; Create the menu |
| 541 | (imenu-progress-message prev-pos 100) |
| 542 | (setq index-alist (nreverse index-alist)) |
| 543 | (and index-tc-alist |
| 544 | (push (cons "Textual Conventions" (nreverse index-tc-alist)) |
| 545 | index-alist)) |
| 546 | (and index-trap-alist |
| 547 | (push (cons "Traps" (nreverse index-trap-alist)) |
| 548 | index-alist)) |
| 549 | (and index-table-alist |
| 550 | (push (cons "Tables" (nreverse index-table-alist)) |
| 551 | index-alist)) |
| 552 | (and index-oid-alist |
| 553 | (push (cons "Object IDs" (nreverse index-oid-alist)) |
| 554 | index-alist)) |
| 555 | index-alist)) |
| 556 | |
| 557 | |
| 558 | ;;;---------------------------------------------------------------------------- |
| 559 | ;; |
| 560 | ;; Tempo Setup |
| 561 | ;; |
| 562 | ;;;---------------------------------------------------------------------------- |
| 563 | |
| 564 | (require 'tempo) |
| 565 | |
| 566 | ;; Perform a completing-read with info given |
| 567 | ;; |
| 568 | (defun snmp-completing-read (prompt table &optional pred require init hist) |
| 569 | "Read from the minibuffer, with completion. |
| 570 | Like `completing-read', but the variable `snmp-completion-ignore-case' |
| 571 | controls whether case is significant." |
| 572 | (let ((completion-ignore-case snmp-completion-ignore-case)) |
| 573 | (completing-read prompt table pred require init hist))) |
| 574 | |
| 575 | ;; OBJECT-TYPE macro template |
| 576 | ;; |
| 577 | (tempo-define-template "snmp-object-type" |
| 578 | '(> (P "Object Label: ") " OBJECT-TYPE" n> |
| 579 | "SYNTAX " |
| 580 | (if tempo-interactive |
| 581 | (snmp-completing-read "Syntax: " snmp-mode-syntax-list nil nil) |
| 582 | p) n> |
| 583 | "ACCESS " |
| 584 | (if tempo-interactive |
| 585 | (snmp-completing-read "Access: " snmp-mode-access-list nil t) |
| 586 | p) n> |
| 587 | "STATUS " |
| 588 | (if tempo-interactive |
| 589 | (snmp-completing-read "Status: " snmp-mode-status-list nil t) |
| 590 | p) n> |
| 591 | "DESCRIPTION" n> "\"" p "\"" n> |
| 592 | (P "Default Value: " defval t) |
| 593 | (if (string= "" (tempo-lookup-named 'defval)) |
| 594 | nil |
| 595 | '(l "DEFVAL { " (s defval) " }" n>)) |
| 596 | "::= { " (p "OID: ") " }" n) |
| 597 | "objectType" |
| 598 | "Insert an OBJECT-TYPE macro." |
| 599 | 'snmp-tempo-tags) |
| 600 | |
| 601 | ;; Table macro template |
| 602 | ;; |
| 603 | (tempo-define-template "snmp-table-type" |
| 604 | ;; First the table OBJECT-TYPE |
| 605 | '(> (P "Table Name: " table) |
| 606 | (P "Entry Name: " entry t) |
| 607 | (let* ((entry (tempo-lookup-named 'entry)) |
| 608 | (seq (copy-sequence entry))) |
| 609 | (aset entry 0 (downcase (aref entry 0))) |
| 610 | (aset seq 0 (upcase (aref seq 0))) |
| 611 | (tempo-save-named 'obj-entry entry) |
| 612 | (tempo-save-named 'seq-entry seq) |
| 613 | nil) |
| 614 | " OBJECT-TYPE" n> |
| 615 | "SYNTAX SEQUENCE OF " |
| 616 | (s seq-entry) n> |
| 617 | "ACCESS not-accessible" n> |
| 618 | "STATUS mandatory" n> |
| 619 | "DESCRIPTION" n> "\"" p "\"" n> |
| 620 | "::= { " (p "OID: ") " }" n n> |
| 621 | ;; Next the row OBJECT-TYPE |
| 622 | (s obj-entry) " OBJECT-TYPE" n> |
| 623 | "SYNTAX " (s seq-entry) n> |
| 624 | "ACCESS not-accessible" n> |
| 625 | "STATUS mandatory" n> |
| 626 | "DESCRIPTION" n> "\"" p "\"" n> |
| 627 | "INDEX { " (p "Index List: ") " }" n> |
| 628 | "::= {" (s table) " 1 }" n n> |
| 629 | ;; Finally the SEQUENCE type |
| 630 | (s seq-entry) " ::= SEQUENCE {" n> p n> "}" n) |
| 631 | "tableType" |
| 632 | "Insert an SNMP table." |
| 633 | 'snmp-tempo-tags) |
| 634 | |
| 635 | |
| 636 | ;; v2 SMI OBJECT-TYPE macro template |
| 637 | ;; |
| 638 | (tempo-define-template "snmpv2-object-type" |
| 639 | '(> (P "Object Label: ") " OBJECT-TYPE" n> |
| 640 | "SYNTAX " |
| 641 | (if tempo-interactive |
| 642 | (snmp-completing-read "Syntax: " snmp-mode-syntax-list nil nil) |
| 643 | p) n> |
| 644 | "MAX-ACCESS " |
| 645 | (if tempo-interactive |
| 646 | (snmp-completing-read "Max Access: " snmp-mode-access-list nil t) |
| 647 | p) n> |
| 648 | "STATUS " |
| 649 | (if tempo-interactive |
| 650 | (snmp-completing-read "Status: " snmp-mode-status-list nil t) |
| 651 | p) n> |
| 652 | "DESCRIPTION" n> "\"" p "\"" n> |
| 653 | (P "Default Value: " defval t) |
| 654 | (if (string= "" (tempo-lookup-named 'defval)) |
| 655 | nil |
| 656 | '(l "DEFVAL { " (s defval) " }" n>)) |
| 657 | "::= { " (p "OID: ") " }" n) |
| 658 | "objectType" |
| 659 | "Insert an v2 SMI OBJECT-TYPE macro." |
| 660 | 'snmpv2-tempo-tags) |
| 661 | |
| 662 | ;; v2 SMI Table macro template |
| 663 | ;; |
| 664 | (tempo-define-template "snmpv2-table-type" |
| 665 | ;; First the table OBJECT-TYPE |
| 666 | '(> (P "Table Name: " table) |
| 667 | (P "Entry Name: " entry t) |
| 668 | (let* ((entry (tempo-lookup-named 'entry)) |
| 669 | (seq (copy-sequence entry))) |
| 670 | (aset entry 0 (downcase (aref entry 0))) |
| 671 | (aset seq 0 (upcase (aref seq 0))) |
| 672 | (tempo-save-named 'obj-entry entry) |
| 673 | (tempo-save-named 'seq-entry seq) |
| 674 | nil) |
| 675 | " OBJECT-TYPE" n> |
| 676 | "SYNTAX SEQUENCE OF " |
| 677 | (s seq-entry) n> |
| 678 | "MAX-ACCESS not-accessible" n> |
| 679 | "STATUS current" n> |
| 680 | "DESCRIPTION" n> "\"" p "\"" n> |
| 681 | "::= { " (p "OID: ") " }" n n> |
| 682 | ;; Next the row OBJECT-TYPE |
| 683 | (s obj-entry) " OBJECT-TYPE" n> |
| 684 | "SYNTAX " (s seq-entry) n> |
| 685 | "MAX-ACCESS not-accessible" n> |
| 686 | "STATUS current" n> |
| 687 | "DESCRIPTION" n> "\"" p "\"" n> |
| 688 | "INDEX { " (p "Index List: ") " }" n> |
| 689 | "::= { " (s table) " 1 }" n n> |
| 690 | ;; Finally the SEQUENCE type |
| 691 | (s seq-entry) " ::= SEQUENCE {" n> p n> "}" n) |
| 692 | "tableType" |
| 693 | "Insert an v2 SMI SNMP table." |
| 694 | 'snmpv2-tempo-tags) |
| 695 | |
| 696 | ;; v2 SMI TEXTUAL-CONVENTION macro template |
| 697 | ;; |
| 698 | (tempo-define-template "snmpv2-textual-convention" |
| 699 | '(> (P "Texual Convention Type: ") " ::= TEXTUAL-CONVENTION" n> |
| 700 | "STATUS " |
| 701 | (if tempo-interactive |
| 702 | (snmp-completing-read "Status: " snmp-mode-status-list nil t) |
| 703 | p) n> |
| 704 | "DESCRIPTION" n> "\"" p "\"" n> |
| 705 | "SYNTAX " |
| 706 | (if tempo-interactive |
| 707 | (snmp-completing-read "Syntax: " snmp-mode-syntax-list nil nil) |
| 708 | p) n> ) |
| 709 | "textualConvention" |
| 710 | "Insert an v2 SMI TEXTUAL-CONVENTION macro." |
| 711 | 'snmpv2-tempo-tags) |
| 712 | |
| 713 | |
| 714 | (provide 'snmp-mode) |
| 715 | |
| 716 | ;; snmp-mode.el ends here |