Mercurial > hg > xemacs-beta
comparison lisp/modes/postscript.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 0293115a14e9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; postscript.el --- major mode for editing PostScript programs | |
2 | |
3 ;; Keywords: langauges | |
4 | |
5 ;; This file is part of XEmacs. | |
6 | |
7 ;; XEmacs is free software; you can redistribute it and/or modify it | |
8 ;; under the terms of the GNU General Public License as published by | |
9 ;; the Free Software Foundation; either version 2, or (at your option) | |
10 ;; any later version. | |
11 | |
12 ;; XEmacs is distributed in the hope that it will be useful, but | |
13 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 ;; General Public License for more details. | |
16 | |
17 ;; You should have received a copy of the GNU General Public License | |
18 ;; along with XEmacs; see the file COPYING. If not, write to the Free | |
19 ;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | |
21 ;;; Synched up with: Not in FSF. | |
22 | |
23 ;; | |
24 ;; Author: Chris Maio | |
25 ;; Last edit: 4 Sep 1988 | |
26 ;; Includes patches from relph@presto.ig.com (John M. Relph) posted to | |
27 ;; gnu.emacs.sources on 22 Nov 90 04:53:43 GMT. | |
28 ;; | |
29 ;; The following two statements, placed in your .emacs file or site-init.el, | |
30 ;; will cause this file to be autoloaded, and postscript-mode invoked, when | |
31 ;; visiting .ps or .cps files: | |
32 ;; | |
33 ;; (autoload 'postscript-mode "postscript.el" "" t) | |
34 ;; (setq auto-mode-alist | |
35 ;; (cons '("\\.c?ps$".postscript-mode) auto-mode-alist)) | |
36 ;; | |
37 | |
38 (provide 'postscript) | |
39 | |
40 (defconst ps-indent-level 2 | |
41 "*Indentation to be used inside of PostScript blocks or arrays") | |
42 | |
43 (defconst ps-tab-width 8 | |
44 "*Tab stop width for PostScript mode") | |
45 | |
46 (defun ps-make-tabs (stop) | |
47 (and (< stop 132) (cons stop (ps-make-tabs (+ stop ps-tab-width))))) | |
48 | |
49 (defconst ps-tab-stop-list (ps-make-tabs ps-tab-width) | |
50 "*Tab stop list for PostScript mode") | |
51 | |
52 (defconst ps-postscript-command '("gs" "-") | |
53 "*Command used to invoke with a printer spooler or NeWS server.") | |
54 | |
55 (defvar ps-mode-map nil | |
56 "Keymap used in PostScript mode buffers") | |
57 | |
58 (defvar ps-mode-syntax-table nil | |
59 "PostScript mode syntax table") | |
60 | |
61 (defvar ps-balanced-string-syntax-p | |
62 (let ((b (current-buffer)) | |
63 (loser (generate-new-buffer "x"))) | |
64 (unwind-protect | |
65 (progn | |
66 (set-buffer loser) | |
67 (set-syntax-table (copy-syntax-table)) | |
68 (modify-syntax-entry ?\( "\"\)") | |
69 (insert "((") | |
70 (let ((v (parse-partial-sexp (point-min) (point-max)))) | |
71 (if (elt v 3) | |
72 ;; New syntax code think's we're still inside a string | |
73 t | |
74 nil))) | |
75 (set-buffer b) | |
76 (kill-buffer loser)))) | |
77 | |
78 (defconst postscript-font-lock-keywords (purecopy | |
79 (list | |
80 ;; Proper rule for Postscript strings | |
81 '("(\\([^)]\\|\\\\.\\|\\\\\n\\)*)" . font-lock-string-face) | |
82 ;; Make any line beginning with a / be a ``keyword'' | |
83 '("^/[^\n%]*" . font-lock-keyword-face) | |
84 ;; Make brackets of all forms be keywords | |
85 '("[][<>{}]+" . font-lock-keyword-face) | |
86 ;; Keywords | |
87 (list (concat | |
88 "[][ \t\f\n\r()<>{}/%]" ;delimiter | |
89 "\\(" | |
90 (mapconcat 'identity | |
91 '("begin" "end" | |
92 "save" "restore" "gsave" "grestore" | |
93 ;; Any delimited name ending in 'def' | |
94 "[a-zA-Z0-9-._]*def" | |
95 "[Dd]efine[a-zA-Z0-9-._]*") | |
96 "\\|") | |
97 "\\)" | |
98 "\\([][ \t\f\n\r()<>{}/%]\\|$\\)" ;delimiter | |
99 ) | |
100 1 'font-lock-keyword-face))) | |
101 "Expressions to highlight in Postscript buffers.") | |
102 (put 'postscript-mode 'font-lock-defaults '(postscript-font-lock-keywords)) | |
103 | |
104 (if ps-mode-syntax-table | |
105 nil | |
106 (let ((i 0)) | |
107 (setq ps-mode-syntax-table (copy-syntax-table nil)) | |
108 (while (< i 256) | |
109 (or (= (char-syntax i ps-mode-syntax-table) ?w) | |
110 (modify-syntax-entry i "_" ps-mode-syntax-table)) | |
111 (setq i (1+ i))) | |
112 (modify-syntax-entry ?\ " " ps-mode-syntax-table) | |
113 (modify-syntax-entry ?\t " " ps-mode-syntax-table) | |
114 (modify-syntax-entry ?\f " " ps-mode-syntax-table) | |
115 (modify-syntax-entry ?\r " " ps-mode-syntax-table) | |
116 (modify-syntax-entry ?\% "<" ps-mode-syntax-table) | |
117 (modify-syntax-entry ?\n ">" ps-mode-syntax-table) | |
118 (modify-syntax-entry ?\\ "\\" ps-mode-syntax-table) | |
119 (modify-syntax-entry ?? "_" ps-mode-syntax-table) | |
120 (modify-syntax-entry ?_ "_" ps-mode-syntax-table) | |
121 (modify-syntax-entry ?. "_" ps-mode-syntax-table) | |
122 (modify-syntax-entry ?/ "'" ps-mode-syntax-table) | |
123 (if ps-balanced-string-syntax-p | |
124 (progn | |
125 (modify-syntax-entry ?\( "\"\)" ps-mode-syntax-table) | |
126 (modify-syntax-entry ?\) "\"\(" ps-mode-syntax-table)) | |
127 (progn | |
128 ;; This isn't correct, but Emacs syntax stuff | |
129 ;; has no way to deal with string syntax which uses | |
130 ;; different open and close characters. Sigh. | |
131 (modify-syntax-entry ?\( "(" ps-mode-syntax-table) | |
132 (modify-syntax-entry ?\) ")" ps-mode-syntax-table))) | |
133 (modify-syntax-entry ?\[ "(\]" ps-mode-syntax-table) | |
134 (modify-syntax-entry ?\] ")\[" ps-mode-syntax-table) | |
135 (modify-syntax-entry ?\{ "\(\}" ps-mode-syntax-table) | |
136 (modify-syntax-entry ?\} "\)\}" ps-mode-syntax-table) | |
137 (modify-syntax-entry ?/ "' p" ps-mode-syntax-table) | |
138 )) | |
139 | |
140 | |
141 ;;;###autoload | |
142 (defun postscript-mode () | |
143 "Major mode for editing PostScript files. | |
144 | |
145 \\[ps-execute-buffer] will send the contents of the buffer to the NeWS | |
146 server using psh(1). \\[ps-execute-region] sends the current region. | |
147 \\[ps-shell] starts an interactive psh(1) window which will be used for | |
148 subsequent \\[ps-execute-buffer] or \\[ps-execute-region] commands. | |
149 | |
150 In this mode, TAB and \\[indent-region] attempt to indent code | |
151 based on the position of {}, [], and begin/end pairs. The variable | |
152 ps-indent-level controls the amount of indentation used inside | |
153 arrays and begin/end pairs. | |
154 | |
155 \\{ps-mode-map} | |
156 | |
157 \\[postscript-mode] calls the value of the variable postscript-mode-hook | |
158 with no args, if that value is non-nil." | |
159 (interactive) | |
160 (kill-all-local-variables) | |
161 (use-local-map ps-mode-map) | |
162 (set-syntax-table ps-mode-syntax-table) | |
163 (make-local-variable 'comment-start) | |
164 (setq comment-start "% ") | |
165 (make-local-variable 'comment-start-skip) | |
166 (setq comment-start-skip "%+ *") | |
167 (make-local-variable 'comment-column) | |
168 (setq comment-column 40) | |
169 (make-local-variable 'indent-line-function) | |
170 (setq indent-line-function 'ps-indent-line) | |
171 (make-local-variable 'tab-stop-list) | |
172 (setq tab-stop-list ps-tab-stop-list) | |
173 (make-local-variable 'page-delimiter) | |
174 (setq page-delimiter "^showpage") | |
175 (make-local-variable 'parse-sexp-ignore-comments) | |
176 (setq parse-sexp-ignore-comments t) | |
177 (setq mode-name "PostScript") | |
178 (setq major-mode 'postscript-mode) | |
179 (run-hooks 'ps-mode-hook) ; bad name! Kept for compatibility. | |
180 (run-hooks 'postscript-mode-hook) | |
181 ) | |
182 | |
183 (defun ps-tab () | |
184 "Command assigned to the TAB key in PostScript mode." | |
185 (interactive) | |
186 (if (save-excursion (skip-chars-backward " \t") (bolp)) | |
187 (ps-indent-line) | |
188 (save-excursion | |
189 (ps-indent-line)))) | |
190 | |
191 (defun ps-indent-line () | |
192 "Indents a line of PostScript code." | |
193 (interactive) | |
194 (beginning-of-line) | |
195 (delete-horizontal-space) | |
196 (if (not (or (looking-at "%%") ; "%%" comments stay at left margin | |
197 (ps-top-level-p))) | |
198 (if (and (< (point) (point-max)) | |
199 (eq ?\) (char-syntax (char-after (point))))) | |
200 (ps-indent-close) ; indent close-delimiter | |
201 (if (looking-at "\\(dict\\|class\\)?end\\|cdef\\|grestore\\|>>") | |
202 (ps-indent-end) ; indent end token | |
203 (ps-indent-in-block))))) ; indent line after open delimiter | |
204 | |
205 ;(defun ps-open () | |
206 ; (interactive) | |
207 ; (insert last-command-char)) | |
208 | |
209 (defun ps-insert-d-char (arg) | |
210 "Awful hack to make \"end\" and \"cdef\" keywords indent themselves." | |
211 (interactive "p") | |
212 (insert-char last-command-char arg) | |
213 (save-excursion | |
214 (beginning-of-line) | |
215 (if (looking-at "^[ \t]*\\(\\(dict\\|class\\)?end\\|cdef\\|grestore\\)") | |
216 (progn | |
217 (delete-horizontal-space) | |
218 (ps-indent-end))))) | |
219 | |
220 (defun ps-close () | |
221 "Inserts and indents a close delimiter." | |
222 (interactive) | |
223 (insert last-command-char) | |
224 (backward-char 1) | |
225 (ps-indent-close) | |
226 (forward-char 1) | |
227 (blink-matching-open)) | |
228 | |
229 (defun ps-indent-close () | |
230 "Internal function to indent a line containing a an array close delimiter." | |
231 (if (save-excursion (skip-chars-backward " \t") (bolp)) | |
232 (let (x (oldpoint (point))) | |
233 (forward-char) (backward-sexp) ;XXX | |
234 (if (and (eq 1 (count-lines (point) oldpoint)) | |
235 (> 1 (- oldpoint (point)))) | |
236 (goto-char oldpoint) | |
237 (beginning-of-line) | |
238 (skip-chars-forward " \t") | |
239 (setq x (current-column)) | |
240 (goto-char oldpoint) | |
241 (delete-horizontal-space) | |
242 (indent-to x))))) | |
243 | |
244 (defun ps-indent-end () | |
245 "Indent an \"end\" token or array close delimiter." | |
246 (let ((goal (ps-block-start))) | |
247 (if (not goal) | |
248 (indent-relative) | |
249 (setq goal (save-excursion | |
250 (goto-char goal) (back-to-indentation) (current-column))) | |
251 (indent-to goal)))) | |
252 | |
253 (defun ps-indent-in-block () | |
254 "Indent a line which does not open or close a block." | |
255 (let ((goal (ps-block-start))) | |
256 (setq goal (save-excursion | |
257 (goto-char goal) | |
258 (back-to-indentation) | |
259 (if (bolp) | |
260 ps-indent-level | |
261 (back-to-indentation) | |
262 (+ (current-column) ps-indent-level)))) | |
263 (indent-to goal))) | |
264 | |
265 ;;; returns nil if at top-level, or char pos of beginning of current block | |
266 (defun ps-block-start () | |
267 "Returns the character position of the character following the nearest | |
268 enclosing `[' `{' or `begin' keyword." | |
269 (save-excursion | |
270 (let ((open (condition-case nil | |
271 (save-excursion | |
272 (backward-up-list 1) | |
273 (1+ (point))) | |
274 (error nil)))) | |
275 (ps-begin-end-hack open)))) | |
276 | |
277 (defun ps-begin-end-hack (start) | |
278 "Search backwards from point to START for enclosing `begin' and returns the | |
279 character number of the character following `begin' or START if not found." | |
280 (save-excursion | |
281 (let ((depth 1)) | |
282 (while (and (> depth 0) | |
283 (or (re-search-backward "^[ \t]*\\(dict\\|class\\)?\\(end\\|grestore\\|>>\\)\\|\\(begin\\|gsave\\|<<\\)[ \t]*\\(%.*\\)*$" | |
284 start t) | |
285 (re-search-backward "^[ \t]*cdef.*$" start t))) | |
286 (setq depth (if (looking-at "[ \t]*\\(dict\\|class\\)?\\(end\\|grestore\\|>>\\)") | |
287 (1+ depth) (1- depth)))) | |
288 (if (not (eq 0 depth)) | |
289 start | |
290 (forward-word 1) | |
291 (point))))) | |
292 | |
293 (defun ps-top-level-p () | |
294 "Awful test to see whether we are inside some sort of PostScript block." | |
295 (and (condition-case nil | |
296 (not (scan-lists (point) -1 1)) | |
297 (error t)) | |
298 (not (ps-begin-end-hack nil)))) | |
299 | |
300 ;;; initialize the keymap if it doesn't already exist | |
301 (if (null ps-mode-map) | |
302 (progn | |
303 (setq ps-mode-map (make-sparse-keymap)) | |
304 (set-keymap-name ps-mode-map 'ps-mode-map) | |
305 ;;(define-key ps-mode-map "d" 'ps-insert-d-char) | |
306 ;;(define-key ps-mode-map "f" 'ps-insert-d-char) | |
307 ;;(define-key ps-mode-map "{" 'ps-open) | |
308 ;;(define-key ps-mode-map "}" 'ps-close) | |
309 ;;(define-key ps-mode-map "[" 'ps-open) | |
310 ;;(define-key ps-mode-map "]" 'ps-close) | |
311 (define-key ps-mode-map "\t" 'ps-tab) | |
312 (define-key ps-mode-map "\C-c\C-c" 'ps-execute-buffer) | |
313 (define-key ps-mode-map "\C-c|" 'ps-execute-region) | |
314 ;; make up yout mind! -- the below or the above? | |
315 (define-key ps-mode-map "\C-c!" 'ps-shell) | |
316 )) | |
317 | |
318 (defun ps-execute-buffer () | |
319 "Send the contents of the buffer to a printer or NeWS server." | |
320 (interactive) | |
321 (save-excursion | |
322 (mark-whole-buffer) | |
323 (ps-execute-region (point-min) (point-max)))) | |
324 | |
325 (defun ps-execute-region (start end) | |
326 "Send the region between START and END to a printer or NeWS server. | |
327 You should kill any existing *PostScript* buffer unless you want the | |
328 PostScript text to be executed in that process." | |
329 (interactive "r") | |
330 (let ((start (min (point) (mark))) | |
331 (end (max (point) (mark)))) | |
332 (condition-case nil | |
333 (process-send-string "PostScript" (buffer-substring start end)) | |
334 (error (shell-command-on-region | |
335 start end | |
336 (mapconcat 'identity ps-postscript-command " ") | |
337 nil))))) | |
338 | |
339 (defun ps-shell () | |
340 "Start a shell communicating with a PostScript printer or NeWS server." | |
341 (interactive) | |
342 (require 'shell) | |
343 (switch-to-buffer-other-window | |
344 (apply 'make-comint | |
345 "PostScript" | |
346 (car ps-postscript-command) | |
347 nil | |
348 (cdr ps-postscript-command))) | |
349 (make-local-variable 'shell-prompt-pattern) | |
350 ; (setq shell-prompt-pattern "PS>") | |
351 (setq shell-prompt-pattern "GS>") | |
352 ; (process-send-string "PostScript" "executive\n") | |
353 ) |