Commit | Line | Data |
463ee0b2 |
1 | Article 15212 of comp.lang.perl: |
2 | Path: netlabs!news.cerf.net!usc!howland.reston.ans.net!spool.mu.edu!umn.edu!news-feed-2.peachnet.edu!concert!duke!khera |
3 | From: khera@cs.duke.edu (Vivek Khera) |
4 | Newsgroups: comp.lang.perl |
5 | Subject: cperl-mode.el |
6 | Message-ID: <KHERA.93Oct21140851@thneed.cs.duke.edu> |
7 | Date: 21 Oct 93 18:08:51 GMT |
8 | Sender: news@duke.cs.duke.edu |
9 | Organization: Duke University CS Dept., Durham, NC |
10 | Lines: 694 |
11 | Nntp-Posting-Host: thneed.cs.duke.edu |
12 | X-Md4-Signature: 40dd9bccfb99794a9da2ee891b5bf557 |
13 | X-Md5-Signature: e4baa8cf00c94092ebf9712514e4696b |
14 | |
15 | Since I've received requests to do so, I'm posting the cperl-mode.el |
16 | file. This allows Emacs (both version 18 and 19) to do nice things |
17 | when editing Perl code. Indentation works well, and it doesn't get |
18 | confused like the perl-mode.el that comes with Emacs 19. |
19 | |
20 | Install this file as cperl-mode.el, and add the following to your |
21 | .emacs file: |
22 | |
23 | (autoload 'perl-mode "cperl-mode" "alternate mode for editing Perl programs" t) |
24 | |
25 | This cperl-mode.el is not exactly the same as when it was originally |
26 | posted here. I made the following changes: perl-mode is an alias for |
27 | cperl-mode, and the major mode name is perl-mode, not cperl-mode. |
28 | This is so it is easier to use with Emacs 19. I suppose one could |
29 | install this as perl-mode.el and then not have to put the autoload |
30 | line in (for Emacs 19). |
31 | |
32 | Anyway, I'm not maintaining this, so don't send me bugs. |
33 | |
34 | --cut here-- |
35 | ;;; From: olson@mcs.anl.gov (Bob Olson) |
36 | ;;; Newsgroups: comp.lang.perl |
37 | ;;; Subject: cperl-mode: Another perl mode for Gnuemacs |
38 | ;;; Date: 14 Aug 91 15:20:01 GMT |
39 | |
40 | ;; Perl code editing commands for Emacs |
41 | ;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc. |
42 | |
43 | ;; This file is part of GNU Emacs. |
44 | |
45 | ;; GNU Emacs is distributed in the hope that it will be useful, |
46 | ;; but WITHOUT ANY WARRANTY. No author or distributor |
47 | ;; accepts responsibility to anyone for the consequences of using it |
48 | ;; or for whether it serves any particular purpose or works at all, |
49 | ;; unless he says so in writing. Refer to the GNU Emacs General Public |
50 | ;; License for full details. |
51 | |
52 | ;; Everyone is granted permission to copy, modify and redistribute |
53 | ;; GNU Emacs, but only under the conditions described in the |
54 | ;; GNU Emacs General Public License. A copy of this license is |
55 | ;; supposed to have been given to you along with GNU Emacs so you |
56 | ;; can know your rights and responsibilities. It should be in a |
57 | ;; file named COPYING. Among other things, the copyright notice |
58 | ;; and this notice must be preserved on all copies. |
59 | |
60 | |
61 | (defvar cperl-mode-abbrev-table nil |
62 | "Abbrev table in use in Cperl-mode buffers.") |
63 | (define-abbrev-table 'cperl-mode-abbrev-table ()) |
64 | |
65 | (defvar cperl-mode-map () |
66 | "Keymap used in C mode.") |
67 | (if cperl-mode-map |
68 | () |
69 | (setq cperl-mode-map (make-sparse-keymap)) |
70 | (define-key cperl-mode-map "{" 'electric-cperl-brace) |
71 | (define-key cperl-mode-map "}" 'electric-cperl-brace) |
72 | (define-key cperl-mode-map ";" 'electric-cperl-semi) |
73 | (define-key cperl-mode-map ":" 'electric-cperl-terminator) |
74 | (define-key cperl-mode-map "\e\C-h" 'mark-cperl-function) |
75 | (define-key cperl-mode-map "\e\C-q" 'indent-cperl-exp) |
76 | (define-key cperl-mode-map "\177" 'backward-delete-char-untabify) |
77 | (define-key cperl-mode-map "\t" 'cperl-indent-command)) |
78 | |
79 | (autoload 'cperl-macro-expand "cmacexp" |
80 | "Display the result of expanding all C macros occurring in the region. |
81 | The expansion is entirely correct because it uses the C preprocessor." |
82 | t) |
83 | |
84 | (defvar cperl-mode-syntax-table nil |
85 | "Syntax table in use in Cperl-mode buffers.") |
86 | |
87 | (if cperl-mode-syntax-table |
88 | () |
89 | (setq cperl-mode-syntax-table (make-syntax-table)) |
90 | (modify-syntax-entry ?\\ "\\" cperl-mode-syntax-table) |
91 | (modify-syntax-entry ?/ ". 14" cperl-mode-syntax-table) |
92 | (modify-syntax-entry ?* ". 23" cperl-mode-syntax-table) |
93 | (modify-syntax-entry ?+ "." cperl-mode-syntax-table) |
94 | (modify-syntax-entry ?- "." cperl-mode-syntax-table) |
95 | (modify-syntax-entry ?= "." cperl-mode-syntax-table) |
96 | (modify-syntax-entry ?% "." cperl-mode-syntax-table) |
97 | (modify-syntax-entry ?< "." cperl-mode-syntax-table) |
98 | (modify-syntax-entry ?> "." cperl-mode-syntax-table) |
99 | (modify-syntax-entry ?& "." cperl-mode-syntax-table) |
100 | (modify-syntax-entry ?| "." cperl-mode-syntax-table)) |
101 | |
102 | |
103 | (defvar cperl-indent-level 2 |
104 | "*Indentation of C statements with respect to containing block.") |
105 | (defvar cperl-brace-imaginary-offset 0 |
106 | "*Imagined indentation of a C open brace that actually follows a statement.") |
107 | (defvar cperl-brace-offset 0 |
108 | "*Extra indentation for braces, compared with other text in same context.") |
109 | (defvar cperl-argdecl-indent 5 |
110 | "*Indentation level of declarations of C function arguments.") |
111 | (defvar cperl-label-offset -2 |
112 | "*Offset of C label lines and case statements relative to usual indentation.") |
113 | (defvar cperl-continued-statement-offset 2 |
114 | "*Extra indent for lines not starting new statements.") |
115 | (defvar cperl-continued-brace-offset 0 |
116 | "*Extra indent for substatements that start with open-braces. |
117 | This is in addition to cperl-continued-statement-offset.") |
118 | |
119 | (defvar cperl-auto-newline nil |
120 | "*Non-nil means automatically newline before and after braces, |
121 | and after colons and semicolons, inserted in C code.") |
122 | |
123 | (defvar cperl-tab-always-indent t |
124 | "*Non-nil means TAB in C mode should always reindent the current line, |
125 | regardless of where in the line point is when the TAB command is used.") |
126 | \f |
127 | ;; provide an alias for working with emacs 19. the perl-mode that comes |
128 | ;; with it is really bad, and this lets us seamlessly replace it. |
129 | (fset 'perl-mode 'cperl-mode) |
130 | (defun cperl-mode () |
131 | "Major mode for editing C code. |
132 | Expression and list commands understand all C brackets. |
133 | Tab indents for C code. |
134 | Comments are delimited with /* ... */. |
135 | Paragraphs are separated by blank lines only. |
136 | Delete converts tabs to spaces as it moves back. |
137 | \\{cperl-mode-map} |
138 | Variables controlling indentation style: |
139 | cperl-tab-always-indent |
140 | Non-nil means TAB in C mode should always reindent the current line, |
141 | regardless of where in the line point is when the TAB command is used. |
142 | cperl-auto-newline |
143 | Non-nil means automatically newline before and after braces, |
144 | and after colons and semicolons, inserted in C code. |
145 | cperl-indent-level |
146 | Indentation of C statements within surrounding block. |
147 | The surrounding block's indentation is the indentation |
148 | of the line on which the open-brace appears. |
149 | cperl-continued-statement-offset |
150 | Extra indentation given to a substatement, such as the |
151 | then-clause of an if or body of a while. |
152 | cperl-continued-brace-offset |
153 | Extra indentation given to a brace that starts a substatement. |
154 | This is in addition to cperl-continued-statement-offset. |
155 | cperl-brace-offset |
156 | Extra indentation for line if it starts with an open brace. |
157 | cperl-brace-imaginary-offset |
158 | An open brace following other text is treated as if it were |
159 | this far to the right of the start of its line. |
160 | cperl-argdecl-indent |
161 | Indentation level of declarations of C function arguments. |
162 | cperl-label-offset |
163 | Extra indentation for line that is a label, or case or default. |
164 | |
165 | Settings for K&R and BSD indentation styles are |
166 | cperl-indent-level 5 8 |
167 | cperl-continued-statement-offset 5 8 |
168 | cperl-brace-offset -5 -8 |
169 | cperl-argdecl-indent 0 8 |
170 | cperl-label-offset -5 -8 |
171 | |
172 | Turning on C mode calls the value of the variable cperl-mode-hook with no args, |
173 | if that value is non-nil." |
174 | (interactive) |
175 | (kill-all-local-variables) |
176 | (use-local-map cperl-mode-map) |
177 | (setq major-mode 'perl-mode) |
178 | (setq mode-name "CPerl") |
179 | (setq local-abbrev-table cperl-mode-abbrev-table) |
180 | (set-syntax-table cperl-mode-syntax-table) |
181 | (make-local-variable 'paragraph-start) |
182 | (setq paragraph-start (concat "^$\\|" page-delimiter)) |
183 | (make-local-variable 'paragraph-separate) |
184 | (setq paragraph-separate paragraph-start) |
185 | (make-local-variable 'paragraph-ignore-fill-prefix) |
186 | (setq paragraph-ignore-fill-prefix t) |
187 | (make-local-variable 'indent-line-function) |
188 | (setq indent-line-function 'cperl-indent-line) |
189 | (make-local-variable 'require-final-newline) |
190 | (setq require-final-newline t) |
191 | (make-local-variable 'comment-start) |
192 | (setq comment-start "# ") |
193 | (make-local-variable 'comment-end) |
194 | (setq comment-end "") |
195 | (make-local-variable 'comment-column) |
196 | (setq comment-column 32) |
197 | (make-local-variable 'comment-start-skip) |
198 | (setq comment-start-skip "# *") |
199 | (make-local-variable 'comment-indent-hook) |
200 | (setq comment-indent-hook 'cperl-comment-indent) |
201 | (make-local-variable 'parse-sexp-ignore-comments) |
202 | (setq parse-sexp-ignore-comments t) |
203 | (run-hooks 'cperl-mode-hook)) |
204 | \f |
205 | ;; This is used by indent-for-comment |
206 | ;; to decide how much to indent a comment in C code |
207 | ;; based on its context. |
208 | (defun cperl-comment-indent () |
209 | (if (looking-at "^#") |
210 | 0 ;Existing comment at bol stays there. |
211 | (save-excursion |
212 | (skip-chars-backward " \t") |
213 | (max (1+ (current-column)) ;Else indent at comment column |
214 | comment-column)))) ; except leave at least one space. |
215 | |
216 | (defun electric-cperl-brace (arg) |
217 | "Insert character and correct line's indentation." |
218 | (interactive "P") |
219 | (let (insertpos) |
220 | (if (and (not arg) |
221 | (eolp) |
222 | (or (save-excursion |
223 | (skip-chars-backward " \t") |
224 | (bolp)) |
225 | (if cperl-auto-newline (progn (cperl-indent-line) (newline) t) nil))) |
226 | (progn |
227 | (insert last-command-char) |
228 | (cperl-indent-line) |
229 | (if cperl-auto-newline |
230 | (progn |
231 | (newline) |
232 | ;; (newline) may have done auto-fill |
233 | (setq insertpos (- (point) 2)) |
234 | (cperl-indent-line))) |
235 | (save-excursion |
236 | (if insertpos (goto-char (1+ insertpos))) |
237 | (delete-char -1)))) |
238 | (if insertpos |
239 | (save-excursion |
240 | (goto-char insertpos) |
241 | (self-insert-command (prefix-numeric-value arg))) |
242 | (self-insert-command (prefix-numeric-value arg))))) |
243 | |
244 | (defun electric-cperl-semi (arg) |
245 | "Insert character and correct line's indentation." |
246 | (interactive "P") |
247 | (if cperl-auto-newline |
248 | (electric-cperl-terminator arg) |
249 | (self-insert-command (prefix-numeric-value arg)))) |
250 | |
251 | (defun electric-cperl-terminator (arg) |
252 | "Insert character and correct line's indentation." |
253 | (interactive "P") |
254 | (let (insertpos (end (point))) |
255 | (if (and (not arg) (eolp) |
256 | (not (save-excursion |
257 | (beginning-of-line) |
258 | (skip-chars-forward " \t") |
259 | (or (= (following-char) ?#) |
260 | ;; Colon is special only after a label, or case .... |
261 | ;; So quickly rule out most other uses of colon |
262 | ;; and do no indentation for them. |
263 | (and (eq last-command-char ?:) |
264 | (not (looking-at "case[ \t]")) |
265 | (save-excursion |
266 | (forward-word 1) |
267 | (skip-chars-forward " \t") |
268 | (< (point) end))) |
269 | (progn |
270 | (beginning-of-defun) |
271 | (let ((pps (parse-partial-sexp (point) end))) |
272 | (or (nth 3 pps) (nth 4 pps) (nth 5 pps)))))))) |
273 | (progn |
274 | (insert last-command-char) |
275 | (cperl-indent-line) |
276 | (and cperl-auto-newline |
277 | (not (cperl-inside-parens-p)) |
278 | (progn |
279 | (newline) |
280 | (setq insertpos (- (point) 2)) |
281 | (cperl-indent-line))) |
282 | (save-excursion |
283 | (if insertpos (goto-char (1+ insertpos))) |
284 | (delete-char -1)))) |
285 | (if insertpos |
286 | (save-excursion |
287 | (goto-char insertpos) |
288 | (self-insert-command (prefix-numeric-value arg))) |
289 | (self-insert-command (prefix-numeric-value arg))))) |
290 | |
291 | (defun cperl-inside-parens-p () |
292 | (condition-case () |
293 | (save-excursion |
294 | (save-restriction |
295 | (narrow-to-region (point) |
296 | (progn (beginning-of-defun) (point))) |
297 | (goto-char (point-max)) |
298 | (= (char-after (or (scan-lists (point) -1 1) (point-min))) ?\())) |
299 | (error nil))) |
300 | \f |
301 | (defun cperl-indent-command (&optional whole-exp) |
302 | (interactive "P") |
303 | "Indent current line as C code, or in some cases insert a tab character. |
304 | If cperl-tab-always-indent is non-nil (the default), always indent current line. |
305 | Otherwise, indent the current line only if point is at the left margin |
306 | or in the line's indentation; otherwise insert a tab. |
307 | |
308 | A numeric argument, regardless of its value, |
309 | means indent rigidly all the lines of the expression starting after point |
310 | so that this line becomes properly indented. |
311 | The relative indentation among the lines of the expression are preserved." |
312 | (if whole-exp |
313 | ;; If arg, always indent this line as C |
314 | ;; and shift remaining lines of expression the same amount. |
315 | (let ((shift-amt (cperl-indent-line)) |
316 | beg end) |
317 | (save-excursion |
318 | (if cperl-tab-always-indent |
319 | (beginning-of-line)) |
320 | (setq beg (point)) |
321 | (forward-sexp 1) |
322 | (setq end (point)) |
323 | (goto-char beg) |
324 | (forward-line 1) |
325 | (setq beg (point))) |
326 | (if (> end beg) |
327 | (indent-code-rigidly beg end shift-amt "#"))) |
328 | (if (and (not cperl-tab-always-indent) |
329 | (save-excursion |
330 | (skip-chars-backward " \t") |
331 | (not (bolp)))) |
332 | (insert-tab) |
333 | (cperl-indent-line)))) |
334 | |
335 | (defun cperl-indent-line () |
336 | "Indent current line as C code. |
337 | Return the amount the indentation changed by." |
338 | (let ((indent (calculate-cperl-indent nil)) |
339 | beg shift-amt |
340 | (case-fold-search nil) |
341 | (pos (- (point-max) (point)))) |
342 | (beginning-of-line) |
343 | (setq beg (point)) |
344 | (cond ((eq indent nil) |
345 | (setq indent (current-indentation))) |
346 | ((eq indent t) |
347 | (setq indent (calculate-cperl-indent-within-comment))) |
348 | ((looking-at "[ \t]*#") |
349 | (setq indent 0)) |
350 | (t |
351 | (skip-chars-forward " \t") |
352 | (if (listp indent) (setq indent (car indent))) |
353 | (cond ((or (looking-at "case[ \t]") |
354 | (and (looking-at "[A-Za-z]") |
355 | (save-excursion |
356 | (forward-sexp 1) |
357 | (looking-at ":")))) |
358 | (setq indent (max 1 (+ indent cperl-label-offset)))) |
359 | ((and (looking-at "else\\b") |
360 | (not (looking-at "else\\s_"))) |
361 | (setq indent (save-excursion |
362 | (cperl-backward-to-start-of-if) |
363 | (current-indentation)))) |
364 | ((= (following-char) ?}) |
365 | (setq indent (- indent cperl-indent-level))) |
366 | ((= (following-char) ?{) |
367 | (setq indent (+ indent cperl-brace-offset)))))) |
368 | (skip-chars-forward " \t") |
369 | (setq shift-amt (- indent (current-column))) |
370 | (if (zerop shift-amt) |
371 | (if (> (- (point-max) pos) (point)) |
372 | (goto-char (- (point-max) pos))) |
373 | (delete-region beg (point)) |
374 | (indent-to indent) |
375 | ;; If initial point was within line's indentation, |
376 | ;; position after the indentation. Else stay at same point in text. |
377 | (if (> (- (point-max) pos) (point)) |
378 | (goto-char (- (point-max) pos)))) |
379 | shift-amt)) |
380 | |
381 | (defun calculate-cperl-indent (&optional parse-start) |
382 | "Return appropriate indentation for current line as C code. |
383 | In usual case returns an integer: the column to indent to. |
384 | Returns nil if line starts inside a string, t if in a comment." |
385 | (save-excursion |
386 | (beginning-of-line) |
387 | (let ((indent-point (point)) |
388 | (case-fold-search nil) |
389 | state |
390 | containing-sexp) |
391 | (if parse-start |
392 | (goto-char parse-start) |
393 | (beginning-of-defun)) |
394 | (while (< (point) indent-point) |
395 | (setq parse-start (point)) |
396 | (setq state (parse-partial-sexp (point) indent-point 0)) |
397 | (setq containing-sexp (car (cdr state)))) |
398 | (cond ((or (nth 3 state) (nth 4 state)) |
399 | ;; return nil or t if should not change this line |
400 | (nth 4 state)) |
401 | ((null containing-sexp) |
402 | ;; Line is at top level. May be data or function definition, |
403 | ;; or may be function argument declaration. |
404 | ;; Indent like the previous top level line |
405 | ;; unless that ends in a closeparen without semicolon, |
406 | ;; in which case this line is the first argument decl. |
407 | (goto-char indent-point) |
408 | (skip-chars-forward " \t") |
409 | (if (= (following-char) ?{) |
410 | 0 ; Unless it starts a function body |
411 | (cperl-backward-to-noncomment (or parse-start (point-min))) |
412 | ;; Look at previous line that's at column 0 |
413 | ;; to determine whether we are in top-level decls |
414 | ;; or function's arg decls. Set basic-indent accordinglu. |
415 | (let ((basic-indent |
416 | (save-excursion |
417 | (re-search-backward "^[^ \^L\t\n#]" nil 'move) |
418 | (if (and (looking-at "\\sw\\|\\s_") |
419 | (looking-at ".*(") |
420 | (progn |
421 | (goto-char (1- (match-end 0))) |
422 | (forward-sexp 1) |
423 | (and (< (point) indent-point) |
424 | (not (memq (following-char) |
425 | '(?\, ?\;)))))) |
426 | cperl-argdecl-indent 0)))) |
427 | ;; Now add a little if this is a continuation line. |
428 | (+ basic-indent (if (or (bobp) |
429 | (memq (preceding-char) '(?\) ?\; ?\}))) |
430 | 0 cperl-continued-statement-offset))))) |
431 | ((/= (char-after containing-sexp) ?{) |
432 | ;; line is expression, not statement: |
433 | ;; indent to just after the surrounding open. |
434 | (goto-char (1+ containing-sexp)) |
435 | (current-column)) |
436 | (t |
437 | ;; Statement level. Is it a continuation or a new statement? |
438 | ;; Find previous non-comment character. |
439 | (goto-char indent-point) |
440 | (cperl-backward-to-noncomment containing-sexp) |
441 | ;; Back up over label lines, since they don't |
442 | ;; affect whether our line is a continuation. |
443 | (while (or (eq (preceding-char) ?\,) |
444 | (and (eq (preceding-char) ?:) |
445 | (or (eq (char-after (- (point) 2)) ?\') |
446 | (memq (char-syntax (char-after (- (point) 2))) |
447 | '(?w ?_))))) |
448 | (if (eq (preceding-char) ?\,) |
449 | (cperl-backward-to-start-of-continued-exp containing-sexp)) |
450 | (beginning-of-line) |
451 | (cperl-backward-to-noncomment containing-sexp)) |
452 | ;; Now we get the answer. |
453 | (if (not (memq (preceding-char) '(nil ?\, ?\; ?\} ?\{))) |
454 | ;; This line is continuation of preceding line's statement; |
455 | ;; indent cperl-continued-statement-offset more than the |
456 | ;; previous line of the statement. |
457 | (progn |
458 | (cperl-backward-to-start-of-continued-exp containing-sexp) |
459 | (+ cperl-continued-statement-offset (current-column) |
460 | (if (save-excursion (goto-char indent-point) |
461 | (skip-chars-forward " \t") |
462 | (eq (following-char) ?{)) |
463 | cperl-continued-brace-offset 0))) |
464 | ;; This line starts a new statement. |
465 | ;; Position following last unclosed open. |
466 | (goto-char containing-sexp) |
467 | ;; Is line first statement after an open-brace? |
468 | (or |
469 | ;; If no, find that first statement and indent like it. |
470 | (save-excursion |
471 | (forward-char 1) |
472 | (let ((colon-line-end 0)) |
473 | (while (progn (skip-chars-forward " \t\n") |
474 | (looking-at "#\\|/\\*\\|case[ \t\n].*:\\|[a-zA-Z0-9_$]*:")) |
475 | ;; Skip over comments and labels following openbrace. |
476 | (cond ((= (following-char) ?\#) |
477 | (forward-line 1)) |
478 | ((= (following-char) ?\/) |
479 | (forward-char 2) |
480 | (search-forward "*/" nil 'move)) |
481 | ;; case or label: |
482 | (t |
483 | (save-excursion (end-of-line) |
484 | (setq colon-line-end (point))) |
485 | (search-forward ":")))) |
486 | ;; The first following code counts |
487 | ;; if it is before the line we want to indent. |
488 | (and (< (point) indent-point) |
489 | (if (> colon-line-end (point)) |
490 | (- (current-indentation) cperl-label-offset) |
491 | (current-column))))) |
492 | ;; If no previous statement, |
493 | ;; indent it relative to line brace is on. |
494 | ;; For open brace in column zero, don't let statement |
495 | ;; start there too. If cperl-indent-level is zero, |
496 | ;; use cperl-brace-offset + cperl-continued-statement-offset instead. |
497 | ;; For open-braces not the first thing in a line, |
498 | ;; add in cperl-brace-imaginary-offset. |
499 | (+ (if (and (bolp) (zerop cperl-indent-level)) |
500 | (+ cperl-brace-offset cperl-continued-statement-offset) |
501 | cperl-indent-level) |
502 | ;; Move back over whitespace before the openbrace. |
503 | ;; If openbrace is not first nonwhite thing on the line, |
504 | ;; add the cperl-brace-imaginary-offset. |
505 | (progn (skip-chars-backward " \t") |
506 | (if (bolp) 0 cperl-brace-imaginary-offset)) |
507 | ;; If the openbrace is preceded by a parenthesized exp, |
508 | ;; move to the beginning of that; |
509 | ;; possibly a different line |
510 | (progn |
511 | (if (eq (preceding-char) ?\)) |
512 | (forward-sexp -1)) |
513 | ;; Get initial indentation of the line we are on. |
514 | (current-indentation)))))))))) |
515 | |
516 | (defun calculate-cperl-indent-within-comment () |
517 | "Return the indentation amount for line, assuming that |
518 | the current line is to be regarded as part of a block comment." |
519 | (let (end star-start) |
520 | (save-excursion |
521 | (beginning-of-line) |
522 | (skip-chars-forward " \t") |
523 | (setq star-start (= (following-char) ?\*)) |
524 | (skip-chars-backward " \t\n") |
525 | (setq end (point)) |
526 | (beginning-of-line) |
527 | (skip-chars-forward " \t") |
528 | (and (re-search-forward "/\\*[ \t]*" end t) |
529 | star-start |
530 | (goto-char (1+ (match-beginning 0)))) |
531 | (current-column)))) |
532 | |
533 | |
534 | (defun cperl-backward-to-noncomment (lim) |
535 | (let (opoint stop) |
536 | (while (not stop) |
537 | (skip-chars-backward " \t\n\f" lim) |
538 | (setq opoint (point)) |
539 | (if (and (>= (point) (+ 2 lim)) |
540 | (save-excursion |
541 | (forward-char -2) |
542 | (looking-at "\\*/"))) |
543 | (search-backward "/*" lim 'move) |
544 | (beginning-of-line) |
545 | (skip-chars-forward " \t") |
546 | (setq stop (or (not (looking-at "#")) (<= (point) lim))) |
547 | (if stop (goto-char opoint) |
548 | (beginning-of-line)))))) |
549 | |
550 | (defun cperl-backward-to-start-of-continued-exp (lim) |
551 | (if (= (preceding-char) ?\)) |
552 | (forward-sexp -1)) |
553 | (beginning-of-line) |
554 | (if (<= (point) lim) |
555 | (goto-char (1+ lim))) |
556 | (skip-chars-forward " \t")) |
557 | |
558 | (defun cperl-backward-to-start-of-if (&optional limit) |
559 | "Move to the start of the last ``unbalanced'' if." |
560 | (or limit (setq limit (save-excursion (beginning-of-defun) (point)))) |
561 | (let ((if-level 1) |
562 | (case-fold-search nil)) |
563 | (while (not (zerop if-level)) |
564 | (backward-sexp 1) |
565 | (cond ((looking-at "else\\b") |
566 | (setq if-level (1+ if-level))) |
567 | ((looking-at "if\\b") |
568 | (setq if-level (1- if-level))) |
569 | ((< (point) limit) |
570 | (setq if-level 0) |
571 | (goto-char limit)))))) |
572 | |
573 | \f |
574 | (defun mark-cperl-function () |
575 | "Put mark at end of C function, point at beginning." |
576 | (interactive) |
577 | (push-mark (point)) |
578 | (end-of-defun) |
579 | (push-mark (point)) |
580 | (beginning-of-defun) |
581 | (backward-paragraph)) |
582 | \f |
583 | (defun indent-cperl-exp () |
584 | "Indent each line of the C grouping following point." |
585 | (interactive) |
586 | (let ((indent-stack (list nil)) |
587 | (contain-stack (list (point))) |
588 | (case-fold-search nil) |
589 | restart outer-loop-done inner-loop-done state ostate |
590 | this-indent last-sexp |
591 | at-else at-brace |
592 | (opoint (point)) |
593 | (next-depth 0)) |
594 | (save-excursion |
595 | (forward-sexp 1)) |
596 | (save-excursion |
597 | (setq outer-loop-done nil) |
598 | (while (and (not (eobp)) (not outer-loop-done)) |
599 | (setq last-depth next-depth) |
600 | ;; Compute how depth changes over this line |
601 | ;; plus enough other lines to get to one that |
602 | ;; does not end inside a comment or string. |
603 | ;; Meanwhile, do appropriate indentation on comment lines. |
604 | (setq innerloop-done nil) |
605 | (while (and (not innerloop-done) |
606 | (not (and (eobp) (setq outer-loop-done t)))) |
607 | (setq ostate state) |
608 | (setq state (parse-partial-sexp (point) (progn (end-of-line) (point)) |
609 | nil nil state)) |
610 | (setq next-depth (car state)) |
611 | (if (and (car (cdr (cdr state))) |
612 | (>= (car (cdr (cdr state))) 0)) |
613 | (setq last-sexp (car (cdr (cdr state))))) |
614 | (if (or (nth 4 ostate)) |
615 | (cperl-indent-line)) |
616 | (if (or (nth 3 state)) |
617 | (forward-line 1) |
618 | (setq innerloop-done t))) |
619 | (if (<= next-depth 0) |
620 | (setq outer-loop-done t)) |
621 | (if outer-loop-done |
622 | nil |
623 | ;; If this line had ..))) (((.. in it, pop out of the levels |
624 | ;; that ended anywhere in this line, even if the final depth |
625 | ;; doesn't indicate that they ended. |
626 | (while (> last-depth (nth 6 state)) |
627 | (setq indent-stack (cdr indent-stack) |
628 | contain-stack (cdr contain-stack) |
629 | last-depth (1- last-depth))) |
630 | (if (/= last-depth next-depth) |
631 | (setq last-sexp nil)) |
632 | ;; Add levels for any parens that were started in this line. |
633 | (while (< last-depth next-depth) |
634 | (setq indent-stack (cons nil indent-stack) |
635 | contain-stack (cons nil contain-stack) |
636 | last-depth (1+ last-depth))) |
637 | (if (null (car contain-stack)) |
638 | (setcar contain-stack (or (car (cdr state)) |
639 | (save-excursion (forward-sexp -1) |
640 | (point))))) |
641 | (forward-line 1) |
642 | (skip-chars-forward " \t") |
643 | (if (eolp) |
644 | nil |
645 | (if (and (car indent-stack) |
646 | (>= (car indent-stack) 0)) |
647 | ;; Line is on an existing nesting level. |
648 | ;; Lines inside parens are handled specially. |
649 | (if (/= (char-after (car contain-stack)) ?{) |
650 | (setq this-indent (car indent-stack)) |
651 | ;; Line is at statement level. |
652 | ;; Is it a new statement? Is it an else? |
653 | ;; Find last non-comment character before this line |
654 | (save-excursion |
655 | (setq at-else (looking-at "else\\W")) |
656 | (setq at-brace (= (following-char) ?{)) |
657 | (cperl-backward-to-noncomment opoint) |
658 | (if (not (memq (preceding-char) '(nil ?\, ?\; ?} ?: ?{))) |
659 | ;; Preceding line did not end in comma or semi; |
660 | ;; indent this line cperl-continued-statement-offset |
661 | ;; more than previous. |
662 | (progn |
663 | (cperl-backward-to-start-of-continued-exp (car contain-stack)) |
664 | (setq this-indent |
665 | (+ cperl-continued-statement-offset (current-column) |
666 | (if at-brace cperl-continued-brace-offset 0)))) |
667 | ;; Preceding line ended in comma or semi; |
668 | ;; use the standard indent for this level. |
669 | (if at-else |
670 | (progn (cperl-backward-to-start-of-if opoint) |
671 | (setq this-indent (current-indentation))) |
672 | (setq this-indent (car indent-stack)))))) |
673 | ;; Just started a new nesting level. |
674 | ;; Compute the standard indent for this level. |
675 | (let ((val (calculate-cperl-indent |
676 | (if (car indent-stack) |
677 | (- (car indent-stack)))))) |
678 | (setcar indent-stack |
679 | (setq this-indent val)))) |
680 | ;; Adjust line indentation according to its contents |
681 | (if (or (looking-at "case[ \t]") |
682 | (and (looking-at "[A-Za-z]") |
683 | (save-excursion |
684 | (forward-sexp 1) |
685 | (looking-at ":")))) |
686 | (setq this-indent (max 1 (+ this-indent cperl-label-offset)))) |
687 | (if (= (following-char) ?}) |
688 | (setq this-indent (- this-indent cperl-indent-level))) |
689 | (if (= (following-char) ?{) |
690 | (setq this-indent (+ this-indent cperl-brace-offset))) |
691 | ;; Put chosen indentation into effect. |
692 | (or (= (current-column) this-indent) |
693 | (= (following-char) ?\#) |
694 | (progn |
695 | (delete-region (point) (progn (beginning-of-line) (point))) |
696 | (indent-to this-indent))) |
697 | ;; Indent any comment following the text. |
698 | (or (looking-at comment-start-skip) |
699 | (if (re-search-forward comment-start-skip (save-excursion (end-of-line) (point)) t) |
700 | (progn (indent-for-comment) (beginning-of-line))))))))) |
701 | ; (message "Indenting C expression...done") |
702 | ) |
703 | --cut here-- |
704 | -- |
705 | =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= |
706 | Vivek Khera, Gradual Student/Systems Guy Department of Computer Science |
707 | Internet: khera@cs.duke.edu Box 90129 |
708 | RIPEM/PGP/MIME spoken here Durham, NC 27708-0129 (919)660-6528 |
709 | |
710 | |