| 1 | ;;; m4-mode.el --- m4 code editing commands for Emacs |
| 2 | |
| 3 | ;; Copyright (C) 1996-1997, 2001-2013 Free Software Foundation, Inc. |
| 4 | |
| 5 | ;; Author: Andrew Csillag <drew_csillag@geocities.com> |
| 6 | ;; Maintainer: Andrew Csillag <drew_csillag@geocities.com> |
| 7 | ;; Keywords: languages, faces |
| 8 | |
| 9 | ;; This file is part of GNU Emacs. |
| 10 | |
| 11 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
| 12 | ;; it under the terms of the GNU General Public License as published by |
| 13 | ;; the Free Software Foundation, either version 3 of the License, or |
| 14 | ;; (at your option) any later version. |
| 15 | |
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, |
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 19 | ;; GNU General Public License for more details. |
| 20 | |
| 21 | ;; You should have received a copy of the GNU General Public License |
| 22 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
| 23 | |
| 24 | ;;; Commentary: |
| 25 | |
| 26 | ;; A smart editing mode for m4 macro definitions. It seems to have most of the |
| 27 | ;; syntax right (sexp motion commands work, but function motion commands don't). |
| 28 | ;; It also sets the font-lock syntax stuff for colorization |
| 29 | |
| 30 | ;; To Do's: |
| 31 | |
| 32 | ;; * want to make m4-m4-(buffer|region) look sorta like M-x compile look&feel ? |
| 33 | ;; * sexp motion commands don't seem to work right |
| 34 | |
| 35 | ;;; Thanks: |
| 36 | ;;; to Akim Demaille and Terry Jones for the bug reports |
| 37 | ;;; to Simon Marshall for the regexp tip |
| 38 | ;;; to Martin Buchholz for some general fixes |
| 39 | |
| 40 | ;;; Code: |
| 41 | |
| 42 | (defgroup m4 nil |
| 43 | "m4 code editing commands for Emacs." |
| 44 | :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) |
| 45 | :prefix "m4-" |
| 46 | :group 'languages) |
| 47 | |
| 48 | (defcustom m4-program |
| 49 | (cond |
| 50 | ((file-exists-p "/usr/local/bin/m4") "/usr/local/bin/m4") |
| 51 | ((file-exists-p "/usr/bin/m4") "/usr/bin/m4") |
| 52 | ((file-exists-p "/bin/m4") "/bin/m4") |
| 53 | ((file-exists-p "/usr/ccs/bin/m4") "/usr/ccs/bin/m4") |
| 54 | ( t "m4") |
| 55 | ) |
| 56 | "File name of the m4 executable." |
| 57 | :type 'file |
| 58 | :group 'm4) |
| 59 | |
| 60 | ;;options to m4 |
| 61 | (defcustom m4-program-options nil |
| 62 | "Options to pass to `m4-program'." |
| 63 | :type '(repeat string) |
| 64 | :group 'm4) |
| 65 | |
| 66 | ;;to use --prefix-builtins, you can use |
| 67 | ;;(defconst m4-program-options '("-P")) |
| 68 | ;;or |
| 69 | ;;(defconst m4-program-options '("--prefix-builtins")) |
| 70 | |
| 71 | (defvar m4-font-lock-keywords |
| 72 | `( |
| 73 | ("\\(\\b\\(m4_\\)?dnl\\b\\|^\\#\\).*$" . font-lock-comment-face) |
| 74 | ; ("\\(\\bdnl\\b\\|\\bm4_dnl\\b\\|^\\#\\).*$" . font-lock-comment-face) |
| 75 | ("\\$[*#@0-9]" . font-lock-variable-name-face) |
| 76 | ("\\\$\\\@" . font-lock-variable-name-face) |
| 77 | ("\\\$\\\*" . font-lock-variable-name-face) |
| 78 | ("\\b\\(builtin\\|change\\(com\\|quote\\|word\\)\\|d\\(e\\(bug\\(file\\|mode\\)\\|cr\\|f\\(ine\\|n\\)\\)\\|iv\\(ert\\|num\\)\\|nl\\|umpdef\\)\\|e\\(rrprint\\|syscmd\\|val\\)\\|f\\(ile\\|ormat\\)\\|gnu\\|i\\(f\\(def\\|else\\)\\|n\\(c\\(lude\\|r\\)\\|d\\(ex\\|ir\\)\\)\\)\\|l\\(en\\|ine\\)\\|m\\(4\\(exit\\|wrap\\)\\|aketemp\\)\\|p\\(atsubst\\|opdef\\|ushdef\\)\\|regexp\\|s\\(hift\\|include\\|ubstr\\|ys\\(cmd\\|val\\)\\)\\|tra\\(ceo\\(ff\\|n\\)\\|nslit\\)\\|un\\(d\\(efine\\|ivert\\)\\|ix\\)\\)\\b" . font-lock-keyword-face) |
| 79 | ("\\b\\(m4_\\(builtin\\|change\\(com\\|quote\\|word\\)\\|d\\(e\\(bug\\(file\\|mode\\)\\|cr\\|f\\(ine\\|n\\)\\)\\|iv\\(ert\\|num\\)\\|nl\\|umpdef\\)\\|e\\(rrprint\\|syscmd\\|val\\)\\|f\\(ile\\|ormat\\)\\|i\\(f\\(def\\|else\\)\\|n\\(c\\(lude\\|r\\)\\|d\\(ex\\|ir\\)\\)\\)\\|l\\(en\\|ine\\)\\|m\\(4\\(_undefine\\|exit\\|wrap\\)\\|aketemp\\)\\|p\\(atsubst\\|opdef\\|ushdef\\)\\|regexp\\|s\\(hift\\|include\\|ubstr\\|ys\\(cmd\\|val\\)\\)\\|tra\\(ceo\\(ff\\|n\\)\\|nslit\\)\\|undivert\\)\\)\\b" . font-lock-keyword-face)) |
| 80 | "Default font-lock-keywords for `m4 mode'.") |
| 81 | |
| 82 | (defcustom m4-mode-hook nil |
| 83 | "Hook called by `m4-mode'." |
| 84 | :type 'hook |
| 85 | :group 'm4) |
| 86 | |
| 87 | ;;this may still need some work |
| 88 | (defvar m4-mode-syntax-table nil |
| 89 | "Syntax table used while in `m4-mode'.") |
| 90 | (setq m4-mode-syntax-table (make-syntax-table)) |
| 91 | (modify-syntax-entry ?` "('" m4-mode-syntax-table) |
| 92 | (modify-syntax-entry ?' ")`" m4-mode-syntax-table) |
| 93 | (modify-syntax-entry ?# "<\n" m4-mode-syntax-table) |
| 94 | (modify-syntax-entry ?\n ">#" m4-mode-syntax-table) |
| 95 | (modify-syntax-entry ?{ "_" m4-mode-syntax-table) |
| 96 | (modify-syntax-entry ?} "_" m4-mode-syntax-table) |
| 97 | (modify-syntax-entry ?* "w" m4-mode-syntax-table) |
| 98 | (modify-syntax-entry ?_ "w" m4-mode-syntax-table) |
| 99 | (modify-syntax-entry ?\" "w" m4-mode-syntax-table) |
| 100 | (modify-syntax-entry ?\" "w" m4-mode-syntax-table) |
| 101 | |
| 102 | (defvar m4-mode-map |
| 103 | (let ((map (make-sparse-keymap)) |
| 104 | (menu-map (make-sparse-keymap))) |
| 105 | (define-key map "\C-c\C-b" 'm4-m4-buffer) |
| 106 | (define-key map "\C-c\C-r" 'm4-m4-region) |
| 107 | (define-key map "\C-c\C-c" 'comment-region) |
| 108 | (define-key map [menu-bar m4-mode] (cons "M4" menu-map)) |
| 109 | (define-key menu-map [m4c] |
| 110 | '(menu-item "Comment Region" comment-region |
| 111 | :help "Comment Region")) |
| 112 | (define-key menu-map [m4b] |
| 113 | '(menu-item "M4 Buffer" m4-m4-buffer |
| 114 | :help "Send contents of the current buffer to m4")) |
| 115 | (define-key menu-map [m4r] |
| 116 | '(menu-item "M4 Region" m4-m4-region |
| 117 | :help "Send contents of the current region to m4")) |
| 118 | map)) |
| 119 | |
| 120 | (defvar m4-mode-abbrev-table nil |
| 121 | "Abbrev table used while in `m4-mode'.") |
| 122 | |
| 123 | (unless m4-mode-abbrev-table |
| 124 | (define-abbrev-table 'm4-mode-abbrev-table ())) |
| 125 | |
| 126 | (defun m4-m4-buffer () |
| 127 | "Send contents of the current buffer to m4." |
| 128 | (interactive) |
| 129 | (shell-command-on-region |
| 130 | (point-min) (point-max) |
| 131 | (mapconcat 'identity (cons m4-program m4-program-options) "\s") |
| 132 | "*m4-output*" nil) |
| 133 | (switch-to-buffer-other-window "*m4-output*")) |
| 134 | |
| 135 | (defun m4-m4-region () |
| 136 | "Send contents of the current region to m4." |
| 137 | (interactive) |
| 138 | (shell-command-on-region |
| 139 | (point) (mark) |
| 140 | (mapconcat 'identity (cons m4-program m4-program-options) "\s") |
| 141 | "*m4-output*" nil) |
| 142 | (switch-to-buffer-other-window "*m4-output*")) |
| 143 | |
| 144 | (defun m4-current-defun-name () |
| 145 | "Return the name of the M4 function at point, or nil." |
| 146 | (save-excursion |
| 147 | (if (re-search-backward |
| 148 | "^\\(\\(m4_\\)?define\\|A._DEFUN\\)(\\[?\\([A-Za-z0-9_]+\\)" nil t) |
| 149 | (match-string-no-properties 3)))) |
| 150 | |
| 151 | ;;;###autoload |
| 152 | (define-derived-mode m4-mode prog-mode "m4" |
| 153 | "A major mode to edit m4 macro files." |
| 154 | :abbrev-table m4-mode-abbrev-table |
| 155 | (setq-local comment-start "#") |
| 156 | (setq-local parse-sexp-ignore-comments t) |
| 157 | (setq-local add-log-current-defun-function #'m4-current-defun-name) |
| 158 | (setq font-lock-defaults '(m4-font-lock-keywords nil))) |
| 159 | |
| 160 | (provide 'm4-mode) |
| 161 | ;;stuff to play with for debugging |
| 162 | ;(char-to-string (char-syntax ?`)) |
| 163 | |
| 164 | ;;;how I generate the nasty looking regexps at the top |
| 165 | ;;;(make-regexp '("builtin" "changecom" "changequote" "changeword" "debugfile" |
| 166 | ;;; "debugmode" "decr" "define" "defn" "divert" "divnum" "dnl" |
| 167 | ;;; "dumpdef" "errprint" "esyscmd" "eval" "file" "format" "gnu" |
| 168 | ;;; "ifdef" "ifelse" "include" "incr" "index" "indir" "len" "line" |
| 169 | ;;; "m4exit" "m4wrap" "maketemp" "patsubst" "popdef" "pushdef" "regexp" |
| 170 | ;;; "shift" "sinclude" "substr" "syscmd" "sysval" "traceoff" "traceon" |
| 171 | ;;; "translit" "undefine" "undivert" "unix")) |
| 172 | ;;;(make-regexp '("m4_builtin" "m4_changecom" "m4_changequote" "m4_changeword" |
| 173 | ;;; "m4_debugfile" "m4_debugmode" "m4_decr" "m4_define" "m4_defn" |
| 174 | ;;; "m4_divert" "m4_divnum" "m4_dnl" "m4_dumpdef" "m4_errprint" |
| 175 | ;;; "m4_esyscmd" "m4_eval" "m4_file" "m4_format" "m4_ifdef" "m4_ifelse" |
| 176 | ;;; "m4_include" "m4_incr" "m4_index" "m4_indir" "m4_len" "m4_line" |
| 177 | ;;; "m4_m4exit" "m4_m4wrap" "m4_maketemp" "m4_patsubst" "m4_popdef" |
| 178 | ;;; "m4_pushdef" "m4_regexp" "m4_shift" "m4_sinclude" "m4_substr" |
| 179 | ;;; "m4_syscmd" "m4_sysval" "m4_traceoff" "m4_traceon" "m4_translit" |
| 180 | ;;; "m4_m4_undefine" "m4_undivert")) |
| 181 | |
| 182 | ;;; m4-mode.el ends here |