Commit | Line | Data |
---|---|---|
400a3178 AM |
1 | ;;; dos.el --- Major mode for editing Dos scripts |
2 | ||
3 | ;; Copyright (C) 2003, 2008-2013 Free Software Foundation, Inc. | |
4 | ||
5 | ;; Author: Arni Magnusson <arnima@hafro.is> | |
6 | ;; Keywords: languages | |
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 3 of the License, or | |
13 | ;; (at your option) 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. If not, see <http://www.gnu.org/licenses/>. | |
22 | ||
23 | ;;; Commentary: | |
24 | ;; | |
25 | ;; Major mode for editing Dos scripts (batch files). Provides syntax | |
26 | ;; highlighting, a basic template, access to Dos help pages, imenu/outline | |
27 | ;; navigation, and the ability to run scripts from within Emacs. The syntax | |
28 | ;; groups for highlighting are: | |
29 | ;; | |
30 | ;; Face Example | |
31 | ;; dos-label-face :LABEL | |
32 | ;; font-lock-comment-face rem | |
33 | ;; font-lock-builtin-face copy | |
34 | ;; font-lock-keyword-face goto | |
35 | ;; font-lock-warning-face cp | |
36 | ;; font-lock-constant-face [call] prog | |
37 | ;; font-lock-variable-name-face %var% | |
38 | ;; font-lock-type-face -option | |
39 | ;; | |
40 | ;; Usage: | |
41 | ;; | |
42 | ;; See documentation of function `dos-mode'. | |
43 | ;; | |
44 | ;; Separate package `dos-indent' (Matthew Fidler) provides rudimentary | |
45 | ;; indentation, see http://www.emacswiki.org/emacs/dos-indent.el. | |
46 | ;; | |
47 | ;; Acknowledgements: | |
48 | ;; | |
49 | ;; Inspired by `batch-mode' (Agnar Renolen) and `cmd-mode' (Tadamegu Furukawa). | |
50 | ||
51 | ;;; Code: | |
52 | ||
53 | ;; 1 Preamble | |
54 | ||
55 | (defgroup dos nil | |
56 | "Major mode for editing Dos scripts." | |
57 | :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces) | |
58 | :group 'languages) | |
59 | ||
60 | ;; 2 User variables | |
61 | ||
62 | (defface dos-label-face '((t :weight bold)) | |
63 | "Font Lock mode face used to highlight Dos labels." | |
64 | :group 'dos) | |
65 | ||
66 | ;; 3 Internal variables | |
67 | ||
68 | (defvar dos-font-lock-keywords | |
69 | (eval-when-compile | |
70 | (let ((COMMANDS | |
71 | '("assoc" "at" "attrib" "cd" "cls" "color" "copy" "date" "del" "dir" | |
72 | "doskey" "echo" "endlocal" "erase" "fc" "find" "findstr" "format" | |
73 | "ftype" "label" "md" "mkdir" "more" "move" "net" "path" "pause" | |
74 | "popd" "prompt" "pushd" "rd" "ren" "rename" "replace" "rmdir" "set" | |
75 | "setlocal" "shift" "sort" "subst" "time" "title" "tree" "type" | |
76 | "ver" "vol" "xcopy")) | |
77 | (CONTROLFLOW | |
78 | '("call" "cmd" "defined" "do" "else" "equ" "exist" "exit" "for" "geq" | |
79 | "goto" "gtr" "if" "in" "leq" "lss" "neq" "not" "start")) | |
80 | (LINUX | |
81 | '("cat" "cp" "ls" "mv" "rm"))) | |
82 | (list | |
83 | '("\\<\\(call\\|goto\\)\\>[ \t]+%?\\([A-Za-z0-9-_\\:.]+\\)%?" | |
84 | (2 font-lock-constant-face t)) | |
85 | '("^[ \t]*\\(@?rem\\>\\|::\\).*" | |
86 | (0 font-lock-comment-face t)) | |
87 | '("^:[^:].*" | |
88 | . 'dos-label-face) | |
89 | '("\\<\\(defined\\|set\\)\\>[ \t]*\\(\\w+\\)" | |
90 | (2 font-lock-variable-name-face)) | |
91 | '("%\\(\\w+\\)%?" | |
92 | (1 font-lock-variable-name-face)) | |
93 | '("!\\(\\w+\\)!?" ; delayed-expansion !variable! | |
94 | (1 font-lock-variable-name-face)) | |
95 | '("[ =][-/]+\\(\\w+\\)" | |
96 | (1 font-lock-type-face append)) | |
97 | (cons (regexp-opt COMMANDS 'words) font-lock-builtin-face) | |
98 | (cons (regexp-opt CONTROLFLOW 'words) font-lock-keyword-face) | |
99 | (cons (regexp-opt LINUX 'words) font-lock-warning-face))))) | |
100 | ||
101 | (defvar dos-menu | |
102 | '("Dos" | |
103 | ["Run" dos-run :help "Run script"] | |
104 | ["Run with Args" dos-run-args :help "Run script with args"] | |
105 | "--" | |
106 | ["Imenu" imenu :help "Navigate with imenu"] | |
107 | "--" | |
108 | ["Template" dos-template :help "Insert template"] | |
109 | "--" | |
110 | ["Help (Command)" dos-cmd-help :help "Show help page for Dos command"] | |
111 | ["Help (Mode)" dos-mode-help :help "Show help page for Emacs Dos Mode"])) | |
112 | ||
113 | (defvar dos-mode-map | |
114 | (let ((map (make-sparse-keymap))) | |
115 | (easy-menu-define nil map nil dos-menu) | |
116 | (define-key map [?\C-c ?\C-.] 'dos-mode-help) | |
117 | (define-key map [?\C-c ?\C-/] 'dos-cmd-help) | |
118 | (define-key map [?\C-c ?\C-a] 'dos-run-args) | |
119 | (define-key map [?\C-c ?\C-c] 'dos-run) | |
120 | (define-key map [?\C-c ?\C-t] 'dos-template) | |
121 | (define-key map [?\C-c ?\C-v] 'dos-run) | |
122 | map)) | |
123 | ||
124 | (defvar dos-mode-syntax-table | |
125 | (let ((table (make-syntax-table))) | |
126 | (modify-syntax-entry ?~ "w" table) | |
127 | (modify-syntax-entry ?% "." table) | |
128 | (modify-syntax-entry ?- "w" table) | |
129 | (modify-syntax-entry ?_ "w" table) | |
130 | (modify-syntax-entry ?{ "w" table) | |
131 | (modify-syntax-entry ?} "w" table) | |
132 | (modify-syntax-entry ?\\ "." table) | |
133 | table)) | |
134 | ||
135 | ;; 4 User functions | |
136 | ||
137 | (defun dos-cmd-help (cmd) | |
138 | "Show help for Dos command." | |
139 | (interactive "sHelp: ") | |
140 | (if (string-equal cmd "net") | |
141 | (shell-command "net /?") (shell-command (concat "help " cmd)))) | |
142 | ||
143 | (defun dos-mode-help () | |
144 | "Show help page for `dos-mode'." | |
145 | (interactive) | |
146 | (describe-function 'dos-mode) | |
147 | (switch-to-buffer "*Help*") (delete-other-windows) (message nil)) | |
148 | ||
149 | (defun dos-run () | |
150 | "Run Dos script." | |
151 | (interactive) | |
152 | (save-buffer) (shell-command buffer-file-name)) | |
153 | ||
154 | (defun dos-run-args (args) | |
155 | "Run Dos script with ARGS." | |
156 | (interactive "sArgs: ") | |
157 | (shell-command (concat buffer-file-name " " args))) | |
158 | ||
159 | (defun dos-template () | |
160 | "Insert minimal Dos template." | |
161 | (interactive) | |
162 | (goto-char (point-min)) (insert "@echo off\nsetlocal\n\n")) | |
163 | ||
164 | ;; 5 Main function | |
165 | ||
166 | ;;;###autoload | |
167 | (define-derived-mode dos-mode prog-mode "Dos" | |
168 | "Major mode for editing Dos scripts.\n | |
169 | The `dos-mode-help' command shows this page.\n | |
170 | Start a new script from `dos-template'. Read help pages for Dos commands with | |
171 | `dos-cmd-help'. Navigate between sections using `imenu'. Run script using | |
172 | `dos-run' and `dos-run-args'.\n | |
173 | \\{dos-mode-map}" | |
174 | (set (make-local-variable 'comment-start) "rem") | |
175 | (set (make-local-variable 'font-lock-defaults) | |
176 | '(dos-font-lock-keywords nil t)) ; case-insensitive keywords | |
177 | (set (make-local-variable 'imenu-generic-expression) '((nil "^:[^:].*" 0))) | |
178 | (set (make-local-variable 'outline-regexp) ":[^:]") | |
179 | (set-syntax-table dos-mode-syntax-table)) | |
180 | ||
181 | (provide 'dos) | |
182 | ||
183 | ;;; dos.el ends here |