475
|
1 ;; Perl code editing commands for GNU Emacs
|
|
2 ;; Copyright (C) 1990 William F. Mann
|
|
3 ;; Adapted from C code editing commands 'c-mode.el', Copyright 1987 by the
|
|
4 ;; Free Software Foundation, under terms of its General Public License.
|
|
5
|
|
6 ;; This file may be made part of GNU Emacs at the option of the FSF, or
|
|
7 ;; of the perl distribution at the option of Larry Wall.
|
|
8
|
|
9 ;; This code is distributed in the hope that it will be useful,
|
|
10 ;; but WITHOUT ANY WARRANTY. No author or distributor
|
|
11 ;; accepts responsibility to anyone for the consequences of using it
|
|
12 ;; or for whether it serves any particular purpose or works at all,
|
|
13 ;; unless he says so in writing. Refer to the GNU Emacs General Public
|
|
14 ;; License for full details.
|
|
15
|
|
16 ;; Everyone is granted permission to copy, modify and redistribute
|
|
17 ;; this code, but only under the conditions described in the
|
|
18 ;; GNU Emacs General Public License. A copy of this license is
|
|
19 ;; supposed to have been given to you along with GNU Emacs so you
|
|
20 ;; can know your rights and responsibilities. It should be in a
|
|
21 ;; file named COPYING. Among other things, the copyright notice
|
|
22 ;; and this notice must be preserved on all copies.
|
|
23
|
|
24 ;; To enter perl-mode automatically, add (autoload 'perl-mode "perl-mode")
|
|
25 ;; to your .emacs file and change the first line of your perl script to:
|
|
26 ;; #!/usr/bin/perl -- # -*-Perl-*-
|
|
27 ;; With argments to perl:
|
|
28 ;; #!/usr/bin/perl -P- # -*-Perl-*-
|
|
29 ;; To handle files included with do 'filename.pl';, add something like
|
|
30 ;; (setq auto-mode-alist (append (list (cons "\\.pl$" 'perl-mode))
|
|
31 ;; auto-mode-alist))
|
|
32 ;; to your .emacs file; otherwise the .pl suffix defaults to prolog-mode.
|
|
33
|
|
34 ;; This code is based on the 18.53 version c-mode.el, with extensive
|
|
35 ;; rewriting. Most of the features of c-mode survived intact.
|
|
36
|
|
37 ;; I added a new feature which adds functionality to TAB; it is controlled
|
|
38 ;; by the variable perl-tab-to-comment. With it enabled, TAB does the
|
|
39 ;; first thing it can from the following list: change the indentation;
|
|
40 ;; move past leading white space; delete an empty comment; reindent a
|
|
41 ;; comment; move to end of line; create an empty comment; tell you that
|
|
42 ;; the line ends in a quoted string, or has a # which should be a \#.
|
|
43
|
|
44 ;; If your machine is slow, you may want to remove some of the bindings
|
|
45 ;; to electric-perl-terminator. I changed the indenting defaults to be
|
|
46 ;; what Larry Wall uses in perl/lib, but left in all the options.
|
|
47
|
|
48 ;; I also tuned a few things: comments and labels starting in column
|
|
49 ;; zero are left there by indent-perl-exp; perl-beginning-of-function
|
|
50 ;; goes back to the first open brace/paren in column zero, the open brace
|
|
51 ;; in 'sub ... {', or the equal sign in 'format ... ='; indent-perl-exp
|
|
52 ;; (meta-^q) indents from the current line through the close of the next
|
|
53 ;; brace/paren, so you don't need to start exactly at a brace or paren.
|
|
54
|
|
55 ;; It may be good style to put a set of redundant braces around your
|
|
56 ;; main program. This will let you reindent it with meta-^q.
|
|
57
|
|
58 ;; Known problems (these are all caused by limitations in the elisp
|
|
59 ;; parsing routine (parse-partial-sexp), which was not designed for such
|
|
60 ;; a rich language; writing a more suitable parser would be a big job):
|
|
61 ;; 1) Regular expression delimitors do not act as quotes, so special
|
|
62 ;; characters such as `'"#:;[](){} may need to be backslashed
|
|
63 ;; in regular expressions and in both parts of s/// and tr///.
|
|
64 ;; 2) The globbing syntax <pattern> is not recognized, so special
|
|
65 ;; characters in the pattern string must be backslashed.
|
|
66 ;; 3) The q, qq, and << quoting operators are not recognized; see below.
|
|
67 ;; 4) \ (backslash) always quotes the next character, so '\' is
|
|
68 ;; treated as the start of a string. Use "\\" as a work-around.
|
|
69 ;; 5) To make variables such a $' and $#array work, perl-mode treats
|
|
70 ;; $ just like backslash, so '$' is the same as problem 5.
|
|
71 ;; 6) Unfortunately, treating $ like \ makes ${var} be treated as an
|
|
72 ;; unmatched }. See below.
|
|
73 ;; 7) When ' (quote) is used as a package name separator, perl-mode
|
|
74 ;; doesn't understand, and thinks it is seeing a quoted string.
|
|
75
|
|
76 ;; Here are some ugly tricks to bypass some of these problems: the perl
|
|
77 ;; expression /`/ (that's a back-tick) usually evaluates harmlessly,
|
|
78 ;; but will trick perl-mode into starting a quoted string, which
|
|
79 ;; can be ended with another /`/. Assuming you have no embedded
|
|
80 ;; back-ticks, this can used to help solve problem 3:
|
|
81 ;;
|
|
82 ;; /`/; $ugly = q?"'$?; /`/;
|
|
83 ;;
|
|
84 ;; To solve problem 6, add a /{/; before each use of ${var}:
|
|
85 ;; /{/; while (<${glob_me}>) ...
|
|
86 ;;
|
|
87 ;; Problem 7 is even worse, but this 'fix' does work :-(
|
|
88 ;; $DB'stop#'
|
|
89 ;; [$DB'line#'
|
|
90 ;; ] =~ s/;9$//;
|
|
91
|
|
92
|
|
93 (defvar perl-mode-abbrev-table nil
|
|
94 "Abbrev table in use in perl-mode buffers.")
|
|
95 (define-abbrev-table 'perl-mode-abbrev-table ())
|
|
96
|
|
97 (defvar perl-mode-map ()
|
|
98 "Keymap used in Perl mode.")
|
|
99 (if perl-mode-map
|
|
100 ()
|
|
101 (setq perl-mode-map (make-sparse-keymap))
|
|
102 (define-key perl-mode-map "{" 'electric-perl-terminator)
|
|
103 (define-key perl-mode-map "}" 'electric-perl-terminator)
|
|
104 (define-key perl-mode-map ";" 'electric-perl-terminator)
|
|
105 (define-key perl-mode-map ":" 'electric-perl-terminator)
|
|
106 (define-key perl-mode-map "\e\C-a" 'perl-beginning-of-function)
|
|
107 (define-key perl-mode-map "\e\C-e" 'perl-end-of-function)
|
|
108 (define-key perl-mode-map "\e\C-h" 'mark-perl-function)
|
|
109 (define-key perl-mode-map "\e\C-q" 'indent-perl-exp)
|
|
110 (define-key perl-mode-map "\177" 'backward-delete-char-untabify)
|
|
111 (define-key perl-mode-map "\t" 'perl-indent-command))
|
|
112
|
|
113 (autoload 'c-macro-expand "cmacexp"
|
|
114 "Display the result of expanding all C macros occurring in the region.
|
|
115 The expansion is entirely correct because it uses the C preprocessor."
|
|
116 t)
|
|
117
|
|
118 (defvar perl-mode-syntax-table nil
|
|
119 "Syntax table in use in perl-mode buffers.")
|
|
120
|
|
121 (if perl-mode-syntax-table
|
|
122 ()
|
|
123 (setq perl-mode-syntax-table (make-syntax-table (standard-syntax-table)))
|
|
124 (modify-syntax-entry ?\n ">" perl-mode-syntax-table)
|
|
125 (modify-syntax-entry ?# "<" perl-mode-syntax-table)
|
|
126 (modify-syntax-entry ?$ "/" perl-mode-syntax-table)
|
|
127 (modify-syntax-entry ?% "." perl-mode-syntax-table)
|
|
128 (modify-syntax-entry ?& "." perl-mode-syntax-table)
|
|
129 (modify-syntax-entry ?\' "\"" perl-mode-syntax-table)
|
|
130 (modify-syntax-entry ?* "." perl-mode-syntax-table)
|
|
131 (modify-syntax-entry ?+ "." perl-mode-syntax-table)
|
|
132 (modify-syntax-entry ?- "." perl-mode-syntax-table)
|
|
133 (modify-syntax-entry ?/ "." perl-mode-syntax-table)
|
|
134 (modify-syntax-entry ?< "." perl-mode-syntax-table)
|
|
135 (modify-syntax-entry ?= "." perl-mode-syntax-table)
|
|
136 (modify-syntax-entry ?> "." perl-mode-syntax-table)
|
|
137 (modify-syntax-entry ?\\ "\\" perl-mode-syntax-table)
|
|
138 (modify-syntax-entry ?` "\"" perl-mode-syntax-table)
|
|
139 (modify-syntax-entry ?| "." perl-mode-syntax-table)
|
|
140 )
|
|
141
|
|
142 (defconst perl-indent-level 4
|
|
143 "*Indentation of Perl statements with respect to containing block.")
|
|
144 (defconst perl-continued-statement-offset 4
|
|
145 "*Extra indent for lines not starting new statements.")
|
|
146 (defconst perl-continued-brace-offset -4
|
|
147 "*Extra indent for substatements that start with open-braces.
|
|
148 This is in addition to perl-continued-statement-offset.")
|
|
149 (defconst perl-brace-offset 0
|
|
150 "*Extra indentation for braces, compared with other text in same context.")
|
|
151 (defconst perl-brace-imaginary-offset 0
|
|
152 "*Imagined indentation of an open brace that actually follows a statement.")
|
|
153 (defconst perl-label-offset -2
|
|
154 "*Offset of Perl label lines relative to usual indentation.")
|
|
155
|
|
156 (defconst perl-tab-always-indent t
|
|
157 "*Non-nil means TAB in Perl mode should always indent the current line,
|
|
158 regardless of where in the line point is when the TAB command is used.")
|
|
159
|
|
160 (defconst perl-tab-to-comment t
|
|
161 "*Non-nil means that for lines which don't need indenting, TAB will
|
|
162 either indent an existing comment, move to end-of-line, or if at end-of-line
|
|
163 already, create a new comment.")
|
|
164
|
|
165 (defconst perl-nochange ";?#\\|\f\\|\\s(\\|\\(\\w\\|\\s_\\)+:"
|
|
166 "*Lines starting with this regular expression will not be auto-indented.")
|
|
167
|
|
168 (defun perl-mode ()
|
|
169 "Major mode for editing Perl code.
|
|
170 Expression and list commands understand all Perl brackets.
|
|
171 Tab indents for Perl code.
|
|
172 Comments are delimited with # ... \\n.
|
|
173 Paragraphs are separated by blank lines only.
|
|
174 Delete converts tabs to spaces as it moves back.
|
|
175 \\{perl-mode-map}
|
|
176 Variables controlling indentation style:
|
|
177 perl-tab-always-indent
|
|
178 Non-nil means TAB in Perl mode should always indent the current line,
|
|
179 regardless of where in the line point is when the TAB command is used.
|
|
180 perl-tab-to-comment
|
|
181 Non-nil means that for lines which don't need indenting, TAB will
|
|
182 either delete an empty comment, indent an existing comment, move
|
|
183 to end-of-line, or if at end-of-line already, create a new comment.
|
|
184 perl-nochange
|
|
185 Lines starting with this regular expression will not be auto-indented.
|
|
186 perl-indent-level
|
|
187 Indentation of Perl statements within surrounding block.
|
|
188 The surrounding block's indentation is the indentation
|
|
189 of the line on which the open-brace appears.
|
|
190 perl-continued-statement-offset
|
|
191 Extra indentation given to a substatement, such as the
|
|
192 then-clause of an if or body of a while.
|
|
193 perl-continued-brace-offset
|
|
194 Extra indentation given to a brace that starts a substatement.
|
|
195 This is in addition to perl-continued-statement-offset.
|
|
196 perl-brace-offset
|
|
197 Extra indentation for line if it starts with an open brace.
|
|
198 perl-brace-imaginary-offset
|
|
199 An open brace following other text is treated as if it were
|
|
200 this far to the right of the start of its line.
|
|
201 perl-label-offset
|
|
202 Extra indentation for line that is a label.
|
|
203
|
|
204 Various indentation styles: K&R BSD BLK GNU LW
|
|
205 perl-indent-level 5 8 0 2 4
|
|
206 perl-continued-statement-offset 5 8 4 2 4
|
|
207 perl-continued-brace-offset 0 0 0 0 -4
|
|
208 perl-brace-offset -5 -8 0 0 0
|
|
209 perl-brace-imaginary-offset 0 0 4 0 0
|
|
210 perl-label-offset -5 -8 -2 -2 -2
|
|
211
|
|
212 Turning on Perl mode calls the value of the variable perl-mode-hook with no
|
|
213 args, if that value is non-nil."
|
|
214 (interactive)
|
|
215 (kill-all-local-variables)
|
|
216 (use-local-map perl-mode-map)
|
|
217 (setq major-mode 'perl-mode)
|
|
218 (setq mode-name "Perl")
|
|
219 (setq local-abbrev-table perl-mode-abbrev-table)
|
|
220 (set-syntax-table perl-mode-syntax-table)
|
|
221 (make-local-variable 'paragraph-start)
|
|
222 (setq paragraph-start (concat "^$\\|" page-delimiter))
|
|
223 (make-local-variable 'paragraph-separate)
|
|
224 (setq paragraph-separate paragraph-start)
|
|
225 (make-local-variable 'paragraph-ignore-fill-prefix)
|
|
226 (setq paragraph-ignore-fill-prefix t)
|
|
227 (make-local-variable 'indent-line-function)
|
|
228 (setq indent-line-function 'perl-indent-line)
|
|
229 (make-local-variable 'require-final-newline)
|
|
230 (setq require-final-newline t)
|
|
231 (make-local-variable 'comment-start)
|
|
232 (setq comment-start "# ")
|
|
233 (make-local-variable 'comment-end)
|
|
234 (setq comment-end "")
|
|
235 (make-local-variable 'comment-column)
|
|
236 (setq comment-column 32)
|
|
237 (make-local-variable 'comment-start-skip)
|
|
238 (setq comment-start-skip "\\(^\\|\\s-\\);?#+ *")
|
|
239 (make-local-variable 'comment-indent-hook)
|
|
240 (setq comment-indent-hook 'perl-comment-indent)
|
|
241 (make-local-variable 'parse-sexp-ignore-comments)
|
|
242 (setq parse-sexp-ignore-comments nil)
|
|
243 (run-hooks 'perl-mode-hook))
|
|
244
|
|
245 ;; This is used by indent-for-comment
|
|
246 ;; to decide how much to indent a comment in Perl code
|
|
247 ;; based on its context.
|
|
248 (defun perl-comment-indent ()
|
|
249 (if (and (bolp) (not (eolp)))
|
|
250 0 ;Existing comment at bol stays there.
|
|
251 (save-excursion
|
|
252 (skip-chars-backward " \t")
|
|
253 (max (1+ (current-column)) ;Else indent at comment column
|
|
254 comment-column)))) ; except leave at least one space.
|
|
255
|
|
256 (defun electric-perl-terminator (arg)
|
|
257 "Insert character. If at end-of-line, and not in a comment or a quote,
|
|
258 correct the line's indentation."
|
|
259 (interactive "P")
|
|
260 (let ((insertpos (point)))
|
|
261 (and (not arg) ; decide whether to indent
|
|
262 (eolp)
|
|
263 (save-excursion
|
|
264 (beginning-of-line)
|
|
265 (and (not ; eliminate comments quickly
|
|
266 (re-search-forward comment-start-skip insertpos t))
|
|
267 (or (/= last-command-char ?:)
|
|
268 ;; Colon is special only after a label ....
|
|
269 (looking-at "\\s-*\\(\\w\\|\\s_\\)+$"))
|
|
270 (let ((pps (parse-partial-sexp
|
|
271 (perl-beginning-of-function) insertpos)))
|
|
272 (not (or (nth 3 pps) (nth 4 pps) (nth 5 pps))))))
|
|
273 (progn ; must insert, indent, delete
|
|
274 (insert-char last-command-char 1)
|
|
275 (perl-indent-line)
|
|
276 (delete-char -1))))
|
|
277 (self-insert-command (prefix-numeric-value arg)))
|
|
278
|
|
279 ;; not used anymore, but may be useful someday:
|
|
280 ;;(defun perl-inside-parens-p ()
|
|
281 ;; (condition-case ()
|
|
282 ;; (save-excursion
|
|
283 ;; (save-restriction
|
|
284 ;; (narrow-to-region (point)
|
|
285 ;; (perl-beginning-of-function))
|
|
286 ;; (goto-char (point-max))
|
|
287 ;; (= (char-after (or (scan-lists (point) -1 1) (point-min))) ?\()))
|
|
288 ;; (error nil)))
|
|
289
|
|
290 (defun perl-indent-command (&optional arg)
|
|
291 "Indent current line as Perl code, or optionally, insert a tab character.
|
|
292
|
|
293 With an argument, indent the current line, regardless of other options.
|
|
294
|
|
295 If perl-tab-always-indent is nil and point is not in the indentation
|
|
296 area at the beginning of the line, simply insert a tab.
|
|
297
|
|
298 Otherwise, indent the current line. If point was within the indentation
|
|
299 area it is moved to the end of the indentation area. If the line was
|
|
300 already indented properly and point was not within the indentation area,
|
|
301 and if perl-tab-to-comment is non-nil (the default), then do the first
|
|
302 possible action from the following list:
|
|
303
|
|
304 1) delete an empty comment
|
|
305 2) move forward to start of comment, indenting if necessary
|
|
306 3) move forward to end of line
|
|
307 4) create an empty comment
|
|
308 5) move backward to start of comment, indenting if necessary."
|
|
309 (interactive "P")
|
|
310 (if arg ; If arg, just indent this line
|
|
311 (perl-indent-line "\f")
|
|
312 (if (and (not perl-tab-always-indent)
|
|
313 (<= (current-column) (current-indentation)))
|
|
314 (insert-tab)
|
|
315 (let (bof lsexp delta (oldpnt (point)))
|
|
316 (beginning-of-line)
|
|
317 (setq lsexp (point))
|
|
318 (setq bof (perl-beginning-of-function))
|
|
319 (goto-char oldpnt)
|
|
320 (setq delta (perl-indent-line "\f\\|;?#" bof))
|
|
321 (and perl-tab-to-comment
|
|
322 (= oldpnt (point)) ; done if point moved
|
|
323 (if (listp delta) ; if line starts in a quoted string
|
|
324 (setq lsexp (or (nth 2 delta) bof))
|
|
325 (= delta 0)) ; done if indenting occurred
|
|
326 (let (eol state)
|
|
327 (end-of-line)
|
|
328 (setq eol (point))
|
|
329 (if (= (char-after bof) ?=)
|
|
330 (if (= oldpnt eol)
|
|
331 (message "In a format statement"))
|
|
332 (setq state (parse-partial-sexp lsexp eol))
|
|
333 (if (nth 3 state)
|
|
334 (if (= oldpnt eol) ; already at eol in a string
|
|
335 (message "In a string which starts with a %c."
|
|
336 (nth 3 state)))
|
|
337 (if (not (nth 4 state))
|
|
338 (if (= oldpnt eol) ; no comment, create one?
|
|
339 (indent-for-comment))
|
|
340 (beginning-of-line)
|
|
341 (if (re-search-forward comment-start-skip eol 'move)
|
|
342 (if (eolp)
|
|
343 (progn ; kill existing comment
|
|
344 (goto-char (match-beginning 0))
|
|
345 (skip-chars-backward " \t")
|
|
346 (kill-region (point) eol))
|
|
347 (if (or (< oldpnt (point)) (= oldpnt eol))
|
|
348 (indent-for-comment) ; indent existing comment
|
|
349 (end-of-line)))
|
|
350 (if (/= oldpnt eol)
|
|
351 (end-of-line)
|
|
352 (message "Use backslash to quote # characters.")
|
|
353 (ding t))))))))))))
|
|
354
|
|
355 (defun perl-indent-line (&optional nochange parse-start)
|
|
356 "Indent current line as Perl code. Return the amount the indentation
|
|
357 changed by, or (parse-state) if line starts in a quoted string."
|
|
358 (let ((case-fold-search nil)
|
|
359 (pos (- (point-max) (point)))
|
|
360 (bof (or parse-start (save-excursion (perl-beginning-of-function))))
|
|
361 beg indent shift-amt)
|
|
362 (beginning-of-line)
|
|
363 (setq beg (point))
|
|
364 (setq shift-amt
|
|
365 (cond ((= (char-after bof) ?=) 0)
|
|
366 ((listp (setq indent (calculate-perl-indent bof))) indent)
|
|
367 ((looking-at (or nochange perl-nochange)) 0)
|
|
368 (t
|
|
369 (skip-chars-forward " \t\f")
|
|
370 (cond ((looking-at "\\(\\w\\|\\s_\\)+:")
|
|
371 (setq indent (max 1 (+ indent perl-label-offset))))
|
|
372 ((= (following-char) ?})
|
|
373 (setq indent (- indent perl-indent-level)))
|
|
374 ((= (following-char) ?{)
|
|
375 (setq indent (+ indent perl-brace-offset))))
|
|
376 (- indent (current-column)))))
|
|
377 (skip-chars-forward " \t\f")
|
|
378 (if (and (numberp shift-amt) (/= 0 shift-amt))
|
|
379 (progn (delete-region beg (point))
|
|
380 (indent-to indent)))
|
|
381 ;; If initial point was within line's indentation,
|
|
382 ;; position after the indentation. Else stay at same point in text.
|
|
383 (if (> (- (point-max) pos) (point))
|
|
384 (goto-char (- (point-max) pos)))
|
|
385 shift-amt))
|
|
386
|
|
387 (defun calculate-perl-indent (&optional parse-start)
|
|
388 "Return appropriate indentation for current line as Perl code.
|
|
389 In usual case returns an integer: the column to indent to.
|
|
390 Returns (parse-state) if line starts inside a string."
|
|
391 (save-excursion
|
|
392 (beginning-of-line)
|
|
393 (let ((indent-point (point))
|
|
394 (case-fold-search nil)
|
|
395 (colon-line-end 0)
|
|
396 state containing-sexp)
|
|
397 (if parse-start ;used to avoid searching
|
|
398 (goto-char parse-start)
|
|
399 (perl-beginning-of-function))
|
|
400 (while (< (point) indent-point) ;repeat until right sexp
|
|
401 (setq parse-start (point))
|
|
402 (setq state (parse-partial-sexp (point) indent-point 0))
|
|
403 ; state = (depth_in_parens innermost_containing_list last_complete_sexp
|
|
404 ; string_terminator_or_nil inside_commentp following_quotep
|
|
405 ; minimum_paren-depth_this_scan)
|
|
406 ; Parsing stops if depth in parentheses becomes equal to third arg.
|
|
407 (setq containing-sexp (nth 1 state)))
|
|
408 (cond ((nth 3 state) state) ; In a quoted string?
|
|
409 ((null containing-sexp) ; Line is at top level.
|
|
410 (skip-chars-forward " \t\f")
|
|
411 (if (= (following-char) ?{)
|
|
412 0 ; move to beginning of line if it starts a function body
|
|
413 ;; indent a little if this is a continuation line
|
|
414 (perl-backward-to-noncomment)
|
|
415 (if (or (bobp)
|
|
416 (memq (preceding-char) '(?\; ?\})))
|
|
417 0 perl-continued-statement-offset)))
|
|
418 ((/= (char-after containing-sexp) ?{)
|
|
419 ;; line is expression, not statement:
|
|
420 ;; indent to just after the surrounding open.
|
|
421 (goto-char (1+ containing-sexp))
|
|
422 (current-column))
|
|
423 (t
|
|
424 ;; Statement level. Is it a continuation or a new statement?
|
|
425 ;; Find previous non-comment character.
|
|
426 (perl-backward-to-noncomment)
|
|
427 ;; Back up over label lines, since they don't
|
|
428 ;; affect whether our line is a continuation.
|
|
429 (while (or (eq (preceding-char) ?\,)
|
|
430 (and (eq (preceding-char) ?:)
|
|
431 (memq (char-syntax (char-after (- (point) 2)))
|
|
432 '(?w ?_))))
|
|
433 (if (eq (preceding-char) ?\,)
|
|
434 (perl-backward-to-start-of-continued-exp containing-sexp))
|
|
435 (beginning-of-line)
|
|
436 (perl-backward-to-noncomment))
|
|
437 ;; Now we get the answer.
|
|
438 (if (not (memq (preceding-char) '(?\; ?\} ?\{)))
|
|
439 ;; This line is continuation of preceding line's statement;
|
|
440 ;; indent perl-continued-statement-offset more than the
|
|
441 ;; previous line of the statement.
|
|
442 (progn
|
|
443 (perl-backward-to-start-of-continued-exp containing-sexp)
|
|
444 (+ perl-continued-statement-offset (current-column)
|
|
445 (if (save-excursion (goto-char indent-point)
|
|
446 (looking-at "[ \t]*{"))
|
|
447 perl-continued-brace-offset 0)))
|
|
448 ;; This line starts a new statement.
|
|
449 ;; Position at last unclosed open.
|
|
450 (goto-char containing-sexp)
|
|
451 (or
|
|
452 ;; If open paren is in col 0, close brace is special
|
|
453 (and (bolp)
|
|
454 (save-excursion (goto-char indent-point)
|
|
455 (looking-at "[ \t]*}"))
|
|
456 perl-indent-level)
|
|
457 ;; Is line first statement after an open-brace?
|
|
458 ;; If no, find that first statement and indent like it.
|
|
459 (save-excursion
|
|
460 (forward-char 1)
|
|
461 ;; Skip over comments and labels following openbrace.
|
|
462 (while (progn
|
|
463 (skip-chars-forward " \t\f\n")
|
|
464 (cond ((looking-at ";?#")
|
|
465 (forward-line 1) t)
|
|
466 ((looking-at "\\(\\w\\|\\s_\\)+:")
|
|
467 (save-excursion
|
|
468 (end-of-line)
|
|
469 (setq colon-line-end (point)))
|
|
470 (search-forward ":")))))
|
|
471 ;; The first following code counts
|
|
472 ;; if it is before the line we want to indent.
|
|
473 (and (< (point) indent-point)
|
|
474 (if (> colon-line-end (point))
|
|
475 (- (current-indentation) perl-label-offset)
|
|
476 (current-column))))
|
|
477 ;; If no previous statement,
|
|
478 ;; indent it relative to line brace is on.
|
|
479 ;; For open paren in column zero, don't let statement
|
|
480 ;; start there too. If perl-indent-level is zero,
|
|
481 ;; use perl-brace-offset + perl-continued-statement-offset
|
|
482 ;; For open-braces not the first thing in a line,
|
|
483 ;; add in perl-brace-imaginary-offset.
|
|
484 (+ (if (and (bolp) (zerop perl-indent-level))
|
|
485 (+ perl-brace-offset perl-continued-statement-offset)
|
|
486 perl-indent-level)
|
|
487 ;; Move back over whitespace before the openbrace.
|
|
488 ;; If openbrace is not first nonwhite thing on the line,
|
|
489 ;; add the perl-brace-imaginary-offset.
|
|
490 (progn (skip-chars-backward " \t")
|
|
491 (if (bolp) 0 perl-brace-imaginary-offset))
|
|
492 ;; If the openbrace is preceded by a parenthesized exp,
|
|
493 ;; move to the beginning of that;
|
|
494 ;; possibly a different line
|
|
495 (progn
|
|
496 (if (eq (preceding-char) ?\))
|
|
497 (forward-sexp -1))
|
|
498 ;; Get initial indentation of the line we are on.
|
|
499 (current-indentation))))))))))
|
|
500
|
|
501 (defun perl-backward-to-noncomment ()
|
|
502 "Move point backward to after the first non-white-space, skipping comments."
|
|
503 (interactive)
|
|
504 (let (opoint stop)
|
|
505 (while (not stop)
|
|
506 (setq opoint (point))
|
|
507 (beginning-of-line)
|
|
508 (if (re-search-forward comment-start-skip opoint 'move 1)
|
|
509 (progn (goto-char (match-end 1))
|
|
510 (skip-chars-forward ";")))
|
|
511 (skip-chars-backward " \t\f")
|
|
512 (setq stop (or (bobp)
|
|
513 (not (bolp))
|
|
514 (forward-char -1))))))
|
|
515
|
|
516 (defun perl-backward-to-start-of-continued-exp (lim)
|
|
517 (if (= (preceding-char) ?\))
|
|
518 (forward-sexp -1))
|
|
519 (beginning-of-line)
|
|
520 (if (<= (point) lim)
|
|
521 (goto-char (1+ lim)))
|
|
522 (skip-chars-forward " \t\f"))
|
|
523
|
|
524 ;; note: this may be slower than the c-mode version, but I can understand it.
|
|
525 (defun indent-perl-exp ()
|
|
526 "Indent each line of the Perl grouping following point."
|
|
527 (interactive)
|
|
528 (let* ((case-fold-search nil)
|
|
529 (oldpnt (point-marker))
|
|
530 (bof-mark (save-excursion
|
|
531 (end-of-line 2)
|
|
532 (perl-beginning-of-function)
|
|
533 (point-marker)))
|
|
534 eol last-mark lsexp-mark delta)
|
|
535 (if (= (char-after (marker-position bof-mark)) ?=)
|
|
536 (message "Can't indent a format statement")
|
|
537 (message "Indenting Perl expression...")
|
|
538 (save-excursion (end-of-line) (setq eol (point)))
|
|
539 (save-excursion ; locate matching close paren
|
|
540 (while (and (not (eobp)) (<= (point) eol))
|
|
541 (parse-partial-sexp (point) (point-max) 0))
|
|
542 (setq last-mark (point-marker)))
|
|
543 (setq lsexp-mark bof-mark)
|
|
544 (beginning-of-line)
|
|
545 (while (< (point) (marker-position last-mark))
|
|
546 (setq delta (perl-indent-line nil (marker-position bof-mark)))
|
|
547 (if (numberp delta) ; unquoted start-of-line?
|
|
548 (progn
|
|
549 (if (eolp)
|
|
550 (delete-horizontal-space))
|
|
551 (setq lsexp-mark (point-marker))))
|
|
552 (end-of-line)
|
|
553 (setq eol (point))
|
|
554 (if (nth 4 (parse-partial-sexp (marker-position lsexp-mark) eol))
|
|
555 (progn ; line ends in a comment
|
|
556 (beginning-of-line)
|
|
557 (if (or (not (looking-at "\\s-*;?#"))
|
|
558 (listp delta)
|
|
559 (and (/= 0 delta)
|
|
560 (= (- (current-indentation) delta) comment-column)))
|
|
561 (if (re-search-forward comment-start-skip eol t)
|
|
562 (indent-for-comment))))) ; indent existing comment
|
|
563 (forward-line 1))
|
|
564 (goto-char (marker-position oldpnt))
|
|
565 (message "Indenting Perl expression...done"))))
|
|
566
|
|
567 (defun perl-beginning-of-function (&optional arg)
|
|
568 "Move backward to next beginning-of-function, or as far as possible.
|
|
569 With argument, repeat that many times; negative args move forward.
|
|
570 Returns new value of point in all cases."
|
|
571 (interactive "p")
|
|
572 (or arg (setq arg 1))
|
|
573 (if (< arg 0) (forward-char 1))
|
|
574 (and (/= arg 0)
|
|
575 (re-search-backward "^\\s(\\|^\\s-*sub\\b[^{]+{\\|^\\s-*format\\b[^=]*=\\|^\\."
|
|
576 nil 'move arg)
|
|
577 (goto-char (1- (match-end 0))))
|
|
578 (point))
|
|
579
|
|
580 ;; note: this routine is adapted directly from emacs lisp.el, end-of-defun;
|
|
581 ;; no bugs have been removed :-)
|
|
582 (defun perl-end-of-function (&optional arg)
|
|
583 "Move forward to next end-of-function.
|
|
584 The end of a function is found by moving forward from the beginning of one.
|
|
585 With argument, repeat that many times; negative args move backward."
|
|
586 (interactive "p")
|
|
587 (or arg (setq arg 1))
|
|
588 (let ((first t))
|
|
589 (while (and (> arg 0) (< (point) (point-max)))
|
|
590 (let ((pos (point)) npos)
|
|
591 (while (progn
|
|
592 (if (and first
|
|
593 (progn
|
|
594 (forward-char 1)
|
|
595 (perl-beginning-of-function 1)
|
|
596 (not (bobp))))
|
|
597 nil
|
|
598 (or (bobp) (forward-char -1))
|
|
599 (perl-beginning-of-function -1))
|
|
600 (setq first nil)
|
|
601 (forward-list 1)
|
|
602 (skip-chars-forward " \t")
|
|
603 (if (looking-at "[#\n]")
|
|
604 (forward-line 1))
|
|
605 (<= (point) pos))))
|
|
606 (setq arg (1- arg)))
|
|
607 (while (< arg 0)
|
|
608 (let ((pos (point)))
|
|
609 (perl-beginning-of-function 1)
|
|
610 (forward-sexp 1)
|
|
611 (forward-line 1)
|
|
612 (if (>= (point) pos)
|
|
613 (if (progn (perl-beginning-of-function 2) (not (bobp)))
|
|
614 (progn
|
|
615 (forward-list 1)
|
|
616 (skip-chars-forward " \t")
|
|
617 (if (looking-at "[#\n]")
|
|
618 (forward-line 1)))
|
|
619 (goto-char (point-min)))))
|
|
620 (setq arg (1+ arg)))))
|
|
621
|
|
622 (defun mark-perl-function ()
|
|
623 "Put mark at end of Perl function, point at beginning."
|
|
624 (interactive)
|
|
625 (push-mark (point))
|
|
626 (perl-end-of-function)
|
|
627 (push-mark (point))
|
|
628 (perl-beginning-of-function)
|
|
629 (backward-paragraph))
|
|
630
|
|
631 ;;;;;;;; That's all, folks! ;;;;;;;;;
|