Undo May 15 change.
[bpt/emacs.git] / lisp / progmodes / cperl-mode.el
CommitLineData
f83d2997
KH
1;;; cperl-mode.el --- Perl code editing commands for Emacs
2
3;; Copyright (C) 1985, 86, 87, 91, 92, 93, 94, 95, 96, 1997
4;; Free Software Foundation, Inc.
5
6;; Author: Ilya Zakharevich and Bob Olson
7;; Maintainer: Ilya Zakharevich <ilya@math.ohio-state.edu>
8;; Keywords: languages, Perl
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
26
27;;; Corrections made by Ilya Zakharevich ilya@math.mps.ohio-state.edu
28;;; XEmacs changes by Peter Arius arius@informatik.uni-erlangen.de
29
30;;; Commentary:
31
32;;; You can either fine-tune the bells and whistles of this mode or
33;;; bulk enable them by putting
34
35;; (setq cperl-hairy t)
36
37;;; in your .emacs file. (Emacs rulers do not consider it politically
38;;; correct to make whistles enabled by default.)
39
40;;; DO NOT FORGET to read micro-docs (available from `Perl' menu) <<<<<<
41;;; or as help on variables `cperl-tips', `cperl-problems', <<<<<<
42;;; `cperl-non-problems', `cperl-praise'. <<<<<<
43
44;;; The mode information (on C-h m) provides some customization help.
45;;; If you use font-lock feature of this mode, it is advisable to use
46;;; either lazy-lock-mode or fast-lock-mode. I prefer lazy-lock.
47
48;;; Faces used now: three faces for first-class and second-class keywords
49;;; and control flow words, one for each: comments, string, labels,
50;;; functions definitions and packages, arrays, hashes, and variable
51;;; definitions. If you do not see all these faces, your font-lock does
52;;; not define them, so you need to define them manually.
53
54;;; into your .emacs file.
55
56;;;; This mode supports font-lock, imenu and mode-compile. In the
57;;;; hairy version font-lock is on, but you should activate imenu
58;;;; yourself (note that mode-compile is not standard yet). Well, you
59;;;; can use imenu from keyboard anyway (M-x imenu), but it is better
60;;;; to bind it like that:
61
62;; (define-key global-map [M-S-down-mouse-3] 'imenu)
63
64;;; Code:
65
ccc3ce39
SE
66(defgroup cperl nil
67 "Major mode for editing Perl code."
68 :prefix "cperl-"
69 :group 'languages)
70
f83d2997
KH
71(defconst cperl-xemacs-p (string-match "XEmacs\\|Lucid" emacs-version))
72\f
ccc3ce39 73(defcustom cperl-extra-newline-before-brace nil
f83d2997
KH
74 "*Non-nil means that if, elsif, while, until, else, for, foreach
75and do constructs look like:
76
77 if ()
78 {
79 }
80
81instead of:
82
83 if () {
84 }
ccc3ce39
SE
85"
86 :type 'boolean
87 :group 'cperl)
88
89(defcustom cperl-indent-level 2
90 "*Indentation of CPerl statements with respect to containing block."
91 :type 'integer
92 :group 'cperl)
f83d2997 93
ccc3ce39 94(defcustom cperl-lineup-step nil
f83d2997 95 "*`cperl-lineup' will always lineup at multiple of this number.
ccc3ce39
SE
96If `nil', the value of `cperl-indent-level' will be used."
97 :type '(choice (const nil) integer)
98 :group 'cperl)
99(defcustom cperl-brace-imaginary-offset 0
f83d2997
KH
100 "*Imagined indentation of a Perl open brace that actually follows a statement.
101An open brace following other text is treated as if it were this far
ccc3ce39
SE
102to the right of the start of its line."
103 :type 'integer
104 :group 'cperl)
105
106(defcustom cperl-brace-offset 0
107 "*Extra indentation for braces, compared with other text in same context."
108 :type 'integer
109 :group 'cperl)
110(defcustom cperl-label-offset -2
111 "*Offset of CPerl label lines relative to usual indentation."
112 :type 'integer
113 :group 'cperl)
114(defcustom cperl-min-label-indent 1
115 "*Minimal offset of CPerl label lines."
116 :type 'integer
117 :group 'cperl)
118(defcustom cperl-continued-statement-offset 2
119 "*Extra indent for lines not starting new statements."
120 :type 'integer
121 :group 'cperl)
122(defcustom cperl-continued-brace-offset 0
f83d2997 123 "*Extra indent for substatements that start with open-braces.
ccc3ce39
SE
124This is in addition to cperl-continued-statement-offset."
125 :type 'integer
126 :group 'cperl)
127(defcustom cperl-close-paren-offset -1
128 "*Extra indent for substatements that start with close-parenthesis."
129 :type 'integer
130 :group 'cperl)
131
132(defcustom cperl-auto-newline nil
f83d2997
KH
133 "*Non-nil means automatically newline before and after braces,
134and after colons and semicolons, inserted in CPerl code. The following
135\\[cperl-electric-backspace] will remove the inserted whitespace.
136Insertion after colons requires both this variable and
ccc3ce39
SE
137`cperl-auto-newline-after-colon' set."
138 :type 'boolean
139 :group 'cperl)
f83d2997 140
ccc3ce39 141(defcustom cperl-auto-newline-after-colon nil
f83d2997 142 "*Non-nil means automatically newline even after colons.
ccc3ce39
SE
143Subject to `cperl-auto-newline' setting."
144 :type 'boolean
145 :group 'cperl)
f83d2997 146
ccc3ce39 147(defcustom cperl-tab-always-indent t
f83d2997 148 "*Non-nil means TAB in CPerl mode should always reindent the current line,
ccc3ce39
SE
149regardless of where in the line point is when the TAB command is used."
150 :type 'boolean
151 :group 'cperl)
f83d2997 152
ccc3ce39 153(defcustom cperl-font-lock nil
f83d2997 154 "*Non-nil (and non-null) means CPerl buffers will use font-lock-mode.
ccc3ce39
SE
155Can be overwritten by `cperl-hairy' if nil."
156 :type 'boolean
157 :group 'cperl)
f83d2997 158
ccc3ce39 159(defcustom cperl-electric-lbrace-space nil
f83d2997 160 "*Non-nil (and non-null) means { after $ in CPerl buffers should be preceded by ` '.
ccc3ce39
SE
161Can be overwritten by `cperl-hairy' if nil."
162 :type 'boolean
163 :group 'cperl)
f83d2997 164
ccc3ce39 165(defcustom cperl-electric-parens-string "({[]})<"
f83d2997 166 "*String of parentheses that should be electric in CPerl.
ccc3ce39
SE
167Closing ones are electric only if the region is highlighted."
168 :type 'string
169 :group 'cperl)
f83d2997 170
ccc3ce39 171(defcustom cperl-electric-parens nil
f83d2997 172 "*Non-nil (and non-null) means parentheses should be electric in CPerl.
ccc3ce39
SE
173Can be overwritten by `cperl-hairy' if nil."
174 :type 'boolean
175 :group 'cperl)
176(defcustom cperl-electric-parens-mark
f83d2997
KH
177 (and window-system
178 (or (and (boundp 'transient-mark-mode) ; For Emacs
179 transient-mark-mode)
180 (and (boundp 'zmacs-regions) ; For XEmacs
181 zmacs-regions)))
182 "*Not-nil means that electric parens look for active mark.
ccc3ce39
SE
183Default is yes if there is visual feedback on mark."
184 :type 'boolean
185 :group 'cperl)
f83d2997 186
ccc3ce39 187(defcustom cperl-electric-linefeed nil
f83d2997
KH
188 "*If true, LFD should be hairy in CPerl, otherwise C-c LFD is hairy.
189In any case these two mean plain and hairy linefeeds together.
ccc3ce39
SE
190Can be overwritten by `cperl-hairy' if nil."
191 :type 'boolean
192 :group 'cperl)
f83d2997 193
ccc3ce39 194(defcustom cperl-electric-keywords nil
f83d2997 195 "*Not-nil (and non-null) means keywords are electric in CPerl.
ccc3ce39
SE
196Can be overwritten by `cperl-hairy' if nil."
197 :type 'boolean
198 :group 'cperl)
199
200(defcustom cperl-hairy nil
201 "*Not-nil means all the bells and whistles are enabled in CPerl."
202 :type 'boolean
203 :group 'cperl)
204
205(defcustom cperl-comment-column 32
206 "*Column to put comments in CPerl (use \\[cperl-indent] to lineup with code)."
207 :type 'integer
208 :group 'cperl)
209
210(defcustom cperl-vc-header-alist '((SCCS "$sccs = '%W\%' ;")
211 (RCS "$rcs = ' $Id\$ ' ;"))
212 "*What to use as `vc-header-alist' in CPerl."
213 :type '(repeat (list symbol string))
214 :group 'cperl)
215
216(defcustom cperl-info-on-command-no-prompt nil
f83d2997
KH
217 "*Not-nil (and non-null) means not to prompt on C-h f.
218The opposite behaviour is always available if prefixed with C-c.
ccc3ce39
SE
219Can be overwritten by `cperl-hairy' if nil."
220 :type 'boolean
221 :group 'cperl)
f83d2997 222
ccc3ce39
SE
223(defcustom cperl-lazy-help-time nil
224 "*Not-nil (and non-null) means to show lazy help after given idle time."
225 :type 'boolean
226 :group 'cperl)
f83d2997 227
ccc3ce39
SE
228(defcustom cperl-pod-face 'font-lock-comment-face
229 "*The result of evaluation of this expression is used for pod highlighting."
230 :type 'face
231 :group 'cperl)
f83d2997 232
ccc3ce39 233(defcustom cperl-pod-head-face 'font-lock-variable-name-face
f83d2997 234 "*The result of evaluation of this expression is used for pod highlighting.
ccc3ce39
SE
235Font for POD headers."
236 :type 'face
237 :group 'cperl)
f83d2997 238
ccc3ce39
SE
239(defcustom cperl-here-face 'font-lock-string-face
240 "*The result of evaluation of this expression is used for here-docs highlighting."
241 :type 'face
242 :group 'cperl)
f83d2997 243
ccc3ce39
SE
244(defcustom cperl-pod-here-fontify '(featurep 'font-lock)
245 "*Not-nil after evaluation means to highlight pod and here-docs sections."
246 :type 'boolean
247 :group 'cperl)
f83d2997 248
ccc3ce39 249(defcustom cperl-pod-here-scan t
f83d2997 250 "*Not-nil means look for pod and here-docs sections during startup.
ccc3ce39
SE
251You can always make lookup from menu or using \\[cperl-find-pods-heres]."
252 :type 'boolean
253 :group 'cperl)
f83d2997 254
ccc3ce39 255(defcustom cperl-imenu-addback nil
f83d2997 256 "*Not-nil means add backreferences to generated `imenu's.
ccc3ce39
SE
257May require patched `imenu' and `imenu-go'."
258 :type 'boolean
259 :group 'cperl)
f83d2997 260
ccc3ce39
SE
261(defcustom cperl-max-help-size 66
262 "*Non-nil means shrink-wrapping of info-buffer allowed up to these percents."
263 :type '(choice integer (const nil))
264 :group 'cperl)
f83d2997 265
ccc3ce39
SE
266(defcustom cperl-shrink-wrap-info-frame t
267 "*Non-nil means shrink-wrapping of info-buffer-frame allowed."
268 :type 'boolean
269 :group 'cperl)
f83d2997 270
ccc3ce39 271(defcustom cperl-info-page "perl"
f83d2997 272 "*Name of the info page containing perl docs.
ccc3ce39
SE
273Older version of this page was called `perl5', newer `perl'."
274 :type 'string
275 :group 'cperl)
f83d2997 276
ccc3ce39 277(defcustom cperl-use-syntax-table-text-property
f83d2997 278 (boundp 'parse-sexp-lookup-properties)
ccc3ce39
SE
279 "*Non-nil means CPerl sets up and uses `syntax-table' text property."
280 :type 'boolean
281 :group 'cperl)
f83d2997 282
ccc3ce39 283(defcustom cperl-use-syntax-table-text-property-for-tags
f83d2997 284 cperl-use-syntax-table-text-property
ccc3ce39
SE
285 "*Non-nil means: set up and use `syntax-table' text property generating TAGS."
286 :type 'boolean
287 :group 'cperl)
288
289(defcustom cperl-scan-files-regexp "\\.\\([pP][Llm]\\|xs\\)$"
290 "*Regexp to match files to scan when generating TAGS."
291 :type 'regexp
292 :group 'cperl)
293
294(defcustom cperl-noscan-files-regexp "/\\(\\.\\.?\\|SCCS\\|RCS\\|blib\\)$"
295 "*Regexp to match files/dirs to skip when generating TAGS."
296 :type 'regexp
297 :group 'cperl)
298
299(defcustom cperl-regexp-indent-step nil
300 "*Indentation used when beautifying regexps.
301If `nil', the value of `cperl-indent-level' will be used."
302 :type '(choice integer (const nil))
303 :group 'cperl)
304
305(defcustom cperl-indent-left-aligned-comments t
306 "*Non-nil means that the comment starting in leftmost column should indent."
307 :type 'boolean
308 :group 'cperl)
309
310(defcustom cperl-under-as-char t
311 "*Non-nil means that the _ (underline) should be treated as word char."
312 :type 'boolean
313 :group 'cperl)
f83d2997
KH
314
315\f
316
317;;; Short extra-docs.
318
319(defvar cperl-tips 'please-ignore-this-line
320 "Get newest version of this package from
321 ftp://ftp.math.ohio-state.edu/pub/users/ilya/emacs
322and/or
323 ftp://ftp.math.ohio-state.edu/pub/users/ilya/perl
324
325Get support packages choose-color.el (or font-lock-extra.el before
32619.30), imenu-go.el from the same place. \(Look for other files there
327too... ;-). Get a patch for imenu.el in 19.29. Note that for 19.30 and
328later you should use choose-color.el *instead* of font-lock-extra.el
329\(and you will not get smart highlighting in C :-().
330
331Note that to enable Compile choices in the menu you need to install
332mode-compile.el.
333
334Get perl5-info from
335 $CPAN/doc/manual/info/perl-info.tar.gz
336older version was on
337 http://www.metronet.com:70/9/perlinfo/perl5/manual/perl5-info.tar.gz
338
339If you use imenu-go, run imenu on perl5-info buffer (you can do it
340from CPerl menu). If many files are related, generate TAGS files from
341Tools/Tags submenu in CPerl menu.
342
343If some class structure is too complicated, use Tools/Hierarchy-view
344from CPerl menu, or hierarchic view of imenu. The second one uses the
345current buffer only, the first one requires generation of TAGS from
346CPerl/Tools/Tags menu beforehand.
347
348Run CPerl/Tools/Insert-spaces-if-needed to fix your lazy typing.
349
350Switch auto-help on/off with CPerl/Tools/Auto-help.
351
352Before reporting (non-)problems look in the problem section on what I
353know about them.")
354
355(defvar cperl-problems 'please-ignore-this-line
356"Emacs has a _very_ restricted syntax parsing engine.
357
358It may be corrected on the level of C code, please look in the
359`non-problems' section if you want to volunteer.
360
361CPerl mode tries to corrects some Emacs misunderstandings, however,
362for efficiency reasons the degree of correction is different for
363different operations. The partially corrected problems are: POD
364sections, here-documents, regexps. The operations are: highlighting,
365indentation, electric keywords, electric braces.
366
367This may be confusing, since the regexp s#//#/#\; may be highlighted
368as a comment, but it will be recognized as a regexp by the indentation
369code. Or the opposite case, when a pod section is highlighted, but
370may break the indentation of the following code (though indentation
371should work if the balance of delimiters is not broken by POD).
372
373The main trick (to make $ a \"backslash\") makes constructions like
374${aaa} look like unbalanced braces. The only trick I can think of is
375to insert it as $ {aaa} (legal in perl5, not in perl4).
376
377Similar problems arise in regexps, when /(\\s|$)/ should be rewritten
378as /($|\\s)/. Note that such a transposition is not always possible
379:-(. " )
380
381(defvar cperl-non-problems 'please-ignore-this-line
382"As you know from `problems' section, Perl syntax is too hard for CPerl.
383
384Most the time, if you write your own code, you may find an equivalent
385\(and almost as readable) expression.
386
387Try to help CPerl: add comments with embedded quotes to fix CPerl
388misunderstandings about the end of quotation:
389
390$a='500$'; # ';
391
392You won't need it too often. The reason: $ \"quotes\" the following
393character (this saves a life a lot of times in CPerl), thus due to
394Emacs parsing rules it does not consider tick (i.e., ' ) after a
395dollar as a closing one, but as a usual character.
396
397Now the indentation code is pretty wise. The only drawback is that it
398relies on Emacs parsing to find matching parentheses. And Emacs
399*cannot* match parentheses in Perl 100% correctly. So
400 1 if s#//#/#;
401will not break indentation, but
402 1 if ( s#//#/# );
403will.
404
405By similar reasons
406 s\"abc\"def\";
407will confuse CPerl a lot.
408
409If you still get wrong indentation in situation that you think the
410code should be able to parse, try:
411
412a) Check what Emacs thinks about balance of your parentheses.
413b) Supply the code to me (IZ).
414
415Pods are treated _very_ rudimentally. Here-documents are not treated
416at all (except highlighting and inhibiting indentation). (This may
417change some time. RMS approved making syntax lookup recognize text
418attributes, but volunteers are needed to change Emacs C code.)
419
420To speed up coloring the following compromises exist:
421 a) sub in $mypackage::sub may be highlighted.
422 b) -z in [a-z] may be highlighted.
423 c) if your regexp contains a keyword (like \"s\"), it may be highlighted.
424
425
426Imenu in 19.31 is broken. Set `imenu-use-keymap-menu' to t, and remove
427`car' before `imenu-choose-buffer-index' in `imenu'.
428")
429
430(defvar cperl-praise 'please-ignore-this-line
431 "RMS asked me to list good things about CPerl. Here they go:
432
4330) It uses the newest `syntax-table' property ;-);
434
4351) It does 99% of Perl syntax correct (as opposed to 80-90% in Perl
436mode - but the latter number may have improved too in last years) even
437without `syntax-table' property; When using this property, it should
438handle 99.995% of lines correct - or somesuch.
439
4402) It is generally belived to be \"the most user-friendly Emacs
441package\" whatever it may mean (I doubt that the people who say similar
442things tried _all_ the rest of Emacs ;-), but this was not a lonely
443voice);
444
4453) Everything is customizable, one-by-one or in a big sweep;
446
4474) It has many easily-accessable \"tools\":
448 a) Can run program, check syntax, start debugger;
449 b) Can lineup vertically \"middles\" of rows, like `=' in
450 a = b;
451 cc = d;
452 c) Can insert spaces where this impoves readability (in one
453 interactive sweep over the buffer);
454 d) Has support for imenu, including:
455 1) Separate unordered list of \"interesting places\";
456 2) Separate TOC of POD sections;
457 3) Separate list of packages;
458 4) Hierarchical view of methods in (sub)packages;
459 5) and functions (by the full name - with package);
460 e) Has an interface to INFO docs for Perl; The interface is
461 very flexible, including shrink-wrapping of
462 documentation buffer/frame;
463 f) Has a builtin list of one-line explanations for perl constructs.
464 g) Can show these explanations if you stay long enough at the
465 corresponding place (or on demand);
466 h) Has an enhanced fontification (using 3 or 4 additional faces
467 comparing to font-lock - basically, different
468 namespaces in Perl have different colors);
469 i) Can construct TAGS basing on its knowledge of Perl syntax,
470 the standard menu has 6 different way to generate
471 TAGS (if by directory, .xs files - with C-language
472 bindings - are included in the scan);
473 j) Can build a hierarchical view of classes (via imenu) basing
474 on generated TAGS file;
475 k) Has electric parentheses, electric newlines, uses Abbrev
476 for electric logical constructs
477 while () {}
478 with different styles of expansion (context sensitive
479 to be not so bothering). Electric parentheses behave
480 \"as they should\" in a presence of a visible region.
481 l) Changes msb.el \"on the fly\" to insert a group \"Perl files\";
482
4835) The indentation engine was very smart, but most of tricks may be
484not needed anymore with the support for `syntax-table' property. Has
485progress indicator for indentation (with `imenu' loaded).
486
4876) Indent-region improves inline-comments as well;
488
4897) Fill-paragraph correctly handles multi-line comments;
490")
491
492\f
493
494;;; Portability stuff:
495
496(defmacro cperl-define-key (emacs-key definition &optional xemacs-key)
497 (` (define-key cperl-mode-map
498 (, (if xemacs-key
499 (` (if cperl-xemacs-p (, xemacs-key) (, emacs-key)))
500 emacs-key))
501 (, definition))))
502
503(defvar cperl-del-back-ch
504 (car (append (where-is-internal 'delete-backward-char)
505 (where-is-internal 'backward-delete-char-untabify)))
506 "Character generated by key bound to delete-backward-char.")
507
508(and (vectorp cperl-del-back-ch) (= (length cperl-del-back-ch) 1)
509 (setq cperl-del-back-ch (aref cperl-del-back-ch 0)))
510
511(if cperl-xemacs-p
512 (progn
513 ;; "Active regions" are on: use region only if active
514 ;; "Active regions" are off: use region unconditionally
515 (defun cperl-use-region-p ()
516 (if zmacs-regions (mark) t))
517 (defun cperl-mark-active () (mark)))
518 (defun cperl-use-region-p ()
519 (if transient-mark-mode mark-active t))
520 (defun cperl-mark-active () mark-active))
521
522(defsubst cperl-enable-font-lock ()
523 (or cperl-xemacs-p window-system))
524
525(if (boundp 'unread-command-events)
526 (if cperl-xemacs-p
527 (defun cperl-putback-char (c) ; XEmacs >= 19.12
528 (setq unread-command-events (list (character-to-event c))))
529 (defun cperl-putback-char (c) ; Emacs 19
530 (setq unread-command-events (list c))))
531 (defun cperl-putback-char (c) ; XEmacs <= 19.11
532 (setq unread-command-event (character-to-event c))))
533
534(or (fboundp 'uncomment-region)
535 (defun uncomment-region (beg end)
536 (interactive "r")
537 (comment-region beg end -1)))
538
539(defvar cperl-do-not-fontify
540 (if (string< emacs-version "19.30")
541 'fontified
542 'lazy-lock)
543 "Text property which inhibits refontification.")
544
545(defsubst cperl-put-do-not-fontify (from to)
546 (put-text-property (max (point-min) (1- from))
547 to cperl-do-not-fontify t))
548
ccc3ce39
SE
549(defcustom cperl-mode-hook nil
550 "Hook run by `cperl-mode'."
551 :type 'hook
552 :group 'cperl)
f83d2997
KH
553
554\f
555;;; Probably it is too late to set these guys already, but it can help later:
556
557;;;(setq auto-mode-alist
558;;; (append '(("\\.\\([pP][Llm]\\|al\\)$" . perl-mode)) auto-mode-alist ))
559;;;(and (boundp 'interpreter-mode-alist)
560;;; (setq interpreter-mode-alist (append interpreter-mode-alist
ccc3ce39 561;;; '(("miniperl" . perl-mode)))))
f83d2997
KH
562(if (fboundp 'eval-when-compile)
563 (eval-when-compile
564 (condition-case nil
565 (require 'imenu)
566 (error nil))
567 (condition-case nil
568 (require 'easymenu)
569 (error nil))
570 ;; Calling `cperl-enable-font-lock' below doesn't compile on XEmacs,
571 ;; macros instead of defsubsts don't work on Emacs, so we do the
572 ;; expansion manually. Any other suggestions?
573 (if (or (string-match "XEmacs\\|Lucid" emacs-version)
574 window-system)
575 (require 'font-lock))
576 (require 'cl)
577 ))
578
579(defvar cperl-mode-abbrev-table nil
580 "Abbrev table in use in Cperl-mode buffers.")
581
582(add-hook 'edit-var-mode-alist '(perl-mode (regexp . "^cperl-")))
583
584(defvar cperl-mode-map () "Keymap used in CPerl mode.")
585
586(if cperl-mode-map nil
587 (setq cperl-mode-map (make-sparse-keymap))
588 (cperl-define-key "{" 'cperl-electric-lbrace)
589 (cperl-define-key "[" 'cperl-electric-paren)
590 (cperl-define-key "(" 'cperl-electric-paren)
591 (cperl-define-key "<" 'cperl-electric-paren)
592 (cperl-define-key "}" 'cperl-electric-brace)
593 (cperl-define-key "]" 'cperl-electric-rparen)
594 (cperl-define-key ")" 'cperl-electric-rparen)
595 (cperl-define-key ";" 'cperl-electric-semi)
596 (cperl-define-key ":" 'cperl-electric-terminator)
597 (cperl-define-key "\C-j" 'newline-and-indent)
598 (cperl-define-key "\C-c\C-j" 'cperl-linefeed)
599 (cperl-define-key "\C-c\C-a" 'cperl-toggle-auto-newline)
600 (cperl-define-key "\C-c\C-k" 'cperl-toggle-abbrev)
601 (cperl-define-key "\C-c\C-e" 'cperl-toggle-electric)
602 (cperl-define-key "\e\C-q" 'cperl-indent-exp) ; Usually not bound
603 (cperl-define-key [?\C-\M-\|] 'cperl-lineup
604 [(control meta |)])
605 ;;(cperl-define-key "\M-q" 'cperl-fill-paragraph)
606 ;;(cperl-define-key "\e;" 'cperl-indent-for-comment)
607 (cperl-define-key "\177" 'cperl-electric-backspace)
608 (cperl-define-key "\t" 'cperl-indent-command)
609 ;; don't clobber the backspace binding:
610 (cperl-define-key "\C-c\C-hf" 'cperl-info-on-current-command
611 [(control c) (control h) f])
612 (cperl-define-key "\C-hf"
613 ;;(concat (char-to-string help-char) "f") ; does not work
614 'cperl-info-on-command
615 [(control h) f])
616 (cperl-define-key "\C-hv"
617 ;;(concat (char-to-string help-char) "v") ; does not work
618 'cperl-get-help
619 [(control h) v])
620 (if (and cperl-xemacs-p
621 (<= emacs-minor-version 11) (<= emacs-major-version 19))
622 (progn
623 ;; substitute-key-definition is usefulness-deenhanced...
624 (cperl-define-key "\M-q" 'cperl-fill-paragraph)
625 (cperl-define-key "\e;" 'cperl-indent-for-comment)
626 (cperl-define-key "\e\C-\\" 'cperl-indent-region))
627 (substitute-key-definition
628 'indent-sexp 'cperl-indent-exp
629 cperl-mode-map global-map)
630 (substitute-key-definition
631 'fill-paragraph 'cperl-fill-paragraph
632 cperl-mode-map global-map)
633 (substitute-key-definition
634 'indent-region 'cperl-indent-region
635 cperl-mode-map global-map)
636 (substitute-key-definition
637 'indent-for-comment 'cperl-indent-for-comment
638 cperl-mode-map global-map)))
639
640(defvar cperl-menu)
641(condition-case nil
642 (progn
643 (require 'easymenu)
644 (easy-menu-define cperl-menu cperl-mode-map "Menu for CPerl mode"
645 '("Perl"
646 ["Beginning of function" beginning-of-defun t]
647 ["End of function" end-of-defun t]
648 ["Mark function" mark-defun t]
649 ["Indent expression" cperl-indent-exp t]
650 ["Fill paragraph/comment" cperl-fill-paragraph t]
651 "----"
652 ["Line up a construction" cperl-lineup (cperl-use-region-p)]
653 ["Beautify a regexp" cperl-beautify-regexp
654 cperl-use-syntax-table-text-property]
655 ["Beautify a group in regexp" cperl-beautify-level
656 cperl-use-syntax-table-text-property]
657 ["Contract a group in regexp" cperl-contract-level
658 cperl-use-syntax-table-text-property]
659 ["Refresh \"hard\" constructions" cperl-find-pods-heres t]
660 "----"
661 ["Indent region" cperl-indent-region (cperl-use-region-p)]
662 ["Comment region" cperl-comment-region (cperl-use-region-p)]
663 ["Uncomment region" cperl-uncomment-region (cperl-use-region-p)]
664 "----"
665 ["Run" mode-compile (fboundp 'mode-compile)]
666 ["Kill" mode-compile-kill (and (fboundp 'mode-compile-kill)
667 (get-buffer "*compilation*"))]
668 ["Next error" next-error (get-buffer "*compilation*")]
669 ["Check syntax" cperl-check-syntax (fboundp 'mode-compile)]
670 "----"
671 ["Debugger" cperl-db t]
672 "----"
673 ("Tools"
674 ["Imenu" imenu (fboundp 'imenu)]
675 ["Insert spaces if needed" cperl-find-bad-style t]
676 ["Class Hierarchy from TAGS" cperl-tags-hier-init t]
677 ;;["Update classes" (cperl-tags-hier-init t) tags-table-list]
678 ["Imenu on info" cperl-imenu-on-info (featurep 'imenu)]
679 ("Tags"
680;;; ["Create tags for current file" cperl-etags t]
681;;; ["Add tags for current file" (cperl-etags t) t]
682;;; ["Create tags for Perl files in directory" (cperl-etags nil t) t]
683;;; ["Add tags for Perl files in directory" (cperl-etags t t) t]
684;;; ["Create tags for Perl files in (sub)directories"
685;;; (cperl-etags nil 'recursive) t]
686;;; ["Add tags for Perl files in (sub)directories"
687;;; (cperl-etags t 'recursive) t])
688;;;; cperl-write-tags (&optional file erase recurse dir inbuffer)
689 ["Create tags for current file" (cperl-write-tags nil t) t]
690 ["Add tags for current file" (cperl-write-tags) t]
691 ["Create tags for Perl files in directory"
692 (cperl-write-tags nil t nil t) t]
693 ["Add tags for Perl files in directory"
694 (cperl-write-tags nil nil nil t) t]
695 ["Create tags for Perl files in (sub)directories"
696 (cperl-write-tags nil t t t) t]
697 ["Add tags for Perl files in (sub)directories"
698 (cperl-write-tags nil nil t t) t])
699 ["Define word at point" imenu-go-find-at-position
700 (fboundp 'imenu-go-find-at-position)]
701 ["Help on function" cperl-info-on-command t]
702 ["Help on function at point" cperl-info-on-current-command t]
703 ["Help on symbol at point" cperl-get-help t]
704 ["Auto-help on" cperl-lazy-install (fboundp 'run-with-idle-timer)]
705 ["Auto-help off" cperl-lazy-unstall
706 (fboundp 'run-with-idle-timer)])
707 ("Toggle..."
708 ["Auto newline" cperl-toggle-auto-newline t]
709 ["Electric parens" cperl-toggle-electric t]
710 ["Electric keywords" cperl-toggle-abbrev t]
711 )
712 ("Indent styles..."
713 ["GNU" (cperl-set-style "GNU") t]
714 ["C++" (cperl-set-style "C++") t]
715 ["FSF" (cperl-set-style "FSF") t]
716 ["BSD" (cperl-set-style "BSD") t]
717 ["Whitesmith" (cperl-set-style "Whitesmith") t])
718 ("Micro-docs"
719 ["Tips" (describe-variable 'cperl-tips) t]
720 ["Problems" (describe-variable 'cperl-problems) t]
721 ["Non-problems" (describe-variable 'cperl-non-problems) t]
722 ["Praise" (describe-variable 'cperl-praise) t]))))
723 (error nil))
724
725(autoload 'c-macro-expand "cmacexp"
726 "Display the result of expanding all C macros occurring in the region.
727The expansion is entirely correct because it uses the C preprocessor."
728 t)
729
730(defvar cperl-mode-syntax-table nil
731 "Syntax table in use in Cperl-mode buffers.")
732
733(defvar cperl-string-syntax-table nil
734 "Syntax table in use in Cperl-mode string-like chunks.")
735
736(if cperl-mode-syntax-table
737 ()
738 (setq cperl-mode-syntax-table (make-syntax-table))
739 (modify-syntax-entry ?\\ "\\" cperl-mode-syntax-table)
740 (modify-syntax-entry ?/ "." cperl-mode-syntax-table)
741 (modify-syntax-entry ?* "." cperl-mode-syntax-table)
742 (modify-syntax-entry ?+ "." cperl-mode-syntax-table)
743 (modify-syntax-entry ?- "." cperl-mode-syntax-table)
744 (modify-syntax-entry ?= "." cperl-mode-syntax-table)
745 (modify-syntax-entry ?% "." cperl-mode-syntax-table)
746 (modify-syntax-entry ?< "." cperl-mode-syntax-table)
747 (modify-syntax-entry ?> "." cperl-mode-syntax-table)
748 (modify-syntax-entry ?& "." cperl-mode-syntax-table)
749 (modify-syntax-entry ?$ "\\" cperl-mode-syntax-table)
750 (modify-syntax-entry ?\n ">" cperl-mode-syntax-table)
751 (modify-syntax-entry ?# "<" cperl-mode-syntax-table)
752 (modify-syntax-entry ?' "\"" cperl-mode-syntax-table)
753 (modify-syntax-entry ?` "\"" cperl-mode-syntax-table)
754 (if cperl-under-as-char
755 (modify-syntax-entry ?_ "w" cperl-mode-syntax-table))
756 (modify-syntax-entry ?: "_" cperl-mode-syntax-table)
757 (modify-syntax-entry ?| "." cperl-mode-syntax-table)
758 (setq cperl-string-syntax-table (copy-syntax-table cperl-mode-syntax-table))
759 (modify-syntax-entry ?$ "." cperl-string-syntax-table)
760 (modify-syntax-entry ?# "." cperl-string-syntax-table) ; (?# comment )
761)
762
763
764\f
765;; Make customization possible "in reverse"
766;;(defun cperl-set (symbol to)
767;; (or (eq (symbol-value symbol) 'null) (set symbol to)))
768(defsubst cperl-val (symbol &optional default hairy)
769 (cond
770 ((eq (symbol-value symbol) 'null) default)
771 (cperl-hairy (or hairy t))
772 (t (symbol-value symbol))))
773\f
774;; provide an alias for working with emacs 19. the perl-mode that comes
775;; with it is really bad, and this lets us seamlessly replace it.
776;;;###autoload
777(fset 'perl-mode 'cperl-mode)
778(defvar cperl-faces-init)
779;; Fix for msb.el
780(defvar cperl-msb-fixed nil)
781;;;###autoload
782(defun cperl-mode ()
783 "Major mode for editing Perl code.
784Expression and list commands understand all C brackets.
785Tab indents for Perl code.
786Paragraphs are separated by blank lines only.
787Delete converts tabs to spaces as it moves back.
788
789Various characters in Perl almost always come in pairs: {}, (), [],
790sometimes <>. When the user types the first, she gets the second as
791well, with optional special formatting done on {}. (Disabled by
792default.) You can always quote (with \\[quoted-insert]) the left
793\"paren\" to avoid the expansion. The processing of < is special,
794since most the time you mean \"less\". Cperl mode tries to guess
795whether you want to type pair <>, and inserts is if it
796appropriate. You can set `cperl-electric-parens-string' to the string that
797contains the parenths from the above list you want to be electrical.
798Electricity of parenths is controlled by `cperl-electric-parens'.
799You may also set `cperl-electric-parens-mark' to have electric parens
800look for active mark and \"embrace\" a region if possible.'
801
802CPerl mode provides expansion of the Perl control constructs:
803 if, else, elsif, unless, while, until, for, and foreach.
804=========(Disabled by default, see `cperl-electric-keywords'.)
805The user types the keyword immediately followed by a space, which causes
806the construct to be expanded, and the user is positioned where she is most
807likely to want to be.
808eg. when the user types a space following \"if\" the following appears in
809the buffer:
810 if () { or if ()
811 } {
812 }
813and the cursor is between the parentheses. The user can then type some
814boolean expression within the parens. Having done that, typing
815\\[cperl-linefeed] places you, appropriately indented on a new line
816between the braces. If CPerl decides that you want to insert
817\"English\" style construct like
818 bite if angry;
819it will not do any expansion. See also help on variable
820`cperl-extra-newline-before-brace'.
821
822\\[cperl-linefeed] is a convenience replacement for typing carriage
823return. It places you in the next line with proper indentation, or if
824you type it inside the inline block of control construct, like
825 foreach (@lines) {print; print}
826and you are on a boundary of a statement inside braces, it will
827transform the construct into a multiline and will place you into an
828appropriately indented blank line. If you need a usual
829`newline-and-indent' behaviour, it is on \\[newline-and-indent],
830see documentation on `cperl-electric-linefeed'.
831
832\\{cperl-mode-map}
833
834Setting the variable `cperl-font-lock' to t switches on
835font-lock-mode, `cperl-electric-lbrace-space' to t switches on
836electric space between $ and {, `cperl-electric-parens-string' is the
837string that contains parentheses that should be electric in CPerl (see
838also `cperl-electric-parens-mark' and `cperl-electric-parens'),
839setting `cperl-electric-keywords' enables electric expansion of
840control structures in CPerl. `cperl-electric-linefeed' governs which
841one of two linefeed behavior is preferable. You can enable all these
842options simultaneously (recommended mode of use) by setting
843`cperl-hairy' to t. In this case you can switch separate options off
844by setting them to `null'. Note that one may undo the extra whitespace
845inserted by semis and braces in `auto-newline'-mode by consequent
846\\[cperl-electric-backspace].
847
848If your site has perl5 documentation in info format, you can use commands
849\\[cperl-info-on-current-command] and \\[cperl-info-on-command] to access it.
850These keys run commands `cperl-info-on-current-command' and
851`cperl-info-on-command', which one is which is controlled by variable
852`cperl-info-on-command-no-prompt' (in turn affected by `cperl-hairy').
853
854Even if you have no info-format documentation, short one-liner-style
855help is available on \\[cperl-get-help].
856
857It is possible to show this help automatically after some idle
858time. This is regulated by variable `cperl-lazy-help-time'. Default
859with `cperl-hairy' is 5 secs idle time if the value of this variable
860is nil. It is also possible to switch this on/off from the
861menu. Requires `run-with-idle-timer'.
862
863Use \\[cperl-lineup] to vertically lineup some construction - put the
864beginning of the region at the start of construction, and make region
865span the needed amount of lines.
866
867Variables `cperl-pod-here-scan', `cperl-pod-here-fontify',
868`cperl-pod-face', `cperl-pod-head-face' control processing of pod and
869here-docs sections. In a future version results of scan may be used
870for indentation too, currently they are used for highlighting only.
871
872Variables controlling indentation style:
873 `cperl-tab-always-indent'
874 Non-nil means TAB in CPerl mode should always reindent the current line,
875 regardless of where in the line point is when the TAB command is used.
876 `cperl-auto-newline'
877 Non-nil means automatically newline before and after braces,
878 and after colons and semicolons, inserted in Perl code. The following
879 \\[cperl-electric-backspace] will remove the inserted whitespace.
880 Insertion after colons requires both this variable and
881 `cperl-auto-newline-after-colon' set.
882 `cperl-auto-newline-after-colon'
883 Non-nil means automatically newline even after colons.
884 Subject to `cperl-auto-newline' setting.
885 `cperl-indent-level'
886 Indentation of Perl statements within surrounding block.
887 The surrounding block's indentation is the indentation
888 of the line on which the open-brace appears.
889 `cperl-continued-statement-offset'
890 Extra indentation given to a substatement, such as the
891 then-clause of an if, or body of a while, or just a statement continuation.
892 `cperl-continued-brace-offset'
893 Extra indentation given to a brace that starts a substatement.
894 This is in addition to `cperl-continued-statement-offset'.
895 `cperl-brace-offset'
896 Extra indentation for line if it starts with an open brace.
897 `cperl-brace-imaginary-offset'
898 An open brace following other text is treated as if it the line started
899 this far to the right of the actual line indentation.
900 `cperl-label-offset'
901 Extra indentation for line that is a label.
902 `cperl-min-label-indent'
903 Minimal indentation for line that is a label.
904
905Settings for K&R and BSD indentation styles are
906 `cperl-indent-level' 5 8
907 `cperl-continued-statement-offset' 5 8
908 `cperl-brace-offset' -5 -8
909 `cperl-label-offset' -5 -8
910
911If `cperl-indent-level' is 0, the statement after opening brace in column 0 is indented on `cperl-brace-offset'+`cperl-continued-statement-offset'.
912
913Turning on CPerl mode calls the hooks in the variable `cperl-mode-hook'
914with no args."
915 (interactive)
916 (kill-all-local-variables)
917 ;;(if cperl-hairy
918 ;; (progn
919 ;; (cperl-set 'cperl-font-lock cperl-hairy)
920 ;; (cperl-set 'cperl-electric-lbrace-space cperl-hairy)
921 ;; (cperl-set 'cperl-electric-parens "{[(<")
922 ;; (cperl-set 'cperl-electric-keywords cperl-hairy)
923 ;; (cperl-set 'cperl-electric-linefeed cperl-hairy)))
924 (use-local-map cperl-mode-map)
925 (if (cperl-val 'cperl-electric-linefeed)
926 (progn
927 (local-set-key "\C-J" 'cperl-linefeed)
928 (local-set-key "\C-C\C-J" 'newline-and-indent)))
929 (if (cperl-val 'cperl-info-on-command-no-prompt)
930 (progn
931 ;; don't clobber the backspace binding:
932 (cperl-define-key "\C-hf" 'cperl-info-on-current-command [(control h) f])
933 (cperl-define-key "\C-c\C-hf" 'cperl-info-on-command
934 [(control c) (control h) f])))
935 (setq major-mode 'perl-mode)
936 (setq mode-name "CPerl")
937 (if (not cperl-mode-abbrev-table)
938 (let ((prev-a-c abbrevs-changed))
939 (define-abbrev-table 'cperl-mode-abbrev-table '(
940 ("if" "if" cperl-electric-keyword 0)
941 ("elsif" "elsif" cperl-electric-keyword 0)
942 ("while" "while" cperl-electric-keyword 0)
943 ("until" "until" cperl-electric-keyword 0)
944 ("unless" "unless" cperl-electric-keyword 0)
945 ("else" "else" cperl-electric-else 0)
946 ("for" "for" cperl-electric-keyword 0)
947 ("foreach" "foreach" cperl-electric-keyword 0)
948 ("do" "do" cperl-electric-keyword 0)))
949 (setq abbrevs-changed prev-a-c)))
950 (setq local-abbrev-table cperl-mode-abbrev-table)
951 (abbrev-mode (if (cperl-val 'cperl-electric-keywords) 1 0))
952 (set-syntax-table cperl-mode-syntax-table)
953 (make-local-variable 'paragraph-start)
954 (setq paragraph-start (concat "^$\\|" page-delimiter))
955 (make-local-variable 'paragraph-separate)
956 (setq paragraph-separate paragraph-start)
957 (make-local-variable 'paragraph-ignore-fill-prefix)
958 (setq paragraph-ignore-fill-prefix t)
959 (make-local-variable 'indent-line-function)
960 (setq indent-line-function 'cperl-indent-line)
961 (make-local-variable 'require-final-newline)
962 (setq require-final-newline t)
963 (make-local-variable 'comment-start)
964 (setq comment-start "# ")
965 (make-local-variable 'comment-end)
966 (setq comment-end "")
967 (make-local-variable 'comment-column)
968 (setq comment-column cperl-comment-column)
969 (make-local-variable 'comment-start-skip)
970 (setq comment-start-skip "#+ *")
971 (make-local-variable 'defun-prompt-regexp)
972 (setq defun-prompt-regexp "^[ \t]*sub[ \t]+\\([^ \t\n{(;]+\\)[ \t]*")
973 (make-local-variable 'comment-indent-function)
974 (setq comment-indent-function 'cperl-comment-indent)
975 (make-local-variable 'parse-sexp-ignore-comments)
976 (setq parse-sexp-ignore-comments t)
977 (make-local-variable 'indent-region-function)
978 (setq indent-region-function 'cperl-indent-region)
979 ;;(setq auto-fill-function 'cperl-do-auto-fill) ; Need to switch on and off!
980 (make-local-variable 'imenu-create-index-function)
981 (setq imenu-create-index-function
982 (function imenu-example--create-perl-index))
983 (make-local-variable 'imenu-sort-function)
984 (setq imenu-sort-function nil)
985 (make-local-variable 'vc-header-alist)
986 (setq vc-header-alist cperl-vc-header-alist)
987 (make-local-variable 'font-lock-defaults)
988 (setq font-lock-defaults
989 (if (string< emacs-version "19.30")
990 '(perl-font-lock-keywords-2)
991 '((perl-font-lock-keywords
992 perl-font-lock-keywords-1
993 perl-font-lock-keywords-2))))
994 (if cperl-use-syntax-table-text-property
995 (progn
996 (make-variable-buffer-local 'parse-sexp-lookup-properties)
997 ;; Do not introduce variable if not needed, we check it!
998 (set 'parse-sexp-lookup-properties t)))
999 (or (fboundp 'cperl-old-auto-fill-mode)
1000 (progn
1001 (fset 'cperl-old-auto-fill-mode (symbol-function 'auto-fill-mode))
1002 (defun auto-fill-mode (&optional arg)
1003 (interactive "P")
1004 (cperl-old-auto-fill-mode arg)
1005 (and auto-fill-function (eq major-mode 'perl-mode)
1006 (setq auto-fill-function 'cperl-do-auto-fill)))))
1007 (if (cperl-enable-font-lock)
1008 (if (cperl-val 'cperl-font-lock)
1009 (progn (or cperl-faces-init (cperl-init-faces))
1010 (font-lock-mode 1))))
1011 (and (boundp 'msb-menu-cond)
1012 (not cperl-msb-fixed)
1013 (cperl-msb-fix))
1014 (if (featurep 'easymenu)
1015 (easy-menu-add cperl-menu)) ; A NOP in Emacs.
1016 (run-hooks 'cperl-mode-hook)
1017 ;; After hooks since fontification will break this
1018 (if cperl-pod-here-scan (cperl-find-pods-heres)))
1019\f
1020;; Fix for perldb - make default reasonable
1021(defun cperl-db ()
1022 (interactive)
1023 (require 'gud)
1024 (perldb (read-from-minibuffer "Run perldb (like this): "
1025 (if (consp gud-perldb-history)
1026 (car gud-perldb-history)
1027 (concat "perl " ;;(file-name-nondirectory
1028 ;; I have problems
1029 ;; in OS/2
1030 ;; otherwise
1031 (buffer-file-name)))
1032 nil nil
1033 '(gud-perldb-history . 1))))
1034\f
1035
1036(defun cperl-msb-fix ()
1037 ;; Adds perl files to msb menu, supposes that msb is already loaded
1038 (setq cperl-msb-fixed t)
1039 (let* ((l (length msb-menu-cond))
1040 (last (nth (1- l) msb-menu-cond))
1041 (precdr (nthcdr (- l 2) msb-menu-cond)) ; cdr of this is last
1042 (handle (1- (nth 1 last))))
1043 (setcdr precdr (list
1044 (list
1045 '(eq major-mode 'perl-mode)
1046 handle
1047 "Perl Files (%d)")
1048 last))))
1049\f
1050;; This is used by indent-for-comment
1051;; to decide how much to indent a comment in CPerl code
1052;; based on its context. Do fallback if comment is found wrong.
1053
1054(defvar cperl-wrong-comment)
1055
1056(defun cperl-comment-indent ()
1057 (let ((p (point)) (c (current-column)) was)
1058 (if (looking-at "^#") 0 ; Existing comment at bol stays there.
1059 ;; Wrong comment found
1060 (save-excursion
1061 (setq was (cperl-to-comment-or-eol))
1062 (if (= (point) p)
1063 (progn
1064 (skip-chars-backward " \t")
1065 (max (1+ (current-column)) ; Else indent at comment column
1066 comment-column))
1067 (if was nil
1068 (insert comment-start)
1069 (backward-char (length comment-start)))
1070 (setq cperl-wrong-comment t)
1071 (indent-to comment-column 1) ; Indent minimum 1
1072 c))))) ; except leave at least one space.
1073
1074;;;(defun cperl-comment-indent-fallback ()
1075;;; "Is called if the standard comment-search procedure fails.
1076;;;Point is at start of real comment."
1077;;; (let ((c (current-column)) target cnt prevc)
1078;;; (if (= c comment-column) nil
1079;;; (setq cnt (skip-chars-backward "[ \t]"))
1080;;; (setq target (max (1+ (setq prevc
1081;;; (current-column))) ; Else indent at comment column
1082;;; comment-column))
1083;;; (if (= c comment-column) nil
1084;;; (delete-backward-char cnt)
1085;;; (while (< prevc target)
1086;;; (insert "\t")
1087;;; (setq prevc (current-column)))
1088;;; (if (> prevc target) (progn (delete-char -1) (setq prevc (current-column))))
1089;;; (while (< prevc target)
1090;;; (insert " ")
1091;;; (setq prevc (current-column)))))))
1092
1093(defun cperl-indent-for-comment ()
1094 "Substitute for `indent-for-comment' in CPerl."
1095 (interactive)
1096 (let (cperl-wrong-comment)
1097 (indent-for-comment)
1098 (if cperl-wrong-comment
1099 (progn (cperl-to-comment-or-eol)
1100 (forward-char (length comment-start))))))
1101
1102(defun cperl-comment-region (b e arg)
1103 "Comment or uncomment each line in the region in CPerl mode.
1104See `comment-region'."
1105 (interactive "r\np")
1106 (let ((comment-start "#"))
1107 (comment-region b e arg)))
1108
1109(defun cperl-uncomment-region (b e arg)
1110 "Uncomment or comment each line in the region in CPerl mode.
1111See `comment-region'."
1112 (interactive "r\np")
1113 (let ((comment-start "#"))
1114 (comment-region b e (- arg))))
1115
1116(defvar cperl-brace-recursing nil)
1117
1118(defun cperl-electric-brace (arg &optional only-before)
1119 "Insert character and correct line's indentation.
1120If ONLY-BEFORE and `cperl-auto-newline', will insert newline before the
1121place (even in empty line), but not after. If after \")\" and the inserted
1122char is \"{\", insert extra newline before only if
1123`cperl-extra-newline-before-brace'."
1124 (interactive "P")
1125 (let (insertpos
1126 (other-end (if (and cperl-electric-parens-mark
1127 (cperl-mark-active)
1128 (< (mark) (point)))
1129 (mark)
1130 nil)))
1131 (if (and other-end
1132 (not cperl-brace-recursing)
1133 (cperl-val 'cperl-electric-parens)
1134 (>= (save-excursion (cperl-to-comment-or-eol) (point)) (point)))
1135 ;; Need to insert a matching pair
1136 (progn
1137 (save-excursion
1138 (setq insertpos (point-marker))
1139 (goto-char other-end)
1140 (setq last-command-char ?\{)
1141 (cperl-electric-lbrace arg insertpos))
1142 (forward-char 1))
1143 (if (and (not arg) ; No args, end (of empty line or auto)
1144 (eolp)
1145 (or (and (null only-before)
1146 (save-excursion
1147 (skip-chars-backward " \t")
1148 (bolp)))
1149 (and (eq last-command-char ?\{) ; Do not insert newline
1150 ;; if after ")" and `cperl-extra-newline-before-brace'
1151 ;; is nil, do not insert extra newline.
1152 (not cperl-extra-newline-before-brace)
1153 (save-excursion
1154 (skip-chars-backward " \t")
1155 (eq (preceding-char) ?\))))
1156 (if cperl-auto-newline
1157 (progn (cperl-indent-line) (newline) t) nil)))
1158 (progn
1159 (self-insert-command (prefix-numeric-value arg))
1160 (cperl-indent-line)
1161 (if cperl-auto-newline
1162 (setq insertpos (1- (point))))
1163 (if (and cperl-auto-newline (null only-before))
1164 (progn
1165 (newline)
1166 (cperl-indent-line)))
1167 (save-excursion
1168 (if insertpos (progn (goto-char insertpos)
1169 (search-forward (make-string
1170 1 last-command-char))
1171 (setq insertpos (1- (point)))))
1172 (delete-char -1))))
1173 (if insertpos
1174 (save-excursion
1175 (goto-char insertpos)
1176 (self-insert-command (prefix-numeric-value arg)))
1177 (self-insert-command (prefix-numeric-value arg))))))
1178
1179(defun cperl-electric-lbrace (arg &optional end)
1180 "Insert character, correct line's indentation, correct quoting by space."
1181 (interactive "P")
1182 (let (pos after
1183 (cperl-brace-recursing t)
1184 (cperl-auto-newline cperl-auto-newline)
1185 (other-end (or end
1186 (if (and cperl-electric-parens-mark
1187 (cperl-mark-active)
1188 (> (mark) (point)))
1189 (save-excursion
1190 (goto-char (mark))
1191 (point-marker))
1192 nil))))
1193 (and (cperl-val 'cperl-electric-lbrace-space)
1194 (eq (preceding-char) ?$)
1195 (save-excursion
1196 (skip-chars-backward "$")
1197 (looking-at "\\(\\$\\$\\)*\\$\\([^\\$]\\|$\\)"))
1198 (insert ?\ ))
1199 (if (cperl-after-expr-p nil "{;)") nil (setq cperl-auto-newline nil))
1200 (cperl-electric-brace arg)
1201 (and (cperl-val 'cperl-electric-parens)
1202 (eq last-command-char ?{)
1203 (memq last-command-char
1204 (append cperl-electric-parens-string nil))
1205 (or (if other-end (goto-char (marker-position other-end)))
1206 t)
1207 (setq last-command-char ?} pos (point))
1208 (progn (cperl-electric-brace arg t)
1209 (goto-char pos)))))
1210
1211(defun cperl-electric-paren (arg)
1212 "Insert a matching pair of parentheses."
1213 (interactive "P")
1214 (let ((beg (save-excursion (beginning-of-line) (point)))
1215 (other-end (if (and cperl-electric-parens-mark
1216 (cperl-mark-active)
1217 (> (mark) (point)))
1218 (save-excursion
1219 (goto-char (mark))
1220 (point-marker))
1221 nil)))
1222 (if (and (cperl-val 'cperl-electric-parens)
1223 (memq last-command-char
1224 (append cperl-electric-parens-string nil))
1225 (>= (save-excursion (cperl-to-comment-or-eol) (point)) (point))
1226 ;;(not (save-excursion (search-backward "#" beg t)))
1227 (if (eq last-command-char ?<)
1228 (progn
1229 (and abbrev-mode ; later it is too late, may be after `for'
1230 (expand-abbrev))
1231 (cperl-after-expr-p nil "{;(,:="))
1232 1))
1233 (progn
1234 (self-insert-command (prefix-numeric-value arg))
1235 (if other-end (goto-char (marker-position other-end)))
1236 (insert (make-string
1237 (prefix-numeric-value arg)
1238 (cdr (assoc last-command-char '((?{ .?})
1239 (?[ . ?])
1240 (?( . ?))
1241 (?< . ?>))))))
1242 (forward-char (- (prefix-numeric-value arg))))
1243 (self-insert-command (prefix-numeric-value arg)))))
1244
1245(defun cperl-electric-rparen (arg)
1246 "Insert a matching pair of parentheses if marking is active.
1247If not, or if we are not at the end of marking range, would self-insert."
1248 (interactive "P")
1249 (let ((beg (save-excursion (beginning-of-line) (point)))
1250 (other-end (if (and cperl-electric-parens-mark
1251 (cperl-val 'cperl-electric-parens)
1252 (memq last-command-char
1253 (append cperl-electric-parens-string nil))
1254 (cperl-mark-active)
1255 (< (mark) (point)))
1256 (mark)
1257 nil))
1258 p)
1259 (if (and other-end
1260 (cperl-val 'cperl-electric-parens)
1261 (memq last-command-char '( ?\) ?\] ?\} ?\> ))
1262 (>= (save-excursion (cperl-to-comment-or-eol) (point)) (point))
1263 ;;(not (save-excursion (search-backward "#" beg t)))
1264 )
1265 (progn
1266 (self-insert-command (prefix-numeric-value arg))
1267 (setq p (point))
1268 (if other-end (goto-char other-end))
1269 (insert (make-string
1270 (prefix-numeric-value arg)
1271 (cdr (assoc last-command-char '((?\} . ?\{)
1272 (?\] . ?\[)
1273 (?\) . ?\()
1274 (?\> . ?\<))))))
1275 (goto-char (1+ p)))
1276 (self-insert-command (prefix-numeric-value arg)))))
1277
1278(defun cperl-electric-keyword ()
1279 "Insert a construction appropriate after a keyword."
1280 (let ((beg (save-excursion (beginning-of-line) (point)))
1281 (dollar (and (eq last-command-char ?$)
1282 (eq this-command 'self-insert-command)))
1283 (delete (and (memq last-command-char '(?\ ?\n ?\t ?\f))
1284 (memq this-command '(self-insert-command newline)))))
1285 (and (save-excursion
1286 (backward-sexp 1)
1287 (cperl-after-expr-p nil "{;:"))
1288 (save-excursion
1289 (not
1290 (re-search-backward
1291 "[#\"'`]\\|\\<q\\(\\|[wqx]\\)\\>"
1292 beg t)))
1293 (save-excursion (or (not (re-search-backward "^=" nil t))
1294 (looking-at "=cut")))
1295 (progn
1296 (and dollar (insert " $"))
1297 (cperl-indent-line)
1298 ;;(insert " () {\n}")
1299 (cond
1300 (cperl-extra-newline-before-brace
1301 (insert " ()\n")
1302 (insert "{")
1303 (cperl-indent-line)
1304 (insert "\n")
1305 (cperl-indent-line)
1306 (insert "\n}"))
1307 (t
1308 (insert " () {\n}"))
1309 )
1310 (or (looking-at "[ \t]\\|$") (insert " "))
1311 (cperl-indent-line)
1312 (if dollar (progn (search-backward "$")
1313 (delete-char 1)
1314 (forward-char -1)
1315 (forward-char 1))
1316 (search-backward ")"))
1317 (if delete
1318 (cperl-putback-char cperl-del-back-ch))))))
1319
1320(defun cperl-electric-else ()
1321 "Insert a construction appropriate after a keyword."
1322 (let ((beg (save-excursion (beginning-of-line) (point))))
1323 (and (save-excursion
1324 (backward-sexp 1)
1325 (cperl-after-expr-p nil "{;:"))
1326 (save-excursion
1327 (not
1328 (re-search-backward
1329 "[#\"'`]\\|\\<q\\(\\|[wqx]\\)\\>"
1330 beg t)))
1331 (save-excursion (or (not (re-search-backward "^=" nil t))
1332 (looking-at "=cut")))
1333 (progn
1334 (cperl-indent-line)
1335 ;;(insert " {\n\n}")
1336 (cond
1337 (cperl-extra-newline-before-brace
1338 (insert "\n")
1339 (insert "{")
1340 (cperl-indent-line)
1341 (insert "\n\n}"))
1342 (t
1343 (insert " {\n\n}"))
1344 )
1345 (or (looking-at "[ \t]\\|$") (insert " "))
1346 (cperl-indent-line)
1347 (forward-line -1)
1348 (cperl-indent-line)
1349 (cperl-putback-char cperl-del-back-ch)))))
1350
1351(defun cperl-linefeed ()
1352 "Go to end of line, open a new line and indent appropriately."
1353 (interactive)
1354 (let ((beg (save-excursion (beginning-of-line) (point)))
1355 (end (save-excursion (end-of-line) (point)))
1356 (pos (point)) start)
1357 (if (and ; Check if we need to split:
1358 ; i.e., on a boundary and inside "{...}"
1359 (save-excursion (cperl-to-comment-or-eol)
1360 (>= (point) pos)) ; Not in a comment
1361 (or (save-excursion
1362 (skip-chars-backward " \t" beg)
1363 (forward-char -1)
1364 (looking-at "[;{]")) ; After { or ; + spaces
1365 (looking-at "[ \t]*}") ; Before }
1366 (re-search-forward "\\=[ \t]*;" end t)) ; Before spaces + ;
1367 (save-excursion
1368 (and
1369 (eq (car (parse-partial-sexp pos end -1)) -1)
1370 ; Leave the level of parens
1371 (looking-at "[,; \t]*\\($\\|#\\)") ; Comma to allow anon subr
1372 ; Are at end
1373 (progn
1374 (backward-sexp 1)
1375 (setq start (point-marker))
1376 (<= start pos))))) ; RedundantAre after the
1377 ; start of parens group.
1378 (progn
1379 (skip-chars-backward " \t")
1380 (or (memq (preceding-char) (append ";{" nil))
1381 (insert ";"))
1382 (insert "\n")
1383 (forward-line -1)
1384 (cperl-indent-line)
1385 (goto-char start)
1386 (or (looking-at "{[ \t]*$") ; If there is a statement
1387 ; before, move it to separate line
1388 (progn
1389 (forward-char 1)
1390 (insert "\n")
1391 (cperl-indent-line)))
1392 (forward-line 1) ; We are on the target line
1393 (cperl-indent-line)
1394 (beginning-of-line)
1395 (or (looking-at "[ \t]*}[,; \t]*$") ; If there is a statement
1396 ; after, move it to separate line
1397 (progn
1398 (end-of-line)
1399 (search-backward "}" beg)
1400 (skip-chars-backward " \t")
1401 (or (memq (preceding-char) (append ";{" nil))
1402 (insert ";"))
1403 (insert "\n")
1404 (cperl-indent-line)
1405 (forward-line -1)))
1406 (forward-line -1) ; We are on the line before target
1407 (end-of-line)
1408 (newline-and-indent))
1409 (end-of-line) ; else
1410 (cond
1411 ((and (looking-at "\n[ \t]*{$")
1412 (save-excursion
1413 (skip-chars-backward " \t")
1414 (eq (preceding-char) ?\)))) ; Probably if () {} group
1415 ; with an extra newline.
1416 (forward-line 2)
1417 (cperl-indent-line))
1418 ((looking-at "\n[ \t]*$") ; Next line is empty - use it.
1419 (forward-line 1)
1420 (cperl-indent-line))
1421 (t
1422 (newline-and-indent))))))
1423
1424(defun cperl-electric-semi (arg)
1425 "Insert character and correct line's indentation."
1426 (interactive "P")
1427 (if cperl-auto-newline
1428 (cperl-electric-terminator arg)
1429 (self-insert-command (prefix-numeric-value arg))))
1430
1431(defun cperl-electric-terminator (arg)
1432 "Insert character and correct line's indentation."
1433 (interactive "P")
1434 (let (insertpos (end (point))
1435 (auto (and cperl-auto-newline
1436 (or (not (eq last-command-char ?:))
1437 cperl-auto-newline-after-colon))))
1438 (if (and ;;(not arg)
1439 (eolp)
1440 (not (save-excursion
1441 (beginning-of-line)
1442 (skip-chars-forward " \t")
1443 (or
1444 ;; Ignore in comment lines
1445 (= (following-char) ?#)
1446 ;; Colon is special only after a label
1447 ;; So quickly rule out most other uses of colon
1448 ;; and do no indentation for them.
1449 (and (eq last-command-char ?:)
1450 (save-excursion
1451 (forward-word 1)
1452 (skip-chars-forward " \t")
1453 (and (< (point) end)
1454 (progn (goto-char (- end 1))
1455 (not (looking-at ":"))))))
1456 (progn
1457 (beginning-of-defun)
1458 (let ((pps (parse-partial-sexp (point) end)))
1459 (or (nth 3 pps) (nth 4 pps) (nth 5 pps))))))))
1460 (progn
1461 (self-insert-command (prefix-numeric-value arg))
1462 ;;(forward-char -1)
1463 (if auto (setq insertpos (point-marker)))
1464 ;;(forward-char 1)
1465 (cperl-indent-line)
1466 (if auto
1467 (progn
1468 (newline)
1469 (cperl-indent-line)))
1470;; (save-excursion
1471;; (if insertpos (progn (goto-char (marker-position insertpos))
1472;; (search-forward (make-string
1473;; 1 last-command-char))
1474;; (setq insertpos (1- (point)))))
1475;; (delete-char -1))))
1476 (save-excursion
1477 (if insertpos (goto-char (1- (marker-position insertpos)))
1478 (forward-char -1))
1479 (delete-char 1))))
1480 (if insertpos
1481 (save-excursion
1482 (goto-char insertpos)
1483 (self-insert-command (prefix-numeric-value arg)))
1484 (self-insert-command (prefix-numeric-value arg)))))
1485
1486(defun cperl-electric-backspace (arg)
1487 "Backspace-untabify, or remove the whitespace inserted by an electric key."
1488 (interactive "p")
1489 (if (and cperl-auto-newline
1490 (memq last-command '(cperl-electric-semi
1491 cperl-electric-terminator
1492 cperl-electric-lbrace))
1493 (memq (preceding-char) '(?\ ?\t ?\n)))
1494 (let (p)
1495 (if (eq last-command 'cperl-electric-lbrace)
1496 (skip-chars-forward " \t\n"))
1497 (setq p (point))
1498 (skip-chars-backward " \t\n")
1499 (delete-region (point) p))
1500 (backward-delete-char-untabify arg)))
1501
1502(defun cperl-inside-parens-p ()
1503 (condition-case ()
1504 (save-excursion
1505 (save-restriction
1506 (narrow-to-region (point)
1507 (progn (beginning-of-defun) (point)))
1508 (goto-char (point-max))
1509 (= (char-after (or (scan-lists (point) -1 1) (point-min))) ?\()))
1510 (error nil)))
1511\f
1512(defun cperl-indent-command (&optional whole-exp)
1513 "Indent current line as Perl code, or in some cases insert a tab character.
1514If `cperl-tab-always-indent' is non-nil (the default), always indent current line.
1515Otherwise, indent the current line only if point is at the left margin
1516or in the line's indentation; otherwise insert a tab.
1517
1518A numeric argument, regardless of its value,
1519means indent rigidly all the lines of the expression starting after point
1520so that this line becomes properly indented.
1521The relative indentation among the lines of the expression are preserved."
1522 (interactive "P")
1523 (if whole-exp
1524 ;; If arg, always indent this line as Perl
1525 ;; and shift remaining lines of expression the same amount.
1526 (let ((shift-amt (cperl-indent-line))
1527 beg end)
1528 (save-excursion
1529 (if cperl-tab-always-indent
1530 (beginning-of-line))
1531 (setq beg (point))
1532 (forward-sexp 1)
1533 (setq end (point))
1534 (goto-char beg)
1535 (forward-line 1)
1536 (setq beg (point)))
1537 (if (> end beg)
1538 (indent-code-rigidly beg end shift-amt "#")))
1539 (if (and (not cperl-tab-always-indent)
1540 (save-excursion
1541 (skip-chars-backward " \t")
1542 (not (bolp))))
1543 (insert-tab)
1544 (cperl-indent-line))))
1545
1546(defun cperl-indent-line (&optional symbol)
1547 "Indent current line as Perl code.
1548Return the amount the indentation changed by."
1549 (let (indent
1550 beg shift-amt
1551 (case-fold-search nil)
1552 (pos (- (point-max) (point))))
1553 (setq indent (cperl-calculate-indent nil symbol))
1554 (beginning-of-line)
1555 (setq beg (point))
1556 (cond ((or (eq indent nil) (eq indent t))
1557 (setq indent (current-indentation)))
1558 ;;((eq indent t) ; Never?
1559 ;; (setq indent (cperl-calculate-indent-within-comment)))
1560 ;;((looking-at "[ \t]*#")
1561 ;; (setq indent 0))
1562 (t
1563 (skip-chars-forward " \t")
1564 (if (listp indent) (setq indent (car indent)))
1565 (cond ((looking-at "[A-Za-z_][A-Za-z_0-9]*:[^:]")
1566 (and (> indent 0)
1567 (setq indent (max cperl-min-label-indent
1568 (+ indent cperl-label-offset)))))
1569 ((= (following-char) ?})
1570 (setq indent (- indent cperl-indent-level)))
1571 ((memq (following-char) '(?\) ?\])) ; To line up with opening paren.
1572 (setq indent (+ indent cperl-close-paren-offset)))
1573 ((= (following-char) ?{)
1574 (setq indent (+ indent cperl-brace-offset))))))
1575 (skip-chars-forward " \t")
1576 (setq shift-amt (- indent (current-column)))
1577 (if (zerop shift-amt)
1578 (if (> (- (point-max) pos) (point))
1579 (goto-char (- (point-max) pos)))
1580 (delete-region beg (point))
1581 (indent-to indent)
1582 ;; If initial point was within line's indentation,
1583 ;; position after the indentation. Else stay at same point in text.
1584 (if (> (- (point-max) pos) (point))
1585 (goto-char (- (point-max) pos))))
1586 shift-amt))
1587
1588(defun cperl-after-label ()
1589 ;; Returns true if the point is after label. Does not do save-excursion.
1590 (and (eq (preceding-char) ?:)
1591 (memq (char-syntax (char-after (- (point) 2)))
1592 '(?w ?_))
1593 (progn
1594 (backward-sexp)
1595 (looking-at "[a-zA-Z_][a-zA-Z0-9_]*:[^:]"))))
1596
1597(defun cperl-get-state (&optional parse-start start-state)
1598 ;; returns list (START STATE DEPTH PRESTART), START is a good place
1599 ;; to start parsing, STATE is what is returned by
1600 ;; `parse-partial-sexp'. DEPTH is true is we are immediately after
1601 ;; end of block which contains START. PRESTART is the position
1602 ;; basing on which START was found.
1603 (save-excursion
1604 (let ((start-point (point)) depth state start prestart)
1605 (if parse-start
1606 (goto-char parse-start)
1607 (beginning-of-defun))
1608 (setq prestart (point))
1609 (if start-state nil
1610 ;; Try to go out, if sub is not on the outermost level
1611 (while (< (point) start-point)
1612 (setq start (point) parse-start start depth nil
1613 state (parse-partial-sexp start start-point -1))
1614 (if (> (car state) -1) nil
1615 ;; The current line could start like }}}, so the indentation
1616 ;; corresponds to a different level than what we reached
1617 (setq depth t)
1618 (beginning-of-line 2))) ; Go to the next line.
1619 (if start (goto-char start))) ; Not at the start of file
1620 (setq start (point))
1621 (if (< start start-point) (setq parse-start start))
1622 (or state (setq state (parse-partial-sexp start start-point -1 nil start-state)))
1623 (list start state depth prestart))))
1624
1625(defun cperl-block-p () ; Do not C-M-q ! One string contains ";" !
1626 ;; Positions is before ?\{. Checks whether it starts a block.
1627 ;; No save-excursion!
1628 (cperl-backward-to-noncomment (point-min))
1629 ;;(skip-chars-backward " \t\n\f")
1630 (or (memq (preceding-char) (append ";){}$@&%\C-@" nil)) ; Or label! \C-@ at bobp
1631 ; Label may be mixed up with `$blah :'
1632 (save-excursion (cperl-after-label))
1633 (and (memq (char-syntax (preceding-char)) '(?w ?_))
1634 (progn
1635 (backward-sexp)
1636 ;; Need take into account `bless', `return', `tr',...
1637 (or (and (looking-at "[a-zA-Z0-9_:]+[ \t\n\f]*[{#]") ; Method call syntax
1638 (not (looking-at "\\(bless\\|return\\|qw\\|tr\\|[smy]\\)\\>")))
1639 (progn
1640 (skip-chars-backward " \t\n\f")
1641 (and (memq (char-syntax (preceding-char)) '(?w ?_))
1642 (progn
1643 (backward-sexp)
1644 (looking-at
1645 "sub[ \t]+[a-zA-Z0-9_:]+[ \t\n\f]*\\(([^()]*)[ \t\n\f]*\\)?[#{]")))))))))
1646
1647(defvar cperl-look-for-prop '((pod in-pod) (here-doc-delim here-doc-group)))
1648
1649(defun cperl-calculate-indent (&optional parse-start symbol)
1650 "Return appropriate indentation for current line as Perl code.
1651In usual case returns an integer: the column to indent to.
1652Returns nil if line starts inside a string, t if in a comment."
1653 (save-excursion
1654 (if (or
1655 (memq (get-text-property (point) 'syntax-type)
1656 '(pod here-doc here-doc-delim format))
1657 ;; before start of POD - whitespace found since do not have 'pod!
1658 (and (looking-at "[ \t]*\n=")
1659 (error "Spaces before pod section!"))
1660 (and (not cperl-indent-left-aligned-comments)
1661 (looking-at "^#")))
1662 nil
1663 (beginning-of-line)
1664 (let ((indent-point (point))
1665 (char-after (save-excursion
1666 (skip-chars-forward " \t")
1667 (following-char)))
1668 (in-pod (get-text-property (point) 'in-pod))
1669 (pre-indent-point (point))
1670 p prop look-prop)
1671 (cond
1672 (in-pod
1673 ;; In the verbatim part, probably code example. What to do???
1674 )
1675 (t
1676 (save-excursion
1677 ;; Not in pod
1678 (cperl-backward-to-noncomment nil)
1679 (setq p (max (point-min) (1- (point)))
1680 prop (get-text-property p 'syntax-type)
1681 look-prop (or (nth 1 (assoc prop cperl-look-for-prop))
1682 'syntax-type))
1683 (if (memq prop '(pod here-doc format here-doc-delim))
1684 (progn
1685 (goto-char (or (previous-single-property-change p look-prop)
1686 (point-min)))
1687 (beginning-of-line)
1688 (setq pre-indent-point (point)))))))
1689 (goto-char pre-indent-point)
1690 (let* ((case-fold-search nil)
1691 (s-s (cperl-get-state))
1692 (start (nth 0 s-s))
1693 (state (nth 1 s-s))
1694 (containing-sexp (car (cdr state)))
1695 (start-indent (save-excursion
1696 (goto-char start)
1697 (- (current-indentation)
1698 (if (nth 2 s-s) cperl-indent-level 0))))
1699 old-indent)
1700 ;; (or parse-start (null symbol)
1701 ;; (setq parse-start (symbol-value symbol)
1702 ;; start-indent (nth 2 parse-start)
1703 ;; parse-start (car parse-start)))
1704 ;; (if parse-start
1705 ;; (goto-char parse-start)
1706 ;; (beginning-of-defun))
1707 ;; ;; Try to go out
1708 ;; (while (< (point) indent-point)
1709 ;; (setq start (point) parse-start start moved nil
1710 ;; state (parse-partial-sexp start indent-point -1))
1711 ;; (if (> (car state) -1) nil
1712 ;; ;; The current line could start like }}}, so the indentation
1713 ;; ;; corresponds to a different level than what we reached
1714 ;; (setq moved t)
1715 ;; (beginning-of-line 2))) ; Go to the next line.
1716 ;; (if start ; Not at the start of file
1717 ;; (progn
1718 ;; (goto-char start)
1719 ;; (setq start-indent (current-indentation))
1720 ;; (if moved ; Should correct...
1721 ;; (setq start-indent (- start-indent cperl-indent-level))))
1722 ;; (setq start-indent 0))
1723 ;; (if (< (point) indent-point) (setq parse-start (point)))
1724 ;; (or state (setq state (parse-partial-sexp
1725 ;; (point) indent-point -1 nil start-state)))
1726 ;; (setq containing-sexp
1727 ;; (or (car (cdr state))
1728 ;; (and (>= (nth 6 state) 0) old-containing-sexp))
1729 ;; old-containing-sexp nil start-state nil)
1730;;;; (while (< (point) indent-point)
1731;;;; (setq parse-start (point))
1732;;;; (setq state (parse-partial-sexp (point) indent-point -1 nil start-state))
1733;;;; (setq containing-sexp
1734;;;; (or (car (cdr state))
1735;;;; (and (>= (nth 6 state) 0) old-containing-sexp))
1736;;;; old-containing-sexp nil start-state nil))
1737 ;; (if symbol (set symbol (list indent-point state start-indent)))
1738 ;; (goto-char indent-point)
1739 (cond ((or (nth 3 state) (nth 4 state))
1740 ;; return nil or t if should not change this line
1741 (nth 4 state))
1742 ((null containing-sexp)
1743 ;; Line is at top level. May be data or function definition,
1744 ;; or may be function argument declaration.
1745 ;; Indent like the previous top level line
1746 ;; unless that ends in a closeparen without semicolon,
1747 ;; in which case this line is the first argument decl.
1748 (skip-chars-forward " \t")
1749 (+ start-indent
1750 (if (= (following-char) ?{) cperl-continued-brace-offset 0)
1751 (progn
1752 (cperl-backward-to-noncomment (or parse-start (point-min)))
1753 ;;(skip-chars-backward " \t\f\n")
1754 ;; Look at previous line that's at column 0
1755 ;; to determine whether we are in top-level decls
1756 ;; or function's arg decls. Set basic-indent accordingly.
1757 ;; Now add a little if this is a continuation line.
1758 (if (or (bobp)
1759 (memq (preceding-char) (append " ;}" nil)) ; Was ?\)
1760 (memq char-after (append ")]}" nil))
1761 (and (eq (preceding-char) ?\:) ; label
1762 (progn
1763 (forward-sexp -1)
1764 (skip-chars-backward " \t")
1765 (looking-at "[ \t]*[a-zA-Z_][a-zA-Z_0-9]*[ \t]*:"))))
1766 0
1767 cperl-continued-statement-offset))))
1768 ((/= (char-after containing-sexp) ?{)
1769 ;; line is expression, not statement:
1770 ;; indent to just after the surrounding open,
1771 ;; skip blanks if we do not close the expression.
1772 (goto-char (1+ containing-sexp))
1773 (or (memq char-after (append ")]}" nil))
1774 (looking-at "[ \t]*\\(#\\|$\\)")
1775 (skip-chars-forward " \t"))
1776 (current-column))
1777 ((progn
1778 ;; Containing-expr starts with \{. Check whether it is a hash.
1779 (goto-char containing-sexp)
1780 (not (cperl-block-p)))
1781 (goto-char (1+ containing-sexp))
1782 (or (eq char-after ?\})
1783 (looking-at "[ \t]*\\(#\\|$\\)")
1784 (skip-chars-forward " \t"))
1785 (+ (current-column) ; Correct indentation of trailing ?\}
1786 (if (eq char-after ?\}) (+ cperl-indent-level
1787 cperl-close-paren-offset)
1788 0)))
1789 (t
1790 ;; Statement level. Is it a continuation or a new statement?
1791 ;; Find previous non-comment character.
1792 (goto-char pre-indent-point)
1793 (cperl-backward-to-noncomment containing-sexp)
1794 ;; Back up over label lines, since they don't
1795 ;; affect whether our line is a continuation.
1796 (while (or (eq (preceding-char) ?\,)
1797 (and (eq (preceding-char) ?:)
1798 (or;;(eq (char-after (- (point) 2)) ?\') ; ????
1799 (memq (char-syntax (char-after (- (point) 2)))
1800 '(?w ?_)))))
1801 (if (eq (preceding-char) ?\,)
1802 ;; Will go to beginning of line, essentially.
1803 ;; Will ignore embedded sexpr XXXX.
1804 (cperl-backward-to-start-of-continued-exp containing-sexp))
1805 (beginning-of-line)
1806 (cperl-backward-to-noncomment containing-sexp))
1807 ;; Now we get the answer.
1808 (if (not (memq (preceding-char) (append ", ;}{" '(nil)))) ; Was ?\,
1809 ;; This line is continuation of preceding line's statement;
1810 ;; indent `cperl-continued-statement-offset' more than the
1811 ;; previous line of the statement.
1812 (progn
1813 (cperl-backward-to-start-of-continued-exp containing-sexp)
1814 (+ (if (memq char-after (append "}])" nil))
1815 0 ; Closing parenth
1816 cperl-continued-statement-offset)
1817 (current-column)
1818 (if (eq char-after ?\{)
1819 cperl-continued-brace-offset 0)))
1820 ;; This line starts a new statement.
1821 ;; Position following last unclosed open.
1822 (goto-char containing-sexp)
1823 ;; Is line first statement after an open-brace?
1824 (or
1825 ;; If no, find that first statement and indent like
1826 ;; it. If the first statement begins with label, do
1827 ;; not believe when the indentation of the label is too
1828 ;; small.
1829 (save-excursion
1830 (forward-char 1)
1831 (setq old-indent (current-indentation))
1832 (let ((colon-line-end 0))
1833 (while (progn (skip-chars-forward " \t\n")
1834 (looking-at "#\\|[a-zA-Z0-9_$]*:[^:]"))
1835 ;; Skip over comments and labels following openbrace.
1836 (cond ((= (following-char) ?\#)
1837 (forward-line 1))
1838 ;; label:
1839 (t
1840 (save-excursion (end-of-line)
1841 (setq colon-line-end (point)))
1842 (search-forward ":"))))
1843 ;; The first following code counts
1844 ;; if it is before the line we want to indent.
1845 (and (< (point) indent-point)
1846 (if (> colon-line-end (point)) ; After label
1847 (if (> (current-indentation)
1848 cperl-min-label-indent)
1849 (- (current-indentation) cperl-label-offset)
1850 ;; Do not believe: `max' is involved
1851 (+ old-indent cperl-indent-level))
1852 (current-column)))))
1853 ;; If no previous statement,
1854 ;; indent it relative to line brace is on.
1855 ;; For open brace in column zero, don't let statement
1856 ;; start there too. If cperl-indent-level is zero,
1857 ;; use cperl-brace-offset + cperl-continued-statement-offset instead.
1858 ;; For open-braces not the first thing in a line,
1859 ;; add in cperl-brace-imaginary-offset.
1860
1861 ;; If first thing on a line: ?????
1862 (+ (if (and (bolp) (zerop cperl-indent-level))
1863 (+ cperl-brace-offset cperl-continued-statement-offset)
1864 cperl-indent-level)
1865 ;; Move back over whitespace before the openbrace.
1866 ;; If openbrace is not first nonwhite thing on the line,
1867 ;; add the cperl-brace-imaginary-offset.
1868 (progn (skip-chars-backward " \t")
1869 (if (bolp) 0 cperl-brace-imaginary-offset))
1870 ;; If the openbrace is preceded by a parenthesized exp,
1871 ;; move to the beginning of that;
1872 ;; possibly a different line
1873 (progn
1874 (if (eq (preceding-char) ?\))
1875 (forward-sexp -1))
1876 ;; In the case it starts a subroutine, indent with
1877 ;; respect to `sub', not with respect to the the
1878 ;; first thing on the line, say in the case of
1879 ;; anonymous sub in a hash.
1880 ;;
1881 (skip-chars-backward " \t")
1882 (if (and (eq (preceding-char) ?b)
1883 (progn
1884 (forward-sexp -1)
1885 (looking-at "sub\\>"))
1886 (setq old-indent
1887 (nth 1
1888 (parse-partial-sexp
1889 (save-excursion (beginning-of-line) (point))
1890 (point)))))
1891 (progn (goto-char (1+ old-indent))
1892 (skip-chars-forward " \t")
1893 (current-column))
1894 ;; Get initial indentation of the line we are on.
1895 ;; If line starts with label, calculate label indentation
1896 (if (save-excursion
1897 (beginning-of-line)
1898 (looking-at "[ \t]*[a-zA-Z_][a-zA-Z_0-9]*:[^:]"))
1899 (if (> (current-indentation) cperl-min-label-indent)
1900 (- (current-indentation) cperl-label-offset)
1901 (cperl-calculate-indent
1902 (if (and parse-start (<= parse-start (point)))
1903 parse-start)))
1904 (current-indentation))))))))))))))
1905
1906(defvar cperl-indent-alist
1907 '((string nil)
1908 (comment nil)
1909 (toplevel 0)
1910 (toplevel-after-parenth 2)
1911 (toplevel-continued 2)
1912 (expression 1))
1913 "Alist of indentation rules for CPerl mode.
1914The values mean:
1915 nil: do not indent;
1916 number: add this amount of indentation.")
1917
1918(defun cperl-where-am-i (&optional parse-start start-state)
1919 ;; Unfinished
1920 "Return a list of lists ((TYPE POS)...) of good points before the point.
1921POS may be nil if it is hard to find, say, when TYPE is `string' or `comment'."
1922 (save-excursion
1923 (let* ((start-point (point))
1924 (s-s (cperl-get-state))
1925 (start (nth 0 s-s))
1926 (state (nth 1 s-s))
1927 (prestart (nth 3 s-s))
1928 (containing-sexp (car (cdr state)))
1929 (case-fold-search nil)
1930 (res (list (list 'parse-start start) (list 'parse-prestart prestart))))
1931 (cond ((nth 3 state) ; In string
1932 (setq res (cons (list 'string nil (nth 3 state)) res))) ; What started string
1933 ((nth 4 state) ; In comment
1934 (setq res (cons '(comment) res)))
1935 ((null containing-sexp)
1936 ;; Line is at top level.
1937 ;; Indent like the previous top level line
1938 ;; unless that ends in a closeparen without semicolon,
1939 ;; in which case this line is the first argument decl.
1940 (cperl-backward-to-noncomment (or parse-start (point-min)))
1941 ;;(skip-chars-backward " \t\f\n")
1942 (cond
1943 ((or (bobp)
1944 (memq (preceding-char) (append ";}" nil)))
1945 (setq res (cons (list 'toplevel start) res)))
1946 ((eq (preceding-char) ?\) )
1947 (setq res (cons (list 'toplevel-after-parenth start) res)))
1948 (t
1949 (setq res (cons (list 'toplevel-continued start) res)))))
1950 ((/= (char-after containing-sexp) ?{)
1951 ;; line is expression, not statement:
1952 ;; indent to just after the surrounding open.
1953 ;; skip blanks if we do not close the expression.
1954 (setq res (cons (list 'expression-blanks
1955 (progn
1956 (goto-char (1+ containing-sexp))
1957 (or (looking-at "[ \t]*\\(#\\|$\\)")
1958 (skip-chars-forward " \t"))
1959 (point)))
1960 (cons (list 'expression containing-sexp) res))))
1961 ((progn
1962 ;; Containing-expr starts with \{. Check whether it is a hash.
1963 (goto-char containing-sexp)
1964 (not (cperl-block-p)))
1965 (setq res (cons (list 'expression-blanks
1966 (progn
1967 (goto-char (1+ containing-sexp))
1968 (or (looking-at "[ \t]*\\(#\\|$\\)")
1969 (skip-chars-forward " \t"))
1970 (point)))
1971 (cons (list 'expression containing-sexp) res))))
1972 (t
1973 ;; Statement level.
1974 (setq res (cons (list 'in-block containing-sexp) res))
1975 ;; Is it a continuation or a new statement?
1976 ;; Find previous non-comment character.
1977 (cperl-backward-to-noncomment containing-sexp)
1978 ;; Back up over label lines, since they don't
1979 ;; affect whether our line is a continuation.
1980 ;; Back up comma-delimited lines too ?????
1981 (while (or (eq (preceding-char) ?\,)
1982 (save-excursion (cperl-after-label)))
1983 (if (eq (preceding-char) ?\,)
1984 ;; Will go to beginning of line, essentially
1985 ;; Will ignore embedded sexpr XXXX.
1986 (cperl-backward-to-start-of-continued-exp containing-sexp))
1987 (beginning-of-line)
1988 (cperl-backward-to-noncomment containing-sexp))
1989 ;; Now we get the answer.
1990 (if (not (memq (preceding-char) (append ";}{" '(nil)))) ; Was ?\,
1991 ;; This line is continuation of preceding line's statement.
1992 (list (list 'statement-continued containing-sexp))
1993 ;; This line starts a new statement.
1994 ;; Position following last unclosed open.
1995 (goto-char containing-sexp)
1996 ;; Is line first statement after an open-brace?
1997 (or
1998 ;; If no, find that first statement and indent like
1999 ;; it. If the first statement begins with label, do
2000 ;; not believe when the indentation of the label is too
2001 ;; small.
2002 (save-excursion
2003 (forward-char 1)
2004 (let ((colon-line-end 0))
2005 (while (progn (skip-chars-forward " \t\n" start-point)
2006 (and (< (point) start-point)
2007 (looking-at
2008 "#\\|[a-zA-Z_][a-zA-Z0-9_]*:[^:]")))
2009 ;; Skip over comments and labels following openbrace.
2010 (cond ((= (following-char) ?\#)
2011 ;;(forward-line 1)
2012 (end-of-line))
2013 ;; label:
2014 (t
2015 (save-excursion (end-of-line)
2016 (setq colon-line-end (point)))
2017 (search-forward ":"))))
2018 ;; Now at the point, after label, or at start
2019 ;; of first statement in the block.
2020 (and (< (point) start-point)
2021 (if (> colon-line-end (point))
2022 ;; Before statement after label
2023 (if (> (current-indentation)
2024 cperl-min-label-indent)
2025 (list (list 'label-in-block (point)))
2026 ;; Do not believe: `max' is involved
2027 (list
2028 (list 'label-in-block-min-indent (point))))
2029 ;; Before statement
2030 (list 'statement-in-block (point))))))
2031 ;; If no previous statement,
2032 ;; indent it relative to line brace is on.
2033 ;; For open brace in column zero, don't let statement
2034 ;; start there too. If cperl-indent-level is zero,
2035 ;; use cperl-brace-offset + cperl-continued-statement-offset instead.
2036 ;; For open-braces not the first thing in a line,
2037 ;; add in cperl-brace-imaginary-offset.
2038
2039 ;; If first thing on a line: ?????
2040 (+ (if (and (bolp) (zerop cperl-indent-level))
2041 (+ cperl-brace-offset cperl-continued-statement-offset)
2042 cperl-indent-level)
2043 ;; Move back over whitespace before the openbrace.
2044 ;; If openbrace is not first nonwhite thing on the line,
2045 ;; add the cperl-brace-imaginary-offset.
2046 (progn (skip-chars-backward " \t")
2047 (if (bolp) 0 cperl-brace-imaginary-offset))
2048 ;; If the openbrace is preceded by a parenthesized exp,
2049 ;; move to the beginning of that;
2050 ;; possibly a different line
2051 (progn
2052 (if (eq (preceding-char) ?\))
2053 (forward-sexp -1))
2054 ;; Get initial indentation of the line we are on.
2055 ;; If line starts with label, calculate label indentation
2056 (if (save-excursion
2057 (beginning-of-line)
2058 (looking-at "[ \t]*[a-zA-Z_][a-zA-Z_0-9]*:[^:]"))
2059 (if (> (current-indentation) cperl-min-label-indent)
2060 (- (current-indentation) cperl-label-offset)
2061 (cperl-calculate-indent
2062 (if (and parse-start (<= parse-start (point)))
2063 parse-start)))
2064 (current-indentation))))))))
2065 res)))
2066
2067(defun cperl-calculate-indent-within-comment ()
2068 "Return the indentation amount for line, assuming that
2069the current line is to be regarded as part of a block comment."
2070 (let (end star-start)
2071 (save-excursion
2072 (beginning-of-line)
2073 (skip-chars-forward " \t")
2074 (setq end (point))
2075 (and (= (following-char) ?#)
2076 (forward-line -1)
2077 (cperl-to-comment-or-eol)
2078 (setq end (point)))
2079 (goto-char end)
2080 (current-column))))
2081
2082
2083(defun cperl-to-comment-or-eol ()
2084 "Goes to position before comment on the current line, or to end of line.
2085Returns true if comment is found."
2086 (let (state stop-in cpoint (lim (progn (end-of-line) (point))))
2087 (beginning-of-line)
2088 (if (or
2089 (eq (get-text-property (point) 'syntax-type) 'pod)
2090 (re-search-forward "\\=[ \t]*\\(#\\|$\\)" lim t))
2091 (if (eq (preceding-char) ?\#) (progn (backward-char 1) t))
2092 ;; Else
2093 (while (not stop-in)
2094 (setq state (parse-partial-sexp (point) lim nil nil nil t))
2095 ; stop at comment
2096 ;; If fails (beginning-of-line inside sexp), then contains not-comment
2097 ;; Do simplified processing
2098 ;;(if (re-search-forward "[^$]#" lim 1)
2099 ;; (progn
2100 ;; (forward-char -1)
2101 ;; (skip-chars-backward " \t\n\f" lim))
2102 ;; (goto-char lim)) ; No `#' at all
2103 ;;)
2104 (if (nth 4 state) ; After `#';
2105 ; (nth 2 state) can be
2106 ; beginning of m,s,qq and so
2107 ; on
2108 (if (nth 2 state)
2109 (progn
2110 (setq cpoint (point))
2111 (goto-char (nth 2 state))
2112 (cond
2113 ((looking-at "\\(s\\|tr\\)\\>")
2114 (or (re-search-forward
2115 "\\=\\w+[ \t]*#\\([^\n\\\\#]\\|\\\\[\\\\#]\\)*#\\([^\n\\\\#]\\|\\\\[\\\\#]\\)*"
2116 lim 'move)
2117 (setq stop-in t)))
2118 ((looking-at "\\(m\\|q\\([qxw]\\)?\\)\\>")
2119 (or (re-search-forward
2120 "\\=\\w+[ \t]*#\\([^\n\\\\#]\\|\\\\[\\\\#]\\)*#"
2121 lim 'move)
2122 (setq stop-in t)))
2123 (t ; It was fair comment
2124 (setq stop-in t) ; Finish
2125 (goto-char (1- cpoint)))))
2126 (setq stop-in t) ; Finish
2127 (forward-char -1))
2128 (setq stop-in t)) ; Finish
2129 )
2130 (nth 4 state))))
2131
2132(defsubst cperl-1- (p)
2133 (max (point-min) (1- p)))
2134
2135(defsubst cperl-1+ (p)
2136 (min (point-max) (1+ p)))
2137
2138(defvar cperl-st-cfence '(14)) ; Comment-fence
2139(defvar cperl-st-sfence '(15)) ; String-fence
2140(defvar cperl-st-punct '(1))
2141(defvar cperl-st-word '(2))
2142(defvar cperl-st-bra '(4 . ?\>))
2143(defvar cperl-st-ket '(5 . ?\<))
2144
2145(defsubst cperl-modify-syntax-type (at how)
2146 (if (< at (point-max))
2147 (progn
2148 (put-text-property at (1+ at) 'syntax-table how)
2149 (put-text-property at (1+ at) 'rear-nonsticky t))))
2150
2151(defun cperl-protect-defun-start (s e)
2152 ;; C code looks for "^\\s(" to skip comment backward in "hard" situations
2153 (save-excursion
2154 (goto-char s)
2155 (while (re-search-forward "^\\s(" e 'to-end)
2156 (put-text-property (1- (point)) (point) 'syntax-table cperl-st-punct))))
2157
2158(defun cperl-commentify (bb e string)
2159 (if cperl-use-syntax-table-text-property
2160 (progn
2161 ;; We suppose that e is _after_ the end of construction, as after eol.
2162 (setq string (if string cperl-st-sfence cperl-st-cfence))
2163 (cperl-modify-syntax-type bb string)
2164 (cperl-modify-syntax-type (1- e) string)
2165 (if (and (eq string cperl-st-sfence) (> (- e 2) bb))
2166 (put-text-property (1+ bb) (1- e)
2167 'syntax-table cperl-string-syntax-table))
2168 (cperl-protect-defun-start bb e))))
2169
2170(defun cperl-forward-re (lim end is-2arg set-st st-l err-l argument
2171 &optional ostart oend)
2172 ;; Works *before* syntax recognition is done
2173 ;; May modify syntax-type text property if the situation is too hard
2174 (let (b starter ender st i i2 go-forward)
2175 (skip-chars-forward " \t")
2176 ;; ender means matching-char matcher.
2177 (setq b (point)
2178 starter (char-after b)
2179 ;; ender:
2180 ender (cdr (assoc starter '(( ?\( . ?\) )
2181 ( ?\[ . ?\] )
2182 ( ?\{ . ?\} )
2183 ( ?\< . ?\> )
2184 ))))
2185 ;; What if starter == ?\\ ????
2186 (if set-st
2187 (if (car st-l)
2188 (setq st (car st-l))
2189 (setcar st-l (make-syntax-table))
2190 (setq i 0 st (car st-l))
2191 (while (< i 256)
2192 (modify-syntax-entry i "." st)
2193 (setq i (1+ i)))
2194 (modify-syntax-entry ?\\ "\\" st)))
2195 (setq set-st t)
2196 ;; Whether we have an intermediate point
2197 (setq i nil)
2198 ;; Prepare the syntax table:
2199 (and set-st
2200 (if (not ender) ; m/blah/, s/x//, s/x/y/
2201 (modify-syntax-entry starter "$" st)
2202 (modify-syntax-entry starter (concat "(" (list ender)) st)
2203 (modify-syntax-entry ender (concat ")" (list starter)) st)))
2204 (condition-case bb
2205 (progn
2206 (if (and (eq starter (char-after (cperl-1+ b)))
2207 (not ender))
2208 ;; $ has TeXish matching rules, so $$ equiv $...
2209 (forward-char 2)
2210 (set-syntax-table st)
2211 (forward-sexp 1)
2212 (set-syntax-table cperl-mode-syntax-table)
2213 ;; Now the problem is with m;blah;;
2214 (and (not ender)
2215 (eq (preceding-char)
2216 (char-after (- (point) 2)))
2217 (save-excursion
2218 (forward-char -2)
2219 (= 0 (% (skip-chars-backward "\\\\") 2)))
2220 (forward-char -1)))
2221 (and is-2arg ; Have trailing part
2222 (not ender)
2223 (eq (following-char) starter) ; Empty trailing part
2224 (progn
2225 (or (eq (char-syntax (following-char)) ?.)
2226 ;; Make trailing letter into punctuation
2227 (cperl-modify-syntax-type (point) cperl-st-punct))
2228 (setq is-2arg nil go-forward t))) ; Ignore the tail
2229 (if is-2arg ; Not number => have second part
2230 (progn
2231 (setq i (point) i2 i)
2232 (if ender
2233 (if (memq (following-char) '(?\ ?\t ?\n ?\f))
2234 (progn
2235 (if (looking-at "[ \t\n\f]+\\(#[^\n]*\n[ \t\n\f]*\\)+")
2236 (goto-char (match-end 0))
2237 (skip-chars-forward " \t\n\f"))
2238 (setq i2 (point))))
2239 (forward-char -1))
2240 (modify-syntax-entry starter (if (eq starter ?\\) "\\" ".") st)
2241 (if ender (modify-syntax-entry ender "." st))
2242 (setq set-st nil)
2243 (setq
2244 ender
2245 (cperl-forward-re lim end nil t st-l err-l argument starter ender)
2246 ender (nth 2 ender)))))
2247 (error (goto-char lim)
2248 (setq set-st nil)
2249 (or end
2250 (message
2251 "End of `%s%s%c ... %c' string not found: %s"
2252 argument
2253 (if ostart (format "%c ... %c" ostart (or oend ostart)) "")
2254 starter (or ender starter) bb)
2255 (or (car err-l) (setcar err-l b)))))
2256 (if set-st
2257 (progn
2258 (modify-syntax-entry starter (if (eq starter ?\\) "\\" ".") st)
2259 (if ender (modify-syntax-entry ender "." st))))
2260 (list i i2 ender starter go-forward)))
2261
2262(defun cperl-find-pods-heres (&optional min max non-inter end)
2263 "Scans the buffer for hard-to-parse Perl constructions.
2264If `cperl-pod-here-fontify' is not-nil after evaluation, will fontify
2265the sections using `cperl-pod-head-face', `cperl-pod-face',
2266`cperl-here-face'."
2267 (interactive)
2268 (or min (setq min (point-min)))
2269 (or max (setq max (point-max)))
2270 (let (face head-face here-face b e bb tag qtag b1 e1 argument i c tail state
2271 (cperl-pod-here-fontify (eval cperl-pod-here-fontify)) go
2272 (case-fold-search nil) (inhibit-read-only t) (buffer-undo-list t)
2273 (modified (buffer-modified-p))
2274 (after-change-functions nil)
2275 (state-point (point-min))
2276 (st-l '(nil)) (err-l '(nil)) i2
2277 ;; Somehow font-lock may be not loaded yet...
2278 (font-lock-string-face (if (boundp 'font-lock-string-face)
2279 font-lock-string-face
2280 'font-lock-string-face))
2281 (search
2282 (concat
2283 "\\(\\`\n?\\|\n\n\\)="
2284 "\\|"
2285 ;; One extra () before this:
2286 "<<"
2287 "\\("
2288 ;; First variant "BLAH" or just ``.
2289 "\\([\"'`]\\)"
2290 "\\([^\"'`\n]*\\)"
2291 "\\3"
2292 "\\|"
2293 ;; Second variant: Identifier or empty
2294 "\\(\\([a-zA-Z_][a-zA-Z_0-9]*\\)?\\)"
2295 ;; Check that we do not have <<= or << 30 or << $blah.
2296 "\\([^= \t$@%&]\\|[ \t]+[^ \t\n0-9$@%&]\\)"
2297 "\\)"
2298 "\\|"
2299 ;; 1+6 extra () before this:
2300 "^[ \t]*\\(format\\)[ \t]*\\([a-zA-Z0-9_]+\\)?[ \t]*=[ \t]*$"
2301 (if cperl-use-syntax-table-text-property
2302 (concat
2303 "\\|"
2304 ;; 1+6+2=9 extra () before this:
2305 "\\<\\(q[wxq]?\\|[msy]\\|tr\\)\\>"
2306 "\\|"
2307 ;; 1+6+2+1=10 extra () before this:
2308 "\\([?/]\\)" ; /blah/ or ?blah?
2309 "\\|"
2310 ;; 1+6+2+1+1=11 extra () before this:
2311 "\\<sub\\>[ \t]*\\([a-zA-Z_:'0-9]+[ \t]*\\)?\\(([^()]*)\\)"
2312 "\\|"
2313 ;; 1+6+2+1+1+2=13 extra () before this:
2314 "\\$\\(['{]\\)"
2315 "\\|"
2316 ;; 1+6+2+1+1+2+1=14 extra () before this:
2317 "\\(\\<sub[ \t\n\f]+\\|[&*$@%]\\)[a-zA-Z0-9_]*'"
2318 ;; 1+6+2+1+1+2+1+1=15 extra () before this:
2319 "\\|"
2320 "__\\(END\\|DATA\\)__" ; Commented - does not help with indent...
2321 )
2322 ""))))
2323 (unwind-protect
2324 (progn
2325 (save-excursion
2326 (or non-inter
2327 (message "Scanning for \"hard\" Perl constructions..."))
2328 (if cperl-pod-here-fontify
2329 ;; We had evals here, do not know why...
2330 (setq face cperl-pod-face
2331 head-face cperl-pod-head-face
2332 here-face cperl-here-face))
2333 (remove-text-properties min max
2334 '(syntax-type t in-pod t syntax-table t))
2335 ;; Need to remove face as well...
2336 (goto-char min)
2337 (if (and (eq system-type 'emx)
2338 (looking-at "extproc[ \t]")) ; Analogue of #!
2339 (cperl-commentify min
2340 (save-excursion (end-of-line) (point))
2341 nil))
2342 (while (re-search-forward search max t)
2343 (cond
2344 ((match-beginning 1) ; POD section
2345 ;; "\\(\\`\n?\\|\n\n\\)="
2346 (if (looking-at "\n*cut\\>")
2347 (progn
2348 (message "=cut is not preceded by a POD section")
2349 (or (car err-l) (setcar err-l (point))))
2350 (beginning-of-line)
2351
2352 (setq b (point) bb b)
2353 (or (re-search-forward "\n\n=cut\\>" max 'toend)
2354 (progn
2355 (message "End of a POD section not marked by =cut")
2356 (or (car err-l) (setcar err-l b))))
2357 (beginning-of-line 2) ; An empty line after =cut is not POD!
2358 (setq e (point))
2359 (put-text-property b e 'in-pod t)
2360 (goto-char b)
2361 (while (re-search-forward "\n\n[ \t]" e t)
2362 ;; We start 'pod 1 char earlier to include the preceding line
2363 (beginning-of-line)
2364 (put-text-property (cperl-1- b) (point) 'syntax-type 'pod)
2365 (cperl-put-do-not-fontify b (point))
2366 ;;(put-text-property (max (point-min) (1- b))
2367 ;; (point) cperl-do-not-fontify t)
2368 (if cperl-pod-here-fontify (put-text-property b (point) 'face face))
2369 (re-search-forward "\n\n[^ \t\f\n]" e 'toend)
2370 (beginning-of-line)
2371 (setq b (point)))
2372 (put-text-property (cperl-1- (point)) e 'syntax-type 'pod)
2373 (cperl-put-do-not-fontify (point) e)
2374 ;;(put-text-property (max (point-min) (1- (point)))
2375 ;; e cperl-do-not-fontify t)
2376 (if cperl-pod-here-fontify
2377 (progn (put-text-property (point) e 'face face)
2378 (goto-char bb)
2379 (if (looking-at
2380 "=[a-zA-Z0-9_]+\\>[ \t]*\\(\\(\n?[^\n]\\)+\\)$")
2381 (put-text-property
2382 (match-beginning 1) (match-end 1)
2383 'face head-face))
2384 (while (re-search-forward
2385 ;; One paragraph
2386 "\n\n=[a-zA-Z0-9_]+\\>[ \t]*\\(\\(\n?[^\n]\\)+\\)$"
2387 e 'toend)
2388 (put-text-property
2389 (match-beginning 1) (match-end 1)
2390 'face head-face))))
2391 (cperl-commentify bb e nil)
2392 (goto-char e)
2393 (or (eq e (point-max))
2394 (forward-char -1)))) ; Prepare for immediate pod start.
2395 ;; Here document
2396 ;; We do only one here-per-line
2397 ;; 1 () ahead
2398 ;; "<<\\(\\([\"'`]\\)\\([^\"'`\n]*\\)\\3\\|\\(\\([a-zA-Z_][a-zA-Z_0-9]*\\)?\\)\\)"
2399 ((match-beginning 2) ; 1 + 1
2400 ;; Abort in comment:
2401 (setq b (point))
2402 (setq state (parse-partial-sexp state-point b nil nil state)
2403 state-point b)
2404 (if ;;(save-excursion
2405 ;; (beginning-of-line)
2406 ;; (search-forward "#" b t))
2407 (or (nth 3 state) (nth 4 state))
2408 (goto-char (match-end 2))
2409 (if (match-beginning 5) ;4 + 1
2410 (setq b1 (match-beginning 5) ; 4 + 1
2411 e1 (match-end 5)) ; 4 + 1
2412 (setq b1 (match-beginning 4) ; 3 + 1
2413 e1 (match-end 4))) ; 3 + 1
2414 (setq tag (buffer-substring b1 e1)
2415 qtag (regexp-quote tag))
2416 (cond (cperl-pod-here-fontify
883212ce 2417 (put-text-property b1 e1 'face font-lock-constant-face)
f83d2997
KH
2418 (cperl-put-do-not-fontify b1 e1)))
2419 (forward-line)
2420 (setq b (point))
2421 (cond ((re-search-forward (concat "^" qtag "$") max 'toend)
2422 (if cperl-pod-here-fontify
2423 (progn
2424 (put-text-property (match-beginning 0) (match-end 0)
883212ce 2425 'face font-lock-constant-face)
f83d2997
KH
2426 (cperl-put-do-not-fontify b (match-end 0))
2427 ;;(put-text-property (max (point-min) (1- b))
2428 ;; (min (point-max)
2429 ;; (1+ (match-end 0)))
2430 ;; cperl-do-not-fontify t)
2431 (put-text-property b (match-beginning 0)
2432 'face here-face)))
2433 (setq e1 (cperl-1+ (match-end 0)))
2434 (put-text-property b (match-beginning 0)
2435 'syntax-type 'here-doc)
2436 (put-text-property (match-beginning 0) e1
2437 'syntax-type 'here-doc-delim)
2438 (put-text-property b e1
2439 'here-doc-group t)
2440 (cperl-commentify b e1 nil)
2441 (cperl-put-do-not-fontify b (match-end 0)))
2442 (t (message "End of here-document `%s' not found." tag)
2443 (or (car err-l) (setcar err-l b))))))
2444 ;; format
2445 ((match-beginning 8)
2446 ;; 1+6=7 extra () before this:
2447 ;;"^[ \t]*\\(format\\)[ \t]*\\([a-zA-Z0-9_]+\\)?[ \t]*=[ \t]*$"
2448 (setq b (point)
2449 name (if (match-beginning 8) ; 7 + 1
2450 (buffer-substring (match-beginning 8) ; 7 + 1
2451 (match-end 8)) ; 7 + 1
2452 ""))
2453 (setq argument nil)
2454 (if cperl-pod-here-fontify
2455 (while (and (eq (forward-line) 0)
2456 (not (looking-at "^[.;]$")))
2457 (cond
2458 ((looking-at "^#")) ; Skip comments
2459 ((and argument ; Skip argument multi-lines
2460 (looking-at "^[ \t]*{"))
2461 (forward-sexp 1)
2462 (setq argument nil))
2463 (argument ; Skip argument lines
2464 (setq argument nil))
2465 (t ; Format line
2466 (setq b1 (point))
2467 (setq argument (looking-at "^[^\n]*[@^]"))
2468 (end-of-line)
2469 (put-text-property b1 (point)
2470 'face font-lock-string-face)
2471 (cperl-commentify b1 (point) nil)
2472 (cperl-put-do-not-fontify b1 (point)))))
2473 (re-search-forward (concat "^[.;]$") max 'toend))
2474 (beginning-of-line)
2475 (if (looking-at "^[.;]$")
2476 (progn
2477 (put-text-property (point) (+ (point) 2)
2478 'face font-lock-string-face)
2479 (cperl-commentify (point) (+ (point) 2) nil)
2480 (cperl-put-do-not-fontify (point) (+ (point) 2)))
2481 (message "End of format `%s' not found." name)
2482 (or (car err-l) (setcar err-l b)))
2483 (forward-line)
2484 (put-text-property b (point) 'syntax-type 'format)
2485;;; (cond ((re-search-forward (concat "^[.;]$") max 'toend)
2486;;; (if cperl-pod-here-fontify
2487;;; (progn
2488;;; (put-text-property b (match-end 0)
2489;;; 'face font-lock-string-face)
2490;;; (cperl-put-do-not-fontify b (match-end 0))))
2491;;; (put-text-property b (match-end 0)
2492;;; 'syntax-type 'format)
2493;;; (cperl-put-do-not-fontify b (match-beginning 0)))
2494;;; (t (message "End of format `%s' not found." name)))
2495 )
2496 ;; Regexp:
2497 ((or (match-beginning 10) (match-beginning 11))
2498 ;; 1+6+2=9 extra () before this:
2499 ;; "\\<\\(q[wxq]?\\|[msy]\\|tr\\)\\>"
2500 ;; "\\|"
2501 ;; "\\([?/]\\)" ; /blah/ or ?blah?
2502 (setq b1 (if (match-beginning 10) 10 11)
2503 argument (buffer-substring
2504 (match-beginning b1) (match-end b1))
2505 b (point)
2506 i b
2507 c (char-after (match-beginning b1))
2508 bb (char-after (1- (match-beginning b1))) ; tmp holder
2509 bb (and ; user variables/whatever
2510 (match-beginning 10)
2511 (or
2512 (memq bb '(?\$ ?\@ ?\% ?\* ?\#)) ; $#y
2513 (and (eq bb ?-) (eq c ?s)) ; -s file test
2514 (and (eq bb ?\&) ; &&m/blah/
2515 (not (eq (char-after
2516 (- (match-beginning b1) 2))
2517 ?\&))))))
2518 (or bb
2519 (if (eq b1 11) ; bare /blah/ or ?blah?
2520 (setq argument ""
2521 bb ; Not a regexp?
2522 (progn
2523 (goto-char (match-beginning b1))
2524 (cperl-backward-to-noncomment (point-min))
2525 (not
2526 ;; What is below: regexp-p?
2527 (and
2528 (or (memq (preceding-char)
2529 (append (if (eq c ?\?)
2530 ;; $a++ ? 1 : 2
2531 "~{(=|&*!,;"
2532 "~{(=|&+-*!,;") nil))
2533 (and (eq (preceding-char) ?\})
2534 (cperl-after-block-p (point-min)))
2535 (and (eq (char-syntax (preceding-char)) ?w)
2536 (progn
2537 (forward-sexp -1)
2538 (looking-at
2539 "\\(while\\|if\\|unless\\|until\\|and\\|or\\|not\\|xor\\|split\\|grep\\|map\\|print\\)\\>")))
2540 (and (eq (preceding-char) ?.)
2541 (eq (char-after (- (point) 2)) ?.))
2542 (bobp))
2543 ;; m|blah| ? foo : bar;
2544 (not
2545 (and (eq c ?\?)
2546 cperl-use-syntax-table-text-property
2547 (not (bobp))
2548 (progn
2549 (forward-char -1)
2550 (looking-at "\\s|")))))))
2551 b (1- b))))
2552 (or bb (setq state (parse-partial-sexp
2553 state-point b nil nil state)
2554 state-point b))
2555 (goto-char b)
2556 (if (or bb (nth 3 state) (nth 4 state))
2557 (goto-char i)
2558 (if (looking-at "[ \t\n\f]+\\(#[^\n]*\n[ \t\n\f]*\\)+")
2559 (goto-char (match-end 0))
2560 (skip-chars-forward " \t\n\f"))
2561 ;; qtag means two-arg matcher, may be reset to
2562 ;; 2 or 3 later if some special quoting is needed.
2563 ;; e1 means matching-char matcher.
2564 (setq b (point)
2565 i (cperl-forward-re max end
2566 (string-match "^\\([sy]\\|tr\\)$" argument)
2567 t st-l err-l argument)
2568 i2 (nth 1 i) ; start of the second part
2569 e1 (nth 2 i) ; ender, true if matching second part
2570 go (nth 4 i) ; There is a 1-char part after the end
2571 i (car i) ; intermediate point
2572 tail (if (and i (not e1)) (1- (point)))
2573 e nil) ; need to preserve backslashitis
2574 ;; Commenting \\ is dangerous, what about ( ?
2575 (and i tail
2576 (eq (char-after i) ?\\)
2577 (setq e t))
2578 (if (null i)
2579 (progn
2580 (cperl-commentify b (point) t)
2581 (if go (forward-char 1)))
2582 (cperl-commentify b i t)
2583 (if (looking-at "\\sw*e") ; s///e
2584 (progn
2585 (and
2586 ;; silent:
2587 (cperl-find-pods-heres i2 (1- (point)) t end)
2588 ;; Error
2589 (goto-char (1+ max)))
2590 (if (and e1 (eq (preceding-char) ?\>))
2591 (progn
2592 (cperl-modify-syntax-type (1- (point)) cperl-st-ket)
2593 (cperl-modify-syntax-type i cperl-st-bra))))
2594 (cperl-commentify i2 (point) t)
2595 (if e
2596 (cperl-modify-syntax-type (1+ i) cperl-st-punct))
2597 (setq tail nil)))
2598 (if (eq (char-syntax (following-char)) ?w)
2599 (progn
2600 (forward-word 1) ; skip modifiers s///s
2601 (if tail (cperl-commentify tail (point) t))))))
2602 ((match-beginning 13) ; sub with prototypes
2603 (setq b (match-beginning 0))
2604 (if (memq (char-after (1- b))
2605 '(?\$ ?\@ ?\% ?\& ?\*))
2606 nil
2607 (setq state (parse-partial-sexp
2608 state-point (1- b) nil nil state)
2609 state-point (1- b))
2610 (if (or (nth 3 state) (nth 4 state))
2611 nil
2612 ;; Mark as string
2613 (cperl-commentify (match-beginning 13) (match-end 13) t))
2614 (goto-char (match-end 0))))
2615 ;; 1+6+2+1+1+2=13 extra () before this:
2616 ;; "\\$\\(['{]\\)"
2617 ((and (match-beginning 14)
2618 (eq (preceding-char) ?\')) ; $'
2619 (setq b (1- (point))
2620 state (parse-partial-sexp
2621 state-point (1- b) nil nil state)
2622 state-point (1- b))
2623 (if (nth 3 state) ; in string
2624 (cperl-modify-syntax-type (1- b) cperl-st-punct))
2625 (goto-char (1+ b)))
2626 ;; 1+6+2+1+1+2=13 extra () before this:
2627 ;; "\\$\\(['{]\\)"
2628 ((match-beginning 14) ; ${
2629 (setq bb (match-beginning 0))
2630 (cperl-modify-syntax-type bb cperl-st-punct))
2631 ;; 1+6+2+1+1+2+1=14 extra () before this:
2632 ;; "\\(\\<sub[ \t\n\f]+\\|[&*$@%]\\)[a-zA-Z0-9_]*'")
2633 ((match-beginning 15) ; old $abc'efg syntax
2634 (setq bb (match-end 0)
2635 b (match-beginning 0)
2636 state (parse-partial-sexp
2637 state-point b nil nil state)
2638 state-point b)
2639 (if (nth 3 state) ; in string
2640 nil
2641 (put-text-property (1- bb) bb 'syntax-table cperl-st-word))
2642 (goto-char bb))
2643 ;; 1+6+2+1+1+2+1+1=15 extra () before this:
2644 ;; "__\\(END\\|DATA\\)__"
2645 (t ; __END__, __DATA__
2646 (setq bb (match-end 0)
2647 b (match-beginning 0)
2648 state (parse-partial-sexp
2649 state-point b nil nil state)
2650 state-point b)
2651 (if (or (nth 3 state) (nth 4 state))
2652 nil
2653 ;; (put-text-property b (1+ bb) 'syntax-type 'pod) ; Cheat
2654 (cperl-commentify b bb nil)
2655 (setq end t))
2656 (goto-char bb)))
2657 (if (> (point) max)
2658 (progn
2659 (if end
2660 (message "Garbage after __END__/__DATA__ ignored")
2661 (message "Unbalanced syntax found while scanning")
2662 (or (car err-l) (setcar err-l b)))
2663 (goto-char max))))
2664;;; (while (re-search-forward "\\(\\`\n?\\|\n\n\\)=" max t)
2665;;; (if (looking-at "\n*cut\\>")
2666;;; (progn
2667;;; (message "=cut is not preceded by a pod section")
2668;;; (setq err (point)))
2669;;; (beginning-of-line)
2670
2671;;; (setq b (point) bb b)
2672;;; (or (re-search-forward "\n\n=cut\\>" max 'toend)
2673;;; (message "Cannot find the end of a pod section"))
2674;;; (beginning-of-line 3)
2675;;; (setq e (point))
2676;;; (put-text-property b e 'in-pod t)
2677;;; (goto-char b)
2678;;; (while (re-search-forward "\n\n[ \t]" e t)
2679;;; (beginning-of-line)
2680;;; (put-text-property b (point) 'syntax-type 'pod)
2681;;; (cperl-put-do-not-fontify b (point))
2682;;; ;;(put-text-property (max (point-min) (1- b))
2683;;; ;; (point) cperl-do-not-fontify t)
2684;;; (if cperl-pod-here-fontify (put-text-property b (point) 'face face))
2685;;; (re-search-forward "\n\n[^ \t\f\n]" e 'toend)
2686;;; (beginning-of-line)
2687;;; (setq b (point)))
2688;;; (put-text-property (point) e 'syntax-type 'pod)
2689;;; (cperl-put-do-not-fontify (point) e)
2690;;; ;;(put-text-property (max (point-min) (1- (point)))
2691;;; ;; e cperl-do-not-fontify t)
2692;;; (if cperl-pod-here-fontify
2693;;; (progn (put-text-property (point) e 'face face)
2694;;; (goto-char bb)
2695;;; (if (looking-at
2696;;; "=[a-zA-Z0-9]+\\>[ \t]*\\(\\(\n?[^\n]\\)+\\)$")
2697;;; (put-text-property
2698;;; (match-beginning 1) (match-end 1)
2699;;; 'face head-face))
2700;;; (while (re-search-forward
2701;;; ;; One paragraph
2702;;; "\n\n=[a-zA-Z0-9]+\\>[ \t]*\\(\\(\n?[^\n]\\)+\\)$"
2703;;; e 'toend)
2704;;; (put-text-property
2705;;; (match-beginning 1) (match-end 1)
2706;;; 'face head-face))))
2707;;; (goto-char e)))
2708;;; (goto-char min)
2709;;; (while (re-search-forward
2710;;; ;; We exclude \n to avoid misrecognition inside quotes.
2711;;; "<<\\(\\([\"'`]\\)\\([^\"'`\n]*\\)\\2\\|\\(\\([a-zA-Z_][a-zA-Z_0-9]*\\)?\\)\\)"
2712;;; max t)
2713;;; (if (match-beginning 4)
2714;;; (setq b1 (match-beginning 4)
2715;;; e1 (match-end 4))
2716;;; (setq b1 (match-beginning 3)
2717;;; e1 (match-end 3)))
2718;;; (setq tag (buffer-substring b1 e1)
2719;;; qtag (regexp-quote tag))
2720;;; (cond (cperl-pod-here-fontify
883212ce 2721;;; (put-text-property b1 e1 'face font-lock-constant-face)
f83d2997
KH
2722;;; (cperl-put-do-not-fontify b1 e1)))
2723;;; (forward-line)
2724;;; (setq b (point))
2725;;; (cond ((re-search-forward (concat "^" qtag "$") max 'toend)
2726;;; (if cperl-pod-here-fontify
2727;;; (progn
2728;;; (put-text-property (match-beginning 0) (match-end 0)
883212ce 2729;;; 'face font-lock-constant-face)
f83d2997
KH
2730;;; (cperl-put-do-not-fontify b (match-end 0))
2731;;; ;;(put-text-property (max (point-min) (1- b))
2732;;; ;; (min (point-max)
2733;;; ;; (1+ (match-end 0)))
2734;;; ;; cperl-do-not-fontify t)
2735;;; (put-text-property b (match-beginning 0)
2736;;; 'face here-face)))
2737;;; (put-text-property b (match-beginning 0)
2738;;; 'syntax-type 'here-doc)
2739;;; (cperl-put-do-not-fontify b (match-beginning 0)))
2740;;; (t (message "End of here-document `%s' not found." tag))))
2741;;; (goto-char min)
2742;;; (while (re-search-forward
2743;;; "^[ \t]*format[ \t]*\\(\\([a-zA-Z0-9_]+[ \t]*\\)?\\)=[ \t]*$"
2744;;; max t)
2745;;; (setq b (point)
2746;;; name (buffer-substring (match-beginning 1)
2747;;; (match-end 1)))
2748;;; (cond ((re-search-forward (concat "^[.;]$") max 'toend)
2749;;; (if cperl-pod-here-fontify
2750;;; (progn
2751;;; (put-text-property b (match-end 0)
2752;;; 'face font-lock-string-face)
2753;;; (cperl-put-do-not-fontify b (match-end 0))))
2754;;; (put-text-property b (match-end 0)
2755;;; 'syntax-type 'format)
2756;;; (cperl-put-do-not-fontify b (match-beginning 0)))
2757;;; (t (message "End of format `%s' not found." name))))
2758 )
2759 (if (car err-l) (goto-char (car err-l))
2760 (or noninteractive
2761 (message "Scan for \"hard\" Perl constructions completed."))))
2762 (and (buffer-modified-p)
2763 (not modified)
2764 (set-buffer-modified-p nil))
2765 (set-syntax-table cperl-mode-syntax-table))
2766 (car err-l)))
2767
2768(defun cperl-backward-to-noncomment (lim)
2769 ;; Stops at lim or after non-whitespace that is not in comment
2770 (let (stop p)
2771 (while (and (not stop) (> (point) (or lim 1)))
2772 (skip-chars-backward " \t\n\f" lim)
2773 (setq p (point))
2774 (beginning-of-line)
2775 (if (or (looking-at "^[ \t]*\\(#\\|$\\)")
2776 (progn (cperl-to-comment-or-eol) (bolp)))
2777 nil ; Only comment, skip
2778 ;; Else
2779 (skip-chars-backward " \t")
2780 (if (< p (point)) (goto-char p))
2781 (setq stop t)))))
2782
2783(defun cperl-after-block-p (lim)
2784 ;; We suppose that the preceding char is }.
2785 (save-excursion
2786 (condition-case nil
2787 (progn
2788 (forward-sexp -1)
2789 (cperl-backward-to-noncomment lim)
2790 (or (eq (preceding-char) ?\) ) ; if () {}
2791 (and (eq (char-syntax (preceding-char)) ?w) ; else {}
2792 (progn
2793 (forward-sexp -1)
2794 (looking-at "\\(else\\|grep\\|map\\)\\>")))
2795 (cperl-after-expr-p lim)))
2796 (error nil))))
2797
2798(defun cperl-after-expr-p (&optional lim chars test)
2799 "Returns true if the position is good for start of expression.
2800TEST is the expression to evaluate at the found position. If absent,
2801CHARS is a string that contains good characters to have before us (however,
2802`}' is treated \"smartly\" if it is not in the list)."
2803 (let (stop p
2804 (lim (or lim (point-min))))
2805 (save-excursion
2806 (while (and (not stop) (> (point) lim))
2807 (skip-chars-backward " \t\n\f" lim)
2808 (setq p (point))
2809 (beginning-of-line)
2810 (if (looking-at "^[ \t]*\\(#\\|$\\)") nil ; Only comment, skip
2811 ;; Else: last iteration (What to do with labels?)
2812 (cperl-to-comment-or-eol)
2813 (skip-chars-backward " \t")
2814 (if (< p (point)) (goto-char p))
2815 (setq stop t)))
2816 (or (bobp)
2817 (progn
2818 (if test (eval test)
2819 (or (memq (preceding-char) (append (or chars "{;") nil))
2820 (and (eq (preceding-char) ?\})
2821 (cperl-after-block-p lim)))))))))
2822
2823(defun cperl-backward-to-start-of-continued-exp (lim)
2824 (if (memq (preceding-char) (append ")]}\"'`" nil))
2825 (forward-sexp -1))
2826 (beginning-of-line)
2827 (if (<= (point) lim)
2828 (goto-char (1+ lim)))
2829 (skip-chars-forward " \t"))
2830
2831\f
2832(defvar innerloop-done nil)
2833(defvar last-depth nil)
2834
2835(defun cperl-indent-exp ()
2836 "Simple variant of indentation of continued-sexp.
2837Should be slow. Will not indent comment if it starts at `comment-indent'
2838or looks like continuation of the comment on the previous line."
2839 (interactive)
2840 (save-excursion
2841 (let ((tmp-end (progn (end-of-line) (point))) top done)
2842 (save-excursion
2843 (beginning-of-line)
2844 (while (null done)
2845 (setq top (point))
2846 (while (= (nth 0 (parse-partial-sexp (point) tmp-end
2847 -1)) -1)
2848 (setq top (point))) ; Get the outermost parenths in line
2849 (goto-char top)
2850 (while (< (point) tmp-end)
2851 (parse-partial-sexp (point) tmp-end nil t) ; To start-sexp or eol
2852 (or (eolp) (forward-sexp 1)))
2853 (if (> (point) tmp-end) (progn (end-of-line) (setq tmp-end (point)))
2854 (setq done t)))
2855 (goto-char tmp-end)
2856 (setq tmp-end (point-marker)))
2857 (cperl-indent-region (point) tmp-end))))
2858
2859(defun cperl-indent-region (start end)
2860 "Simple variant of indentation of region in CPerl mode.
2861Should be slow. Will not indent comment if it starts at `comment-indent'
2862or looks like continuation of the comment on the previous line.
2863Indents all the lines whose first character is between START and END
2864inclusive."
2865 (interactive "r")
2866 (save-excursion
2867 (let (st comm indent-info old-comm-indent new-comm-indent
2868 (pm 0) (imenu-scanning-message "Indenting... (%3d%%)"))
2869 (goto-char start)
2870 (setq old-comm-indent (and (cperl-to-comment-or-eol)
2871 (current-column))
2872 new-comm-indent old-comm-indent)
2873 (goto-char start)
2874 (or (bolp) (beginning-of-line 2))
2875 (or (fboundp 'imenu-progress-message)
2876 (message "Indenting... For feedback load `imenu'..."))
2877 (while (and (<= (point) end) (not (eobp))) ; bol to check start
2878 (and (fboundp 'imenu-progress-message)
2879 (imenu-progress-message
2880 pm (/ (* 100 (- (point) start)) (- end start -1))))
2881 (setq st (point)
2882 indent-info nil
2883 ) ; Believe indentation of the current
2884 (if (and (setq comm (looking-at "[ \t]*#"))
2885 (or (eq (current-indentation) (or old-comm-indent
2886 comment-column))
2887 (setq old-comm-indent nil)))
2888 (if (and old-comm-indent
2889 (= (current-indentation) old-comm-indent)
2890 (not (eq (get-text-property (point) 'syntax-type) 'pod)))
2891 (let ((comment-column new-comm-indent))
2892 (indent-for-comment)))
2893 (progn
2894 (cperl-indent-line 'indent-info)
2895 (or comm
2896 (progn
2897 (if (setq old-comm-indent
2898 (and (cperl-to-comment-or-eol)
2899 (not (memq (get-text-property (point)
2900 'syntax-type)
2901 '(pod here-doc)))
2902 (current-column)))
2903 (progn (indent-for-comment)
2904 (skip-chars-backward " \t")
2905 (skip-chars-backward "#")
2906 (setq new-comm-indent (current-column))))))))
2907 (beginning-of-line 2))
2908 (if (fboundp 'imenu-progress-message)
2909 (imenu-progress-message pm 100)
2910 (message nil)))))
2911
2912;;(defun cperl-slash-is-regexp (&optional pos)
2913;; (save-excursion
2914;; (goto-char (if pos pos (1- (point))))
2915;; (and
2916;; (not (memq (get-text-property (point) 'face)
2917;; '(font-lock-string-face font-lock-comment-face)))
2918;; (cperl-after-expr-p nil nil '
2919;; (or (looking-at "[^]a-zA-Z0-9_)}]")
2920;; (eq (get-text-property (point) 'face)
2921;; 'font-lock-keyword-face))))))
2922
2923;; Stolen from lisp-mode with a lot of improvements
2924
2925(defun cperl-fill-paragraph (&optional justify iteration)
2926 "Like \\[fill-paragraph], but handle CPerl comments.
2927If any of the current line is a comment, fill the comment or the
2928block of it that point is in, preserving the comment's initial
2929indentation and initial hashes. Behaves usually outside of comment."
2930 (interactive "P")
2931 (let (
2932 ;; Non-nil if the current line contains a comment.
2933 has-comment
2934
2935 ;; If has-comment, the appropriate fill-prefix for the comment.
2936 comment-fill-prefix
2937 ;; Line that contains code and comment (or nil)
2938 start
2939 c spaces len dc (comment-column comment-column))
2940 ;; Figure out what kind of comment we are looking at.
2941 (save-excursion
2942 (beginning-of-line)
2943 (cond
2944
2945 ;; A line with nothing but a comment on it?
2946 ((looking-at "[ \t]*#[# \t]*")
2947 (setq has-comment t
2948 comment-fill-prefix (buffer-substring (match-beginning 0)
2949 (match-end 0))))
2950
2951 ;; A line with some code, followed by a comment? Remember that the
2952 ;; semi which starts the comment shouldn't be part of a string or
2953 ;; character.
2954 ((cperl-to-comment-or-eol)
2955 (setq has-comment t)
2956 (looking-at "#+[ \t]*")
2957 (setq start (point) c (current-column)
2958 comment-fill-prefix
2959 (concat (make-string (current-column) ?\ )
2960 (buffer-substring (match-beginning 0) (match-end 0)))
2961 spaces (progn (skip-chars-backward " \t")
2962 (buffer-substring (point) start))
2963 dc (- c (current-column)) len (- start (point))
2964 start (point-marker))
2965 (delete-char len)
2966 (insert (make-string dc ?-)))))
2967 (if (not has-comment)
2968 (fill-paragraph justify) ; Do the usual thing outside of comment
2969 ;; Narrow to include only the comment, and then fill the region.
2970 (save-restriction
2971 (narrow-to-region
2972 ;; Find the first line we should include in the region to fill.
2973 (if start (progn (beginning-of-line) (point))
2974 (save-excursion
2975 (while (and (zerop (forward-line -1))
2976 (looking-at "^[ \t]*#+[ \t]*[^ \t\n#]")))
2977 ;; We may have gone to far. Go forward again.
2978 (or (looking-at "^[ \t]*#+[ \t]*[^ \t\n#]")
2979 (forward-line 1))
2980 (point)))
2981 ;; Find the beginning of the first line past the region to fill.
2982 (save-excursion
2983 (while (progn (forward-line 1)
2984 (looking-at "^[ \t]*#+[ \t]*[^ \t\n#]")))
2985 (point)))
2986 ;; Remove existing hashes
2987 (goto-char (point-min))
2988 (while (progn (forward-line 1) (< (point) (point-max)))
2989 (skip-chars-forward " \t")
2990 (and (looking-at "#+")
2991 (delete-char (- (match-end 0) (match-beginning 0)))))
2992
2993 ;; Lines with only hashes on them can be paragraph boundaries.
2994 (let ((paragraph-start (concat paragraph-start "\\|^[ \t#]*$"))
2995 (paragraph-separate (concat paragraph-start "\\|^[ \t#]*$"))
2996 (fill-prefix comment-fill-prefix))
2997 (fill-paragraph justify)))
2998 (if (and start)
2999 (progn
3000 (goto-char start)
3001 (if (> dc 0)
3002 (progn (delete-char dc) (insert spaces)))
3003 (if (or (= (current-column) c) iteration) nil
3004 (setq comment-column c)
3005 (indent-for-comment)
3006 ;; Repeat once more, flagging as iteration
3007 (cperl-fill-paragraph justify t)))))))
3008
3009(defun cperl-do-auto-fill ()
3010 ;; Break out if the line is short enough
3011 (if (> (save-excursion
3012 (end-of-line)
3013 (current-column))
3014 fill-column)
3015 (let ((c (save-excursion (beginning-of-line)
3016 (cperl-to-comment-or-eol) (point)))
3017 (s (memq (following-char) '(?\ ?\t))) marker)
3018 (if (>= c (point)) nil
3019 (setq marker (point-marker))
3020 (cperl-fill-paragraph)
3021 (goto-char marker)
3022 ;; Is not enough, sometimes marker is a start of line
3023 (if (bolp) (progn (re-search-forward "#+[ \t]*")
3024 (goto-char (match-end 0))))
3025 ;; Following space could have gone:
3026 (if (or (not s) (memq (following-char) '(?\ ?\t))) nil
3027 (insert " ")
3028 (backward-char 1))
3029 ;; Previous space could have gone:
3030 (or (memq (preceding-char) '(?\ ?\t)) (insert " "))))))
3031
3032(defvar imenu-example--function-name-regexp-perl
3033 (concat
3034 "^\\("
3035 "[ \t]*\\(sub\\|package\\)[ \t\n]+\\([a-zA-Z_0-9:']+\\)[ \t]*\\(([^()]*)[ \t]*\\)?"
3036 "\\|"
3037 "=head\\([12]\\)[ \t]+\\([^\n]+\\)$"
3038 "\\)"))
3039
3040(defun cperl-imenu-addback (lst &optional isback name)
3041 ;; We suppose that the lst is a DAG, unless the first element only
3042 ;; loops back, and ISBACK is set. Thus this function cannot be
3043 ;; applied twice without ISBACK set.
3044 (cond ((not cperl-imenu-addback) lst)
3045 (t
3046 (or name
3047 (setq name "+++BACK+++"))
3048 (mapcar (function (lambda (elt)
3049 (if (and (listp elt) (listp (cdr elt)))
3050 (progn
3051 ;; In the other order it goes up
3052 ;; one level only ;-(
3053 (setcdr elt (cons (cons name lst)
3054 (cdr elt)))
3055 (cperl-imenu-addback (cdr elt) t name)
3056 ))))
3057 (if isback (cdr lst) lst))
3058 lst)))
3059
3060(defun imenu-example--create-perl-index (&optional regexp)
3061 (require 'cl)
3062 (require 'imenu) ; May be called from TAGS creator
3063 (let ((index-alist '()) (index-pack-alist '()) (index-pod-alist '())
3064 (index-unsorted-alist '()) (i-s-f (default-value 'imenu-sort-function))
3065 (index-meth-alist '()) meth
3066 packages ends-ranges p
3067 (prev-pos 0) char fchar index index1 name (end-range 0) package)
3068 (goto-char (point-min))
3069 (if noninteractive
3070 (message "Scanning Perl for index")
3071 (imenu-progress-message prev-pos 0))
3072 ;; Search for the function
3073 (progn ;;save-match-data
3074 (while (re-search-forward
3075 (or regexp imenu-example--function-name-regexp-perl)
3076 nil t)
3077 (or noninteractive
3078 (imenu-progress-message prev-pos))
3079 ;;(backward-up-list 1)
3080 (cond
3081 ((and ; Skip some noise if building tags
3082 (match-beginning 2) ; package or sub
3083 (eq (char-after (match-beginning 2)) ?p) ; package
3084 (not (save-match-data
3085 (looking-at "[ \t\n]*;")))) ; Plain text word 'package'
3086 nil)
3087 ((and
3088 (match-beginning 2) ; package or sub
3089 ;; Skip if quoted (will not skip multi-line ''-comments :-():
3090 (null (get-text-property (match-beginning 1) 'syntax-table))
3091 (null (get-text-property (match-beginning 1) 'syntax-type))
3092 (null (get-text-property (match-beginning 1) 'in-pod)))
3093 (save-excursion
3094 (goto-char (match-beginning 2))
3095 (setq fchar (following-char))
3096 )
3097 ;; (if (looking-at "([^()]*)[ \t\n\f]*")
3098 ;; (goto-char (match-end 0))) ; Messes what follows
3099 (setq char (following-char)
3100 meth nil
3101 p (point))
3102 (while (and ends-ranges (>= p (car ends-ranges)))
3103 ;; delete obsolete entries
3104 (setq ends-ranges (cdr ends-ranges) packages (cdr packages)))
3105 (setq package (or (car packages) "")
3106 end-range (or (car ends-ranges) 0))
3107 (if (eq fchar ?p)
3108 (setq name (buffer-substring (match-beginning 3) (match-end 3))
3109 name (progn
3110 (set-text-properties 0 (length name) nil name)
3111 name)
3112 package (concat name "::")
3113 name (concat "package " name)
3114 end-range
3115 (save-excursion
3116 (parse-partial-sexp (point) (point-max) -1) (point))
3117 ends-ranges (cons end-range ends-ranges)
3118 packages (cons package packages)))
3119 ;; )
3120 ;; Skip this function name if it is a prototype declaration.
3121 (if (and (eq fchar ?s) (eq char ?\;)) nil
3122 (setq index (imenu-example--name-and-position))
3123 (if (eq fchar ?p) nil
3124 (setq name (buffer-substring (match-beginning 3) (match-end 3)))
3125 (set-text-properties 0 (length name) nil name)
3126 (cond ((string-match "[:']" name)
3127 (setq meth t))
3128 ((> p end-range) nil)
3129 (t
3130 (setq name (concat package name) meth t))))
3131 (setcar index name)
3132 (if (eq fchar ?p)
3133 (push index index-pack-alist)
3134 (push index index-alist))
3135 (if meth (push index index-meth-alist))
3136 (push index index-unsorted-alist)))
3137 ((match-beginning 5) ; Pod section
3138 ;; (beginning-of-line)
3139 (setq index (imenu-example--name-and-position)
3140 name (buffer-substring (match-beginning 6) (match-end 6)))
3141 (set-text-properties 0 (length name) nil name)
3142 (if (eq (char-after (match-beginning 5)) ?2)
3143 (setq name (concat " " name)))
3144 (setcar index name)
3145 (setq index1 (cons (concat "=" name) (cdr index)))
3146 (push index index-pod-alist)
3147 (push index1 index-unsorted-alist)))))
3148 (or noninteractive
3149 (imenu-progress-message prev-pos 100))
3150 (setq index-alist
3151 (if (default-value 'imenu-sort-function)
3152 (sort index-alist (default-value 'imenu-sort-function))
3153 (nreverse index-alist)))
3154 (and index-pod-alist
3155 (push (cons "+POD headers+..."
3156 (nreverse index-pod-alist))
3157 index-alist))
3158 (and (or index-pack-alist index-meth-alist)
3159 (let ((lst index-pack-alist) hier-list pack elt group name)
3160 ;; Remove "package ", reverse and uniquify.
3161 (while lst
3162 (setq elt (car lst) lst (cdr lst) name (substring (car elt) 8))
3163 (if (assoc name hier-list) nil
3164 (setq hier-list (cons (cons name (cdr elt)) hier-list))))
3165 (setq lst index-meth-alist)
3166 (while lst
3167 (setq elt (car lst) lst (cdr lst))
3168 (cond ((string-match "\\(::\\|'\\)[_a-zA-Z0-9]+$" (car elt))
3169 (setq pack (substring (car elt) 0 (match-beginning 0)))
3170 (if (setq group (assoc pack hier-list))
3171 (if (listp (cdr group))
3172 ;; Have some functions already
3173 (setcdr group
3174 (cons (cons (substring
3175 (car elt)
3176 (+ 2 (match-beginning 0)))
3177 (cdr elt))
3178 (cdr group)))
3179 (setcdr group (list (cons (substring
3180 (car elt)
3181 (+ 2 (match-beginning 0)))
3182 (cdr elt)))))
3183 (setq hier-list
3184 (cons (cons pack
3185 (list (cons (substring
3186 (car elt)
3187 (+ 2 (match-beginning 0)))
3188 (cdr elt))))
3189 hier-list))))))
3190 (push (cons "+Hierarchy+..."
3191 hier-list)
3192 index-alist)))
3193 (and index-pack-alist
3194 (push (cons "+Packages+..."
3195 (nreverse index-pack-alist))
3196 index-alist))
3197 (and (or index-pack-alist index-pod-alist
3198 (default-value 'imenu-sort-function))
3199 index-unsorted-alist
3200 (push (cons "+Unsorted List+..."
3201 (nreverse index-unsorted-alist))
3202 index-alist))
3203 (cperl-imenu-addback index-alist)))
3204
3205(defvar cperl-compilation-error-regexp-alist
3206 ;; This look like a paranoiac regexp: could anybody find a better one? (which WORK).
3207 '(("^[^\n]* \\(file\\|at\\) \\([^ \t\n]+\\) [^\n]*line \\([0-9]+\\)[\\., \n]"
3208 2 3))
3209 "Alist that specifies how to match errors in perl output.")
3210
3211(if (fboundp 'eval-after-load)
3212 (eval-after-load
3213 "mode-compile"
3214 '(setq perl-compilation-error-regexp-alist
3215 cperl-compilation-error-regexp-alist)))
3216
3217
3218(defvar cperl-faces-init nil)
3219
3220(defun cperl-windowed-init ()
3221 "Initialization under windowed version."
3222 (add-hook 'font-lock-mode-hook
3223 (function
3224 (lambda ()
3225 (if (or
3226 (eq major-mode 'perl-mode)
3227 (eq major-mode 'cperl-mode))
3228 (progn
3229 (or cperl-faces-init (cperl-init-faces))))))))
3230
3231(defvar perl-font-lock-keywords-1 nil
3232 "Additional expressions to highlight in Perl mode. Minimal set.")
3233(defvar perl-font-lock-keywords nil
3234 "Additional expressions to highlight in Perl mode. Default set.")
3235(defvar perl-font-lock-keywords-2 nil
3236 "Additional expressions to highlight in Perl mode. Maximal set")
3237
3238(defun cperl-init-faces ()
3239 (condition-case nil
3240 (progn
3241 (require 'font-lock)
3242 (and (fboundp 'font-lock-fontify-anchored-keywords)
3243 (featurep 'font-lock-extra)
3244 (message "You have an obsolete package `font-lock-extra'. Install `choose-color'."))
3245 (let (t-font-lock-keywords t-font-lock-keywords-1 font-lock-anchored)
3246 ;;(defvar cperl-font-lock-enhanced nil
3247 ;; "Set to be non-nil if font-lock allows active highlights.")
3248 (if (fboundp 'font-lock-fontify-anchored-keywords)
3249 (setq font-lock-anchored t))
3250 (setq
3251 t-font-lock-keywords
3252 (list
3253 (cons
3254 (concat
3255 "\\(^\\|[^$@%&\\]\\)\\<\\("
3256 (mapconcat
3257 'identity
3258 '("if" "until" "while" "elsif" "else" "unless" "for"
3259 "foreach" "continue" "exit" "die" "last" "goto" "next"
3260 "redo" "return" "local" "exec" "sub" "do" "dump" "use"
3261 "require" "package" "eval" "my" "BEGIN" "END")
3262 "\\|") ; Flow control
3263 "\\)\\>") 2) ; was "\\)[ \n\t;():,\|&]"
3264 ; In what follows we use `type' style
3265 ; for overwritable builtins
3266 (list
3267 (concat
3268 "\\(^\\|[^$@%&\\]\\)\\<\\("
3269 ;; "CORE" "__FILE__" "__LINE__" "abs" "accept" "alarm"
3270 ;; "and" "atan2" "bind" "binmode" "bless" "caller"
3271 ;; "chdir" "chmod" "chown" "chr" "chroot" "close"
3272 ;; "closedir" "cmp" "connect" "continue" "cos" "crypt"
3273 ;; "dbmclose" "dbmopen" "die" "dump" "endgrent"
3274 ;; "endhostent" "endnetent" "endprotoent" "endpwent"
3275 ;; "endservent" "eof" "eq" "exec" "exit" "exp" "fcntl"
3276 ;; "fileno" "flock" "fork" "formline" "ge" "getc"
3277 ;; "getgrent" "getgrgid" "getgrnam" "gethostbyaddr"
3278 ;; "gethostbyname" "gethostent" "getlogin"
3279 ;; "getnetbyaddr" "getnetbyname" "getnetent"
3280 ;; "getpeername" "getpgrp" "getppid" "getpriority"
3281 ;; "getprotobyname" "getprotobynumber" "getprotoent"
3282 ;; "getpwent" "getpwnam" "getpwuid" "getservbyname"
3283 ;; "getservbyport" "getservent" "getsockname"
3284 ;; "getsockopt" "glob" "gmtime" "gt" "hex" "index" "int"
3285 ;; "ioctl" "join" "kill" "lc" "lcfirst" "le" "length"
3286 ;; "link" "listen" "localtime" "log" "lstat" "lt"
3287 ;; "mkdir" "msgctl" "msgget" "msgrcv" "msgsnd" "ne"
3288 ;; "not" "oct" "open" "opendir" "or" "ord" "pack" "pipe"
3289 ;; "quotemeta" "rand" "read" "readdir" "readline"
3290 ;; "readlink" "readpipe" "recv" "ref" "rename" "require"
3291 ;; "reset" "reverse" "rewinddir" "rindex" "rmdir" "seek"
3292 ;; "seekdir" "select" "semctl" "semget" "semop" "send"
3293 ;; "setgrent" "sethostent" "setnetent" "setpgrp"
3294 ;; "setpriority" "setprotoent" "setpwent" "setservent"
3295 ;; "setsockopt" "shmctl" "shmget" "shmread" "shmwrite"
3296 ;; "shutdown" "sin" "sleep" "socket" "socketpair"
3297 ;; "sprintf" "sqrt" "srand" "stat" "substr" "symlink"
3298 ;; "syscall" "sysread" "system" "syswrite" "tell"
3299 ;; "telldir" "time" "times" "truncate" "uc" "ucfirst"
3300 ;; "umask" "unlink" "unpack" "utime" "values" "vec"
3301 ;; "wait" "waitpid" "wantarray" "warn" "write" "x" "xor"
3302 "a\\(bs\\|ccept\\|tan2\\|larm\\|nd\\)\\|"
3303 "b\\(in\\(d\\|mode\\)\\|less\\)\\|"
3304 "c\\(h\\(r\\(\\|oot\\)\\|dir\\|mod\\|own\\)\\|aller\\|rypt\\|"
3305 "lose\\(\\|dir\\)\\|mp\\|o\\(s\\|n\\(tinue\\|nect\\)\\)\\)\\|"
3306 "CORE\\|d\\(ie\\|bm\\(close\\|open\\)\\|ump\\)\\|"
3307 "e\\(x\\(p\\|it\\|ec\\)\\|q\\|nd\\(p\\(rotoent\\|went\\)\\|"
3308 "hostent\\|servent\\|netent\\|grent\\)\\|of\\)\\|"
3309 "f\\(ileno\\|cntl\\|lock\\|or\\(k\\|mline\\)\\)\\|"
3310 "g\\(t\\|lob\\|mtime\\|e\\(\\|t\\(p\\(pid\\|r\\(iority\\|"
3311 "oto\\(byn\\(ame\\|umber\\)\\|ent\\)\\)\\|eername\\|w"
3312 "\\(uid\\|ent\\|nam\\)\\|grp\\)\\|host\\(by\\(addr\\|name\\)\\|"
3313 "ent\\)\\|s\\(erv\\(by\\(port\\|name\\)\\|ent\\)\\|"
3314 "ock\\(name\\|opt\\)\\)\\|c\\|login\\|net\\(by\\(addr\\|name\\)\\|"
3315 "ent\\)\\|gr\\(ent\\|nam\\|gid\\)\\)\\)\\)\\|"
3316 "hex\\|i\\(n\\(t\\|dex\\)\\|octl\\)\\|join\\|kill\\|"
3317 "l\\(i\\(sten\\|nk\\)\\|stat\\|c\\(\\|first\\)\\|t\\|e"
3318 "\\(\\|ngth\\)\\|o\\(caltime\\|g\\)\\)\\|m\\(sg\\(rcv\\|snd\\|"
3319 "ctl\\|get\\)\\|kdir\\)\\|n\\(e\\|ot\\)\\|o\\(pen\\(\\|dir\\)\\|"
3320 "r\\(\\|d\\)\\|ct\\)\\|p\\(ipe\\|ack\\)\\|quotemeta\\|"
3321 "r\\(index\\|and\\|mdir\\|e\\(quire\\|ad\\(pipe\\|\\|lin"
3322 "\\(k\\|e\\)\\|dir\\)\\|set\\|cv\\|verse\\|f\\|winddir\\|name"
3323 "\\)\\)\\|s\\(printf\\|qrt\\|rand\\|tat\\|ubstr\\|e\\(t\\(p\\(r"
3324 "\\(iority\\|otoent\\)\\|went\\|grp\\)\\|hostent\\|s\\(ervent\\|"
3325 "ockopt\\)\\|netent\\|grent\\)\\|ek\\(\\|dir\\)\\|lect\\|"
3326 "m\\(ctl\\|op\\|get\\)\\|nd\\)\\|h\\(utdown\\|m\\(read\\|ctl\\|"
3327 "write\\|get\\)\\)\\|y\\(s\\(read\\|call\\|tem\\|write\\)\\|"
3328 "mlink\\)\\|in\\|leep\\|ocket\\(pair\\|\\)\\)\\|t\\(runcate\\|"
3329 "ell\\(\\|dir\\)\\|ime\\(\\|s\\)\\)\\|u\\(c\\(\\|first\\)\\|"
3330 "time\\|mask\\|n\\(pack\\|link\\)\\)\\|v\\(alues\\|ec\\)\\|"
3331 "w\\(a\\(rn\\|it\\(pid\\|\\)\\|ntarray\\)\\|rite\\)\\|"
3332 "x\\(\\|or\\)\\|__\\(FILE__\\|LINE__\\|PACKAGE__\\)"
3333 "\\)\\>") 2 'font-lock-type-face)
3334 ;; In what follows we use `other' style
3335 ;; for nonoverwritable builtins
3336 ;; Somehow 's', 'm' are not auto-generated???
3337 (list
3338 (concat
3339 "\\(^\\|[^$@%&\\]\\)\\<\\("
3340 ;; "AUTOLOAD" "BEGIN" "DESTROY" "END" "__END__" "chomp"
3341 ;; "chop" "defined" "delete" "do" "each" "else" "elsif"
3342 ;; "eval" "exists" "for" "foreach" "format" "goto"
3343 ;; "grep" "if" "keys" "last" "local" "map" "my" "next"
3344 ;; "no" "package" "pop" "pos" "print" "printf" "push"
3345 ;; "q" "qq" "qw" "qx" "redo" "return" "scalar" "shift"
3346 ;; "sort" "splice" "split" "study" "sub" "tie" "tr"
3347 ;; "undef" "unless" "unshift" "untie" "until" "use"
3348 ;; "while" "y"
3349 "AUTOLOAD\\|BEGIN\\|cho\\(p\\|mp\\)\\|d\\(e\\(fined\\|lete\\)\\|"
3350 "o\\)\\|DESTROY\\|e\\(ach\\|val\\|xists\\|ls\\(e\\|if\\)\\)\\|"
3351 "END\\|for\\(\\|each\\|mat\\)\\|g\\(rep\\|oto\\)\\|if\\|keys\\|"
3352 "l\\(ast\\|ocal\\)\\|m\\(ap\\|y\\)\\|n\\(ext\\|o\\)\\|"
3353 "p\\(ackage\\|rint\\(\\|f\\)\\|ush\\|o\\(p\\|s\\)\\)\\|"
3354 "q\\(\\|q\\|w\\|x\\)\\|re\\(turn\\|do\\)\\|s\\(pli\\(ce\\|t\\)\\|"
3355 "calar\\|tudy\\|ub\\|hift\\|ort\\)\\|t\\(r\\|ie\\)\\|"
3356 "u\\(se\\|n\\(shift\\|ti\\(l\\|e\\)\\|def\\|less\\)\\)\\|"
3357 "while\\|y\\|__\\(END\\|DATA\\)__" ;__DATA__ added manually
3358 "\\|[sm]" ; Added manually
3359 "\\)\\>") 2 'font-lock-other-type-face)
3360 ;; (mapconcat 'identity
3361 ;; '("#endif" "#else" "#ifdef" "#ifndef" "#if"
3362 ;; "#include" "#define" "#undef")
3363 ;; "\\|")
3364 '("-[rwxoRWXOezsfdlpSbctugkTBMAC]\\>\\([ \t]+_\\>\\)?" 0
3365 font-lock-function-name-face keep) ; Not very good, triggers at "[a-z]"
3366 '("\\<sub[ \t]+\\([^ \t{;]+\\)[ \t]*\\(([^()]*)[ \t]*\\)?[#{\n]" 1
3367 font-lock-function-name-face)
3368 '("\\<\\(package\\|require\\|use\\|import\\|no\\|bootstrap\\)[ \t]+\\([a-zA-z_][a-zA-z_0-9:]*\\)[ \t;]" ; require A if B;
3369 2 font-lock-function-name-face)
3370 '("^[ \t]*format[ \t]+\\([a-zA-z_][a-zA-z_0-9:]*\\)[ \t]*=[ \t]*$"
3371 1 font-lock-function-name-face)
3372 (cond ((featurep 'font-lock-extra)
3373 '("\\([]}\\\\%@>*&]\\|\\$[a-zA-Z0-9_:]*\\)[ \t]*{[ \t]*\\(-?[a-zA-Z0-9_:]+\\)[ \t]*}"
3374 (2 font-lock-string-face t)
3375 (0 '(restart 2 t)))) ; To highlight $a{bc}{ef}
3376 (font-lock-anchored
3377 '("\\([]}\\\\%@>*&]\\|\\$[a-zA-Z0-9_:]*\\)[ \t]*{[ \t]*\\(-?[a-zA-Z0-9_:]+\\)[ \t]*}"
3378 (2 font-lock-string-face t)
3379 ("\\=[ \t]*{[ \t]*\\(-?[a-zA-Z0-9_:]+\\)[ \t]*}"
3380 nil nil
3381 (1 font-lock-string-face t))))
3382 (t '("\\([]}\\\\%@>*&]\\|\\$[a-zA-Z0-9_:]*\\)[ \t]*{[ \t]*\\(-?[a-zA-Z0-9_:]+\\)[ \t]*}"
3383 2 font-lock-string-face t)))
3384 '("[ \t{,(]\\(-?[a-zA-Z0-9_:]+\\)[ \t]*=>" 1
3385 font-lock-string-face t)
3386 '("^[ \t]*\\([a-zA-Z0-9_]+[ \t]*:\\)[ \t]*\\($\\|{\\|\\<\\(until\\|while\\|for\\(each\\)?\\|do\\)\\>\\)" 1
883212ce 3387 font-lock-constant-face) ; labels
f83d2997 3388 '("\\<\\(continue\\|next\\|last\\|redo\\|goto\\)\\>[ \t]+\\([a-zA-Z0-9_:]+\\)" ; labels as targets
883212ce 3389 2 font-lock-constant-face)
f83d2997
KH
3390 (cond ((featurep 'font-lock-extra)
3391 '("^[ \t]*\\(my\\|local\\)[ \t]*\\(([ \t]*\\)?\\([$@%*][a-zA-Z0-9_:]+\\)\\([ \t]*,\\)?"
3392 (3 font-lock-variable-name-face)
3393 (4 '(another 4 nil
3394 ("\\=[ \t]*,[ \t]*\\([$@%*][a-zA-Z0-9_:]+\\)\\([ \t]*,\\)?"
3395 (1 font-lock-variable-name-face)
3396 (2 '(restart 2 nil) nil t)))
3397 nil t))) ; local variables, multiple
3398 (font-lock-anchored
3399 '("^[ \t{}]*\\(my\\|local\\)[ \t]*\\(([ \t]*\\)?\\([$@%*][a-zA-Z0-9_:]+\\)"
3400 (3 font-lock-variable-name-face)
3401 ("\\=[ \t]*,[ \t]*\\([$@%*][a-zA-Z0-9_:]+\\)"
3402 nil nil
3403 (1 font-lock-variable-name-face))))
3404 (t '("^[ \t{}]*\\(my\\|local\\)[ \t]*\\(([ \t]*\\)?\\([$@%*][a-zA-Z0-9_:]+\\)"
3405 3 font-lock-variable-name-face)))
3406 '("\\<for\\(each\\)?[ \t]*\\(\\$[a-zA-Z_][a-zA-Z_0-9]*\\)[ \t]*("
3407 2 font-lock-variable-name-face)))
3408 (setq
3409 t-font-lock-keywords-1
3410 (and (fboundp 'turn-on-font-lock) ; Check for newer font-lock
3411 (not cperl-xemacs-p) ; not yet as of XEmacs 19.12
3412 '(
3413 ("\\(\\([@%]\\|\$#\\)[a-zA-Z_:][a-zA-Z0-9_:]*\\)" 1
3414 (if (eq (char-after (match-beginning 2)) ?%)
3415 font-lock-other-emphasized-face
3416 font-lock-emphasized-face)
3417 t) ; arrays and hashes
3418 ("\\(\\([$@]+\\)[a-zA-Z_:][a-zA-Z0-9_:]*\\)[ \t]*\\([[{]\\)"
3419 1
3420 (if (= (- (match-end 2) (match-beginning 2)) 1)
3421 (if (eq (char-after (match-beginning 3)) ?{)
3422 font-lock-other-emphasized-face
3423 font-lock-emphasized-face) ; arrays and hashes
3424 font-lock-variable-name-face) ; Just to put something
3425 t)
3426 ;;("\\([smy]\\|tr\\)\\([^a-z_A-Z0-9]\\)\\(\\([^\n\\]*||\\)\\)\\2")
3427 ;;; Too much noise from \s* @s[ and friends
3428 ;;("\\(\\<\\([msy]\\|tr\\)[ \t]*\\([^ \t\na-zA-Z0-9_]\\)\\|\\(/\\)\\)"
3429 ;;(3 font-lock-function-name-face t t)
3430 ;;(4
3431 ;; (if (cperl-slash-is-regexp)
3432 ;; font-lock-function-name-face 'default) nil t))
3433 )))
3434 (setq perl-font-lock-keywords-1 t-font-lock-keywords
3435 perl-font-lock-keywords perl-font-lock-keywords-1
3436 perl-font-lock-keywords-2 (append
3437 t-font-lock-keywords
3438 t-font-lock-keywords-1)))
3439 (if (fboundp 'ps-print-buffer) (cperl-ps-print-init))
3440 (if (or (featurep 'choose-color) (featurep 'font-lock-extra))
3441 (font-lock-require-faces
3442 (list
3443 ;; Color-light Color-dark Gray-light Gray-dark Mono
3444 (list 'font-lock-comment-face
3445 ["Firebrick" "OrangeRed" "DimGray" "Gray80"]
3446 nil
3447 [nil nil t t t]
3448 [nil nil t t t]
3449 nil)
3450 (list 'font-lock-string-face
3451 ["RosyBrown" "LightSalmon" "Gray50" "LightGray"]
3452 nil
3453 nil
3454 [nil nil t t t]
3455 nil)
3456 (list 'font-lock-keyword-face
3457 ["Purple" "LightSteelBlue" "DimGray" "Gray90"]
3458 nil
3459 [nil nil t t t]
3460 nil
3461 nil)
3462 (list 'font-lock-function-name-face
3463 (vector
3464 "Blue" "LightSkyBlue" "Gray50" "LightGray"
3465 (cdr (assq 'background-color ; if mono
3466 (frame-parameters))))
3467 (vector
3468 nil nil nil nil
3469 (cdr (assq 'foreground-color ; if mono
3470 (frame-parameters))))
3471 [nil nil t t t]
3472 nil
3473 nil)
3474 (list 'font-lock-variable-name-face
3475 ["DarkGoldenrod" "LightGoldenrod" "DimGray" "Gray90"]
3476 nil
3477 [nil nil t t t]
3478 [nil nil t t t]
3479 nil)
3480 (list 'font-lock-type-face
3481 ["DarkOliveGreen" "PaleGreen" "DimGray" "Gray80"]
3482 nil
3483 [nil nil t t t]
3484 nil
3485 [nil nil t t t]
3486 )
883212ce 3487 (list 'font-lock-constant-face
f83d2997
KH
3488 ["CadetBlue" "Aquamarine" "Gray50" "LightGray"]
3489 nil
3490 [nil nil t t t]
3491 nil
3492 [nil nil t t t]
3493 )
3494 (list 'font-lock-other-type-face
3495 ["chartreuse3" ("orchid1" "orange")
3496 nil "Gray80"]
3497 [nil nil "gray90"]
3498 [nil nil nil t t]
3499 [nil nil t t]
3500 [nil nil t t t]
3501 )
3502 (list 'font-lock-emphasized-face
3503 ["blue" "yellow" nil "Gray80"]
3504 ["lightyellow2" ("navy" "os2blue" "darkgreen")
3505 "gray90"]
3506 t
3507 nil
3508 nil)
3509 (list 'font-lock-other-emphasized-face
3510 ["red" "red" nil "Gray80"]
3511 ["lightyellow2" ("navy" "os2blue" "darkgreen")
3512 "gray90"]
3513 t
3514 t
3515 nil)))
3516 (defvar cperl-guessed-background nil
3517 "Display characteristics as guessed by cperl.")
3518 (or (fboundp 'x-color-defined-p)
3519 (defalias 'x-color-defined-p
3520 (cond ((fboundp 'color-defined-p) 'color-defined-p)
3521 ;; XEmacs >= 19.12
3522 ((fboundp 'valid-color-name-p) 'valid-color-name-p)
3523 ;; XEmacs 19.11
3524 (t 'x-valid-color-name-p))))
883212ce 3525 (defvar font-lock-constant-face 'font-lock-constant-face)
f83d2997
KH
3526 (defvar font-lock-variable-name-face 'font-lock-variable-name-face)
3527 (or (boundp 'font-lock-type-face)
3528 (defconst font-lock-type-face
3529 'font-lock-type-face
3530 "Face to use for data types.")
3531 )
3532 (or (boundp 'font-lock-other-type-face)
3533 (defconst font-lock-other-type-face
3534 'font-lock-other-type-face
3535 "Face to use for data types from another group.")
3536 )
3537 (if (not cperl-xemacs-p) nil
3538 (or (boundp 'font-lock-comment-face)
3539 (defconst font-lock-comment-face
3540 'font-lock-comment-face
3541 "Face to use for comments.")
3542 )
3543 (or (boundp 'font-lock-keyword-face)
3544 (defconst font-lock-keyword-face
3545 'font-lock-keyword-face
3546 "Face to use for keywords.")
3547 )
3548 (or (boundp 'font-lock-function-name-face)
3549 (defconst font-lock-function-name-face
3550 'font-lock-function-name-face
3551 "Face to use for function names.")
3552 )
3553 )
3554 ;;(if (featurep 'font-lock)
3555 (if (face-equal font-lock-type-face font-lock-comment-face)
3556 (defconst font-lock-type-face
3557 'font-lock-type-face
3558 "Face to use for basic data types.")
3559 )
3560;;; (if (fboundp 'eval-after-load)
3561;;; (eval-after-load "font-lock"
3562;;; '(if (face-equal font-lock-type-face
3563;;; font-lock-comment-face)
3564;;; (defconst font-lock-type-face
3565;;; 'font-lock-type-face
3566;;; "Face to use for basic data types.")
3567;;; ))) ; This does not work :-( Why?!
3568;;; ; Workaround: added to font-lock-m-h
3569;;; )
3570 (or (boundp 'font-lock-other-emphasized-face)
3571 (defconst font-lock-other-emphasized-face
3572 'font-lock-other-emphasized-face
3573 "Face to use for another type of emphasizing.")
3574 )
3575 (or (boundp 'font-lock-emphasized-face)
3576 (defconst font-lock-emphasized-face
3577 'font-lock-emphasized-face
3578 "Face to use for emphasizing.")
3579 )
3580 ;; Here we try to guess background
3581 (let ((background
3582 (if (boundp 'font-lock-background-mode)
3583 font-lock-background-mode
3584 'light))
3585 (face-list (and (fboundp 'face-list) (face-list)))
3586 is-face)
3587 (fset 'is-face
3588 (cond ((fboundp 'find-face)
3589 (symbol-function 'find-face))
3590 (face-list
3591 (function (lambda (face) (member face face-list))))
3592 (t
3593 (function (lambda (face) (boundp face))))))
3594 (defvar cperl-guessed-background
3595 (if (and (boundp 'font-lock-display-type)
3596 (eq font-lock-display-type 'grayscale))
3597 'gray
3598 background)
3599 "Background as guessed by CPerl mode")
3600 (if (is-face 'font-lock-type-face) nil
3601 (copy-face 'default 'font-lock-type-face)
3602 (cond
3603 ((eq background 'light)
3604 (set-face-foreground 'font-lock-type-face
3605 (if (x-color-defined-p "seagreen")
3606 "seagreen"
3607 "sea green")))
3608 ((eq background 'dark)
3609 (set-face-foreground 'font-lock-type-face
3610 (if (x-color-defined-p "os2pink")
3611 "os2pink"
3612 "pink")))
3613 (t
3614 (set-face-background 'font-lock-type-face "gray90"))))
3615 (if (is-face 'font-lock-other-type-face)
3616 nil
3617 (copy-face 'font-lock-type-face 'font-lock-other-type-face)
3618 (cond
3619 ((eq background 'light)
3620 (set-face-foreground 'font-lock-other-type-face
3621 (if (x-color-defined-p "chartreuse3")
3622 "chartreuse3"
3623 "chartreuse")))
3624 ((eq background 'dark)
3625 (set-face-foreground 'font-lock-other-type-face
3626 (if (x-color-defined-p "orchid1")
3627 "orchid1"
3628 "orange")))))
3629 (if (is-face 'font-lock-other-emphasized-face) nil
3630 (copy-face 'bold-italic 'font-lock-other-emphasized-face)
3631 (cond
3632 ((eq background 'light)
3633 (set-face-background 'font-lock-other-emphasized-face
3634 (if (x-color-defined-p "lightyellow2")
3635 "lightyellow2"
3636 (if (x-color-defined-p "lightyellow")
3637 "lightyellow"
3638 "light yellow"))))
3639 ((eq background 'dark)
3640 (set-face-background 'font-lock-other-emphasized-face
3641 (if (x-color-defined-p "navy")
3642 "navy"
3643 (if (x-color-defined-p "darkgreen")
3644 "darkgreen"
3645 "dark green"))))
3646 (t (set-face-background 'font-lock-other-emphasized-face "gray90"))))
3647 (if (is-face 'font-lock-emphasized-face) nil
3648 (copy-face 'bold 'font-lock-emphasized-face)
3649 (cond
3650 ((eq background 'light)
3651 (set-face-background 'font-lock-emphasized-face
3652 (if (x-color-defined-p "lightyellow2")
3653 "lightyellow2"
3654 "lightyellow")))
3655 ((eq background 'dark)
3656 (set-face-background 'font-lock-emphasized-face
3657 (if (x-color-defined-p "navy")
3658 "navy"
3659 (if (x-color-defined-p "darkgreen")
3660 "darkgreen"
3661 "dark green"))))
3662 (t (set-face-background 'font-lock-emphasized-face "gray90"))))
3663 (if (is-face 'font-lock-variable-name-face) nil
3664 (copy-face 'italic 'font-lock-variable-name-face))
883212ce
SM
3665 (if (is-face 'font-lock-constant-face) nil
3666 (copy-face 'italic 'font-lock-constant-face))))
f83d2997
KH
3667 (setq cperl-faces-init t))
3668 (error nil)))
3669
3670
3671(defun cperl-ps-print-init ()
3672 "Initialization of `ps-print' components for faces used in CPerl."
3673 ;; Guard against old versions
3674 (defvar ps-underlined-faces nil)
3675 (defvar ps-bold-faces nil)
3676 (defvar ps-italic-faces nil)
3677 (setq ps-bold-faces
3678 (append '(font-lock-emphasized-face
3679 font-lock-keyword-face
3680 font-lock-variable-name-face
3681 font-lock-reference-face
3682 font-lock-other-emphasized-face)
3683 ps-bold-faces))
3684 (setq ps-italic-faces
3685 (append '(font-lock-other-type-face
3686 font-lock-reference-face
3687 font-lock-other-emphasized-face)
3688 ps-italic-faces))
3689 (setq ps-underlined-faces
3690 (append '(font-lock-emphasized-face
3691 font-lock-other-emphasized-face
3692 font-lock-other-type-face font-lock-type-face)
3693 ps-underlined-faces))
3694 (cons 'font-lock-type-face ps-underlined-faces))
3695
3696
3697(if (cperl-enable-font-lock) (cperl-windowed-init))
3698
3699(defun cperl-set-style (style)
3700 "Set CPerl-mode variables to use one of several different indentation styles.
3701The arguments are a string representing the desired style.
3702Available styles are GNU, K&R, BSD and Whitesmith."
3703 (interactive
3704 (let ((list (mapcar (function (lambda (elt) (list (car elt))))
3705 c-style-alist)))
3706 (list (completing-read "Enter style: " list nil 'insist))))
3707 (let ((style (cdr (assoc style c-style-alist))) setting str sym)
3708 (while style
3709 (setq setting (car style) style (cdr style))
3710 (setq str (symbol-name (car setting)))
3711 (and (string-match "^c-" str)
3712 (setq str (concat "cperl-" (substring str 2)))
3713 (setq sym (intern-soft str))
3714 (boundp sym)
3715 (set sym (cdr setting))))))
3716
3717(defun cperl-check-syntax ()
3718 (interactive)
3719 (require 'mode-compile)
3720 (let ((perl-dbg-flags "-wc"))
3721 (mode-compile)))
3722
3723(defun cperl-info-buffer (type)
3724 ;; Returns buffer with documentation. Creates if missing.
3725 ;; If TYPE, this vars buffer.
3726 ;; Special care is taken to not stomp over an existing info buffer
3727 (let* ((bname (if type "*info-perl-var*" "*info-perl*"))
3728 (info (get-buffer bname))
3729 (oldbuf (get-buffer "*info*")))
3730 (if info info
3731 (save-window-excursion
3732 ;; Get Info running
3733 (require 'info)
3734 (cond (oldbuf
3735 (set-buffer oldbuf)
3736 (rename-buffer "*info-perl-tmp*")))
3737 (save-window-excursion
3738 (info))
3739 (Info-find-node cperl-info-page (if type "perlvar" "perlfunc"))
3740 (set-buffer "*info*")
3741 (rename-buffer bname)
3742 (cond (oldbuf
3743 (set-buffer "*info-perl-tmp*")
3744 (rename-buffer "*info*")
3745 (set-buffer bname)))
3746 (make-variable-buffer-local 'window-min-height)
3747 (setq window-min-height 2)
3748 (current-buffer)))))
3749
3750(defun cperl-word-at-point (&optional p)
3751 ;; Returns the word at point or at P.
3752 (save-excursion
3753 (if p (goto-char p))
3754 (or (cperl-word-at-point-hard)
3755 (progn
3756 (require 'etags)
3757 (funcall (or (and (boundp 'find-tag-default-function)
3758 find-tag-default-function)
3759 (get major-mode 'find-tag-default-function)
3760 ;; XEmacs 19.12 has `find-tag-default-hook'; it is
3761 ;; automatically used within `find-tag-default':
3762 'find-tag-default))))))
3763
3764(defun cperl-info-on-command (command)
3765 "Shows documentation for Perl command in other window.
3766If perl-info buffer is shown in some frame, uses this frame.
3767Customized by setting variables `cperl-shrink-wrap-info-frame',
3768`cperl-max-help-size'."
3769 (interactive
3770 (let* ((default (cperl-word-at-point))
3771 (read (read-string
3772 (format "Find doc for Perl function (default %s): "
3773 default))))
3774 (list (if (equal read "")
3775 default
3776 read))))
3777
3778 (let ((buffer (current-buffer))
3779 (cmd-desc (concat "^" (regexp-quote command) "[^a-zA-Z_0-9]")) ; "tr///"
3780 pos isvar height iniheight frheight buf win fr1 fr2 iniwin not-loner
3781 max-height char-height buf-list)
3782 (if (string-match "^-[a-zA-Z]$" command)
3783 (setq cmd-desc "^-X[ \t\n]"))
3784 (setq isvar (string-match "^[$@%]" command)
3785 buf (cperl-info-buffer isvar)
3786 iniwin (selected-window)
3787 fr1 (window-frame iniwin))
3788 (set-buffer buf)
3789 (beginning-of-buffer)
3790 (or isvar
3791 (progn (re-search-forward "^-X[ \t\n]")
3792 (forward-line -1)))
3793 (if (re-search-forward cmd-desc nil t)
3794 (progn
3795 ;; Go back to beginning of the group (ex, for qq)
3796 (if (re-search-backward "^[ \t\n\f]")
3797 (forward-line 1))
3798 (beginning-of-line)
3799 ;; Get some of
3800 (setq pos (point)
3801 buf-list (list buf "*info-perl-var*" "*info-perl*"))
3802 (while (and (not win) buf-list)
3803 (setq win (get-buffer-window (car buf-list) t))
3804 (setq buf-list (cdr buf-list)))
3805 (or (not win)
3806 (eq (window-buffer win) buf)
3807 (set-window-buffer win buf))
3808 (and win (setq fr2 (window-frame win)))
3809 (if (or (not fr2) (eq fr1 fr2))
3810 (pop-to-buffer buf)
3811 (special-display-popup-frame buf) ; Make it visible
3812 (select-window win))
3813 (goto-char pos) ; Needed (?!).
3814 ;; Resize
3815 (setq iniheight (window-height)
3816 frheight (frame-height)
3817 not-loner (< iniheight (1- frheight))) ; Are not alone
3818 (cond ((if not-loner cperl-max-help-size
3819 cperl-shrink-wrap-info-frame)
3820 (setq height
3821 (+ 2
3822 (count-lines
3823 pos
3824 (save-excursion
3825 (if (re-search-forward
3826 "^[ \t][^\n]*\n+\\([^ \t\n\f]\\|\\'\\)" nil t)
3827 (match-beginning 0) (point-max)))))
3828 max-height
3829 (if not-loner
3830 (/ (* (- frheight 3) cperl-max-help-size) 100)
3831 (setq char-height (frame-char-height))
3832 ;; Non-functioning under OS/2:
3833 (if (eq char-height 1) (setq char-height 18))
3834 ;; Title, menubar, + 2 for slack
3835 (- (/ (x-display-pixel-height) char-height) 4)
3836 ))
3837 (if (> height max-height) (setq height max-height))
3838 ;;(message "was %s doing %s" iniheight height)
3839 (if not-loner
3840 (enlarge-window (- height iniheight))
3841 (set-frame-height (window-frame win) (1+ height)))))
3842 (set-window-start (selected-window) pos))
3843 (message "No entry for %s found." command))
3844 ;;(pop-to-buffer buffer)
3845 (select-window iniwin)))
3846
3847(defun cperl-info-on-current-command ()
3848 "Shows documentation for Perl command at point in other window."
3849 (interactive)
3850 (cperl-info-on-command (cperl-word-at-point)))
3851
3852(defun cperl-imenu-info-imenu-search ()
3853 (if (looking-at "^-X[ \t\n]") nil
3854 (re-search-backward
3855 "^\n\\([-a-zA-Z_]+\\)[ \t\n]")
3856 (forward-line 1)))
3857
3858(defun cperl-imenu-info-imenu-name ()
3859 (buffer-substring
3860 (match-beginning 1) (match-end 1)))
3861
3862(defun cperl-imenu-on-info ()
3863 (interactive)
3864 (let* ((buffer (current-buffer))
3865 imenu-create-index-function
3866 imenu-prev-index-position-function
3867 imenu-extract-index-name-function
3868 (index-item (save-restriction
3869 (save-window-excursion
3870 (set-buffer (cperl-info-buffer nil))
3871 (setq imenu-create-index-function
3872 'imenu-default-create-index-function
3873 imenu-prev-index-position-function
3874 'cperl-imenu-info-imenu-search
3875 imenu-extract-index-name-function
3876 'cperl-imenu-info-imenu-name)
3877 (imenu-choose-buffer-index)))))
3878 (and index-item
3879 (progn
3880 (push-mark)
3881 (pop-to-buffer "*info-perl*")
3882 (cond
3883 ((markerp (cdr index-item))
3884 (goto-char (marker-position (cdr index-item))))
3885 (t
3886 (goto-char (cdr index-item))))
3887 (set-window-start (selected-window) (point))
3888 (pop-to-buffer buffer)))))
3889
3890(defun cperl-lineup (beg end &optional step minshift)
3891 "Lineup construction in a region.
3892Beginning of region should be at the start of a construction.
3893All first occurrences of this construction in the lines that are
3894partially contained in the region are lined up at the same column.
3895
3896MINSHIFT is the minimal amount of space to insert before the construction.
3897STEP is the tabwidth to position constructions.
3898If STEP is `nil', `cperl-lineup-step' will be used
3899\(or `cperl-indent-level', if `cperl-lineup-step' is `nil').
3900Will not move the position at the start to the left."
3901 (interactive "r")
3902 (let (search col tcol seen b e)
3903 (save-excursion
3904 (goto-char end)
3905 (end-of-line)
3906 (setq end (point-marker))
3907 (goto-char beg)
3908 (skip-chars-forward " \t\f")
3909 (setq beg (point-marker))
3910 (indent-region beg end nil)
3911 (goto-char beg)
3912 (setq col (current-column))
3913 (if (looking-at "[a-zA-Z0-9_]")
3914 (if (looking-at "\\<[a-zA-Z0-9_]+\\>")
3915 (setq search
3916 (concat "\\<"
3917 (regexp-quote
3918 (buffer-substring (match-beginning 0)
3919 (match-end 0))) "\\>"))
3920 (error "Cannot line up in a middle of the word"))
3921 (if (looking-at "$")
3922 (error "Cannot line up end of line"))
3923 (setq search (regexp-quote (char-to-string (following-char)))))
3924 (setq step (or step cperl-lineup-step cperl-indent-level))
3925 (or minshift (setq minshift 1))
3926 (while (progn
3927 (beginning-of-line 2)
3928 (and (< (point) end)
3929 (re-search-forward search end t)
3930 (goto-char (match-beginning 0))))
3931 (setq tcol (current-column) seen t)
3932 (if (> tcol col) (setq col tcol)))
3933 (or seen
3934 (error "The construction to line up occurred only once"))
3935 (goto-char beg)
3936 (setq col (+ col minshift))
3937 (if (/= (% col step) 0) (setq step (* step (1+ (/ col step)))))
3938 (while
3939 (progn
3940 (setq e (point))
3941 (skip-chars-backward " \t")
3942 (delete-region (point) e)
3943 (indent-to-column col); (make-string (- col (current-column)) ?\ ))
3944 (beginning-of-line 2)
3945 (and (< (point) end)
3946 (re-search-forward search end t)
3947 (goto-char (match-beginning 0)))))))) ; No body
3948
3949(defun cperl-etags (&optional add all files)
3950 "Run etags with appropriate options for Perl files.
3951If optional argument ALL is `recursive', will process Perl files
3952in subdirectories too."
3953 (interactive)
3954 (let ((cmd "etags")
3955 (args '("-l" "none" "-r" "/\\<\\(package\\|sub\\)[ \\t]+\\(\\([a-zA-Z0-9:_]*::\\)?\\([a-zA-Z0-9_]+\\)[ \\t]*\\(([^()]*)[ \t]*\\)?\\([{#]\\|$\\)\\)/\\4/"))
3956 res)
3957 (if add (setq args (cons "-a" args)))
3958 (or files (setq files (list buffer-file-name)))
3959 (cond
3960 ((eq all 'recursive)
3961 ;;(error "Not implemented: recursive")
3962 (setq args (append (list "-e"
3963 "sub wanted {push @ARGV, $File::Find::name if /\\.[pP][Llm]$/}
3964 use File::Find;
3965 find(\\&wanted, '.');
3966 exec @ARGV;"
3967 cmd) args)
3968 cmd "perl"))
3969 (all
3970 ;;(error "Not implemented: all")
3971 (setq args (append (list "-e"
3972 "push @ARGV, <*.PL *.pl *.pm>;
3973 exec @ARGV;"
3974 cmd) args)
3975 cmd "perl"))
3976 (t
3977 (setq args (append args files))))
3978 (setq res (apply 'call-process cmd nil nil nil args))
3979 (or (eq res 0)
3980 (message "etags returned \"%s\"" res))))
3981
3982(defun cperl-toggle-auto-newline ()
3983 "Toggle the state of `cperl-auto-newline'."
3984 (interactive)
3985 (setq cperl-auto-newline (not cperl-auto-newline))
3986 (message "Newlines will %sbe auto-inserted now."
3987 (if cperl-auto-newline "" "not ")))
3988
3989(defun cperl-toggle-abbrev ()
3990 "Toggle the state of automatic keyword expansion in CPerl mode."
3991 (interactive)
3992 (abbrev-mode (if abbrev-mode 0 1))
3993 (message "Perl control structure will %sbe auto-inserted now."
3994 (if abbrev-mode "" "not ")))
3995
3996
3997(defun cperl-toggle-electric ()
3998 "Toggle the state of parentheses doubling in CPerl mode."
3999 (interactive)
4000 (setq cperl-electric-parens (if (cperl-val 'cperl-electric-parens) 'null t))
4001 (message "Parentheses will %sbe auto-doubled now."
4002 (if (cperl-val 'cperl-electric-parens) "" "not ")))
4003
4004;;;; Tags file creation.
4005
4006(defvar cperl-tmp-buffer " *cperl-tmp*")
4007
4008(defun cperl-setup-tmp-buf ()
4009 (set-buffer (get-buffer-create cperl-tmp-buffer))
4010 (set-syntax-table cperl-mode-syntax-table)
4011 (buffer-disable-undo)
4012 (auto-fill-mode 0)
4013 (if cperl-use-syntax-table-text-property-for-tags
4014 (progn
4015 (make-variable-buffer-local 'parse-sexp-lookup-properties)
4016 ;; Do not introduce variable if not needed, we check it!
4017 (set 'parse-sexp-lookup-properties t))))
4018
4019(defun cperl-xsub-scan ()
4020 (require 'cl)
4021 (require 'imenu)
4022 (let ((index-alist '())
4023 (prev-pos 0) index index1 name package prefix)
4024 (goto-char (point-min))
4025 (if noninteractive
4026 (message "Scanning XSUB for index")
4027 (imenu-progress-message prev-pos 0))
4028 ;; Search for the function
4029 (progn ;;save-match-data
4030 (while (re-search-forward
4031 "^\\([ \t]*MODULE\\>[^\n]*\\<PACKAGE[ \t]*=[ \t]*\\([a-zA-Z_][a-zA-Z_0-9:]*\\)\\>\\|\\([a-zA-Z_][a-zA-Z_0-9]*\\)(\\|[ \t]*BOOT:\\)"
4032 nil t)
4033 (or noninteractive
4034 (imenu-progress-message prev-pos))
4035 (cond
4036 ((match-beginning 2) ; SECTION
4037 (setq package (buffer-substring (match-beginning 2) (match-end 2)))
4038 (goto-char (match-beginning 0))
4039 (skip-chars-forward " \t")
4040 (forward-char 1)
4041 (if (looking-at "[^\n]*\\<PREFIX[ \t]*=[ \t]*\\([a-zA-Z_][a-zA-Z_0-9]*\\)\\>")
4042 (setq prefix (buffer-substring (match-beginning 1) (match-end 1)))
4043 (setq prefix nil)))
4044 ((not package) nil) ; C language section
4045 ((match-beginning 3) ; XSUB
4046 (goto-char (1+ (match-beginning 3)))
4047 (setq index (imenu-example--name-and-position))
4048 (setq name (buffer-substring (match-beginning 3) (match-end 3)))
4049 (if (and prefix (string-match (concat "^" prefix) name))
4050 (setq name (substring name (length prefix))))
4051 (cond ((string-match "::" name) nil)
4052 (t
4053 (setq index1 (cons (concat package "::" name) (cdr index)))
4054 (push index1 index-alist)))
4055 (setcar index name)
4056 (push index index-alist))
4057 (t ; BOOT: section
4058 ;; (beginning-of-line)
4059 (setq index (imenu-example--name-and-position))
4060 (setcar index (concat package "::BOOT:"))
4061 (push index index-alist)))))
4062 (or noninteractive
4063 (imenu-progress-message prev-pos 100))
4064 ;;(setq index-alist
4065 ;; (if (default-value 'imenu-sort-function)
4066 ;; (sort index-alist (default-value 'imenu-sort-function))
4067 ;; (nreverse index-alist)))
4068 index-alist))
4069
4070(defun cperl-find-tags (file xs topdir)
4071 (let (ind (b (get-buffer cperl-tmp-buffer)) lst elt pos ret rel
4072 (cperl-pod-here-fontify nil))
4073 (save-excursion
4074 (if b (set-buffer b)
4075 (cperl-setup-tmp-buf))
4076 (erase-buffer)
4077 (setq file (car (insert-file-contents file)))
4078 (message "Scanning file %s ..." file)
4079 (if (and cperl-use-syntax-table-text-property-for-tags
4080 (not xs))
4081 (condition-case err ; after __END__ may have garbage
4082 (cperl-find-pods-heres)
4083 (error (message "While scanning for syntax: %s" err))))
4084 (if xs
4085 (setq lst (cperl-xsub-scan))
4086 (setq ind (imenu-example--create-perl-index))
4087 (setq lst (cdr (assoc "+Unsorted List+..." ind))))
4088 (setq lst
4089 (mapcar
4090 (function
4091 (lambda (elt)
4092 (cond ((string-match "^[_a-zA-Z]" (car elt))
4093 (goto-char (cdr elt))
4094 (list (car elt)
4095 (point) (count-lines 1 (point))
4096 (buffer-substring (progn
4097 (skip-chars-forward
4098 ":_a-zA-Z0-9")
4099 (or (eolp) (forward-char 1))
4100 (point))
4101 (progn
4102 (beginning-of-line)
4103 (point))))))))
4104 lst))
4105 (erase-buffer)
4106 (while lst
4107 (setq elt (car lst) lst (cdr lst))
4108 (if elt
4109 (progn
4110 (insert (elt elt 3)
4111 127
4112 (if (string-match "^package " (car elt))
4113 (substring (car elt) 8)
4114 (car elt) )
4115 1
4116 (number-to-string (elt elt 1))
4117 ","
4118 (number-to-string (elt elt 2))
4119 "\n")
4120 (if (and (string-match "^[_a-zA-Z]+::" (car elt))
4121 (string-match "^sub[ \t]+\\([_a-zA-Z]+\\)[^:_a-zA-Z]"
4122 (elt elt 3)))
4123 ;; Need to insert the name without package as well
4124 (setq lst (cons (cons (substring (elt elt 3)
4125 (match-beginning 1)
4126 (match-end 1))
4127 (cdr elt))
4128 lst))))))
4129 (setq pos (point))
4130 (goto-char 1)
4131 (setq rel file)
4132 ;; On case-preserving filesystems (EMX on OS/2) case might be encoded in properties
4133 (set-text-properties 0 (length rel) nil rel)
4134 (and (equal topdir (substring rel 0 (length topdir)))
4135 (setq rel (substring file (length topdir))))
4136 (insert "\f\n" rel "," (number-to-string (1- pos)) "\n")
4137 (setq ret (buffer-substring 1 (point-max)))
4138 (erase-buffer)
4139 (or noninteractive
4140 (message "Scanning file %s finished" file))
4141 ret)))
4142
4143(defun cperl-add-tags-recurse-noxs ()
4144 "Add to TAGS data for Perl and XSUB files in the current directory and kids.
4145Use as
4146 emacs -batch -q -no-site-file -l emacs/cperl-mode.el \
4147 -f cperl-add-tags-recurse
4148"
4149 (cperl-write-tags nil nil t t nil t))
4150
4151(defun cperl-add-tags-recurse ()
4152 "Add to TAGS file data for Perl files in the current directory and kids.
4153Use as
4154 emacs -batch -q -no-site-file -l emacs/cperl-mode.el \
4155 -f cperl-add-tags-recurse
4156"
4157 (cperl-write-tags nil nil t t))
4158
4159(defun cperl-write-tags (&optional file erase recurse dir inbuffer noxs topdir)
4160 ;; If INBUFFER, do not select buffer, and do not save
4161 ;; If ERASE is `ignore', do not erase, and do not try to delete old info.
4162 (require 'etags)
4163 (if file nil
4164 (setq file (if dir default-directory (buffer-file-name)))
4165 (if (and (not dir) (buffer-modified-p)) (error "Save buffer first!")))
4166 (or topdir
4167 (setq topdir default-directory))
4168 (let ((tags-file-name "TAGS")
4169 (case-fold-search (eq system-type 'emx))
4170 xs)
4171 (save-excursion
4172 (cond (inbuffer nil) ; Already there
4173 ((file-exists-p tags-file-name)
4174 (visit-tags-table-buffer tags-file-name))
4175 (t (set-buffer (find-file-noselect tags-file-name))))
4176 (cond
4177 (dir
4178 (cond ((eq erase 'ignore))
4179 (erase
4180 (erase-buffer)
4181 (setq erase 'ignore)))
4182 (let ((files
4183 (directory-files file t
4184 (if recurse nil cperl-scan-files-regexp)
4185 t)))
4186 (mapcar (function (lambda (file)
4187 (cond
4188 ((string-match cperl-noscan-files-regexp file)
4189 nil)
4190 ((not (file-directory-p file))
4191 (if (string-match cperl-scan-files-regexp file)
4192 (cperl-write-tags file erase recurse nil t noxs topdir)))
4193 ((not recurse) nil)
4194 (t (cperl-write-tags file erase recurse t t noxs topdir)))))
4195 files))
4196 )
4197 (t
4198 (setq xs (string-match "\\.xs$" file))
4199 (if (not (and xs noxs))
4200 (progn
4201 (cond ((eq erase 'ignore) (goto-char (point-max)))
4202 (erase (erase-buffer))
4203 (t
4204 (goto-char 1)
4205 (if (search-forward (concat "\f\n" file ",") nil t)
4206 (progn
4207 (search-backward "\f\n")
4208 (delete-region (point)
4209 (save-excursion
4210 (forward-char 1)
4211 (if (search-forward "\f\n"
4212 nil 'toend)
4213 (- (point) 2)
4214 (point-max)))))
4215 (goto-char (point-max)))))
4216 (insert (cperl-find-tags file xs topdir))))))
4217 (if inbuffer nil ; Delegate to the caller
4218 (save-buffer 0) ; No backup
4219 (if (fboundp 'initialize-new-tags-table) ; Do we need something special in XEmacs?
4220 (initialize-new-tags-table))))))
4221
4222(defvar cperl-tags-hier-regexp-list
4223 (concat
4224 "^\\("
4225 "\\(package\\)\\>"
4226 "\\|"
4227 "sub\\>[^\n]+::"
4228 "\\|"
4229 "[a-zA-Z_][a-zA-Z_0-9:]*(\C-?[^\n]+::" ; XSUB?
4230 "\\|"
4231 "[ \t]*BOOT:\C-?[^\n]+::" ; BOOT section
4232 "\\)"))
4233
4234(defvar cperl-hierarchy '(() ())
4235 "Global hierarchy of classes")
4236
4237(defun cperl-tags-hier-fill ()
4238 ;; Suppose we are in a tag table cooked by cperl.
4239 (goto-char 1)
4240 (let (type pack name pos line chunk ord cons1 file str info fileind)
4241 (while (re-search-forward cperl-tags-hier-regexp-list nil t)
4242 (setq pos (match-beginning 0)
4243 pack (match-beginning 2))
4244 (beginning-of-line)
4245 (if (looking-at (concat
4246 "\\([^\n]+\\)"
4247 "\C-?"
4248 "\\([^\n]+\\)"
4249 "\C-a"
4250 "\\([0-9]+\\)"
4251 ","
4252 "\\([0-9]+\\)"))
4253 (progn
4254 (setq ;;str (buffer-substring (match-beginning 1) (match-end 1))
4255 name (buffer-substring (match-beginning 2) (match-end 2))
4256 ;;pos (buffer-substring (match-beginning 3) (match-end 3))
4257 line (buffer-substring (match-beginning 4) (match-end 4))
4258 ord (if pack 1 0)
4259 info (etags-snarf-tag) ; Moves to beginning of the next line
4260 file (file-of-tag)
4261 fileind (format "%s:%s" file line))
4262 ;; Move back
4263 (forward-char -1)
4264 ;; Make new member of hierarchy name ==> file ==> pos if needed
4265 (if (setq cons1 (assoc name (nth ord cperl-hierarchy)))
4266 ;; Name known
4267 (setcdr cons1 (cons (cons fileind (vector file info))
4268 (cdr cons1)))
4269 ;; First occurrence of the name, start alist
4270 (setq cons1 (cons name (list (cons fileind (vector file info)))))
4271 (if pack
4272 (setcar (cdr cperl-hierarchy)
4273 (cons cons1 (nth 1 cperl-hierarchy)))
4274 (setcar cperl-hierarchy
4275 (cons cons1 (car cperl-hierarchy)))))))
4276 (end-of-line))))
4277
4278(defun cperl-tags-hier-init (&optional update)
4279 "Show hierarchical menu of classes and methods.
4280Finds info about classes by a scan of loaded TAGS files.
4281Supposes that the TAGS files contain fully qualified function names.
4282One may build such TAGS files from CPerl mode menu."
4283 (interactive)
4284 (require 'etags)
4285 (require 'imenu)
4286 (if (or update (null (nth 2 cperl-hierarchy)))
4287 (let (pack name cons1 to l1 l2 l3 l4
4288 (remover (function (lambda (elt) ; (name (file1...) (file2..))
4289 (or (nthcdr 2 elt)
4290 ;; Only in one file
4291 (setcdr elt (cdr (nth 1 elt))))))))
4292 ;; (setq cperl-hierarchy '(() () ())) ; Would write into '() later!
4293 (setq cperl-hierarchy (list l1 l2 l3))
4294 (or tags-table-list
4295 (call-interactively 'visit-tags-table))
4296 (message "Updating list of classes...")
4297 (mapcar
4298 (function
4299 (lambda (tagsfile)
4300 (set-buffer (get-file-buffer tagsfile))
4301 (cperl-tags-hier-fill)))
4302 tags-table-list)
4303 (mapcar remover (car cperl-hierarchy))
4304 (mapcar remover (nth 1 cperl-hierarchy))
4305 (setq to (list nil (cons "Packages: " (nth 1 cperl-hierarchy))
4306 (cons "Methods: " (car cperl-hierarchy))))
4307 (cperl-tags-treeify to 1)
4308 (setcar (nthcdr 2 cperl-hierarchy)
4309 (cperl-menu-to-keymap (cons '("+++UPDATE+++" . -999) (cdr to))))
4310 (message "Updating list of classes: done, requesting display...")
4311 ;;(cperl-imenu-addback (nth 2 cperl-hierarchy))
4312 ))
4313 (or (nth 2 cperl-hierarchy)
4314 (error "No items found"))
4315 (setq update
4316;;; (imenu-choose-buffer-index "Packages: " (nth 2 cperl-hierarchy))
4317 (if window-system
4318 (x-popup-menu t (nth 2 cperl-hierarchy))
4319 (require 'tmm)
4320 (tmm-prompt (nth 2 cperl-hierarchy))))
4321 (if (and update (listp update))
4322 (progn (while (cdr update) (setq update (cdr update)))
4323 (setq update (car update)))) ; Get the last from the list
4324 (if (vectorp update)
4325 (progn
4326 (find-file (elt update 0))
4327 (etags-goto-tag-location (elt update 1))))
4328 (if (eq update -999) (cperl-tags-hier-init t)))
4329
4330(defun cperl-tags-treeify (to level)
4331 ;; cadr of `to' is read-write. On start it is a cons
4332 (let* ((regexp (concat "^\\(" (mapconcat
4333 'identity
4334 (make-list level "[_a-zA-Z0-9]+")
4335 "::")
4336 "\\)\\(::\\)?"))
4337 (packages (cdr (nth 1 to)))
4338 (methods (cdr (nth 2 to)))
4339 l1 head tail cons1 cons2 ord writeto packs recurse
4340 root-packages root-functions ms many_ms same_name ps
4341 (move-deeper
4342 (function
4343 (lambda (elt)
4344 (cond ((and (string-match regexp (car elt))
4345 (or (eq ord 1) (match-end 2)))
4346 (setq head (substring (car elt) 0 (match-end 1))
4347 tail (if (match-end 2) (substring (car elt)
4348 (match-end 2)))
4349 recurse t)
4350 (if (setq cons1 (assoc head writeto)) nil
4351 ;; Need to init new head
4352 (setcdr writeto (cons (list head (list "Packages: ")
4353 (list "Methods: "))
4354 (cdr writeto)))
4355 (setq cons1 (nth 1 writeto)))
4356 (setq cons2 (nth ord cons1)) ; Either packs or meths
4357 (setcdr cons2 (cons elt (cdr cons2))))
4358 ((eq ord 2)
4359 (setq root-functions (cons elt root-functions)))
4360 (t
4361 (setq root-packages (cons elt root-packages))))))))
4362 (setcdr to l1) ; Init to dynamic space
4363 (setq writeto to)
4364 (setq ord 1)
4365 (mapcar move-deeper packages)
4366 (setq ord 2)
4367 (mapcar move-deeper methods)
4368 (if recurse
4369 (mapcar (function (lambda (elt)
4370 (cperl-tags-treeify elt (1+ level))))
4371 (cdr to)))
4372 ;;Now clean up leaders with one child only
4373 (mapcar (function (lambda (elt)
4374 (if (not (and (listp (cdr elt))
4375 (eq (length elt) 2))) nil
4376 (setcar elt (car (nth 1 elt)))
4377 (setcdr elt (cdr (nth 1 elt))))))
4378 (cdr to))
4379 ;; Sort the roots of subtrees
4380 (if (default-value 'imenu-sort-function)
4381 (setcdr to
4382 (sort (cdr to) (default-value 'imenu-sort-function))))
4383 ;; Now add back functions removed from display
4384 (mapcar (function (lambda (elt)
4385 (setcdr to (cons elt (cdr to)))))
4386 (if (default-value 'imenu-sort-function)
4387 (nreverse
4388 (sort root-functions (default-value 'imenu-sort-function)))
4389 root-functions))
4390 ;; Now add back packages removed from display
4391 (mapcar (function (lambda (elt)
4392 (setcdr to (cons (cons (concat "package " (car elt))
4393 (cdr elt))
4394 (cdr to)))))
4395 (if (default-value 'imenu-sort-function)
4396 (nreverse
4397 (sort root-packages (default-value 'imenu-sort-function)))
4398 root-packages))
4399 ))
4400
4401;;;(x-popup-menu t
4402;;; '(keymap "Name1"
4403;;; ("Ret1" "aa")
4404;;; ("Head1" "ab"
4405;;; keymap "Name2"
4406;;; ("Tail1" "x") ("Tail2" "y"))))
4407
4408(defun cperl-list-fold (list name limit)
4409 (let (list1 list2 elt1 (num 0))
4410 (if (<= (length list) limit) list
4411 (setq list1 nil list2 nil)
4412 (while list
4413 (setq num (1+ num)
4414 elt1 (car list)
4415 list (cdr list))
4416 (if (<= num imenu-max-items)
4417 (setq list2 (cons elt1 list2))
4418 (setq list1 (cons (cons name
4419 (nreverse list2))
4420 list1)
4421 list2 (list elt1)
4422 num 1)))
4423 (nreverse (cons (cons name
4424 (nreverse list2))
4425 list1)))))
4426
4427(defun cperl-menu-to-keymap (menu &optional name)
4428 (let (list)
4429 (cons 'keymap
4430 (mapcar
4431 (function
4432 (lambda (elt)
4433 (cond ((listp (cdr elt))
4434 (setq list (cperl-list-fold
4435 (cdr elt) (car elt) imenu-max-items))
4436 (cons nil
4437 (cons (car elt)
4438 (cperl-menu-to-keymap list))))
4439 (t
4440 (list (cdr elt) (car elt) t))))) ; t is needed in 19.34
4441 (cperl-list-fold menu "Root" imenu-max-items)))))
4442
4443\f
4444(defvar cperl-bad-style-regexp
4445 (mapconcat 'identity
4446 '("[^-\n\t <>=+!.&|(*/'`\"#^][-=+<>!|&^]" ; char sign
4447 "[-<>=+^&|]+[^- \t\n=+<>~]" ; sign+ char
4448 )
4449 "\\|")
4450 "Finds places such that insertion of a whitespace may help a lot.")
4451
4452(defvar cperl-not-bad-style-regexp
4453 (mapconcat 'identity
4454 '("[^-\t <>=+]\\(--\\|\\+\\+\\)" ; var-- var++
4455 "[a-zA-Z0-9_][|&][a-zA-Z0-9_$]" ; abc|def abc&def are often used.
4456 "&[(a-zA-Z0-9_$]" ; &subroutine &(var->field)
4457 "<\\$?\\sw+\\(\\.\\sw+\\)?>" ; <IN> <stdin.h>
4458 "-[a-zA-Z][ \t]+[_$\"'`]" ; -f file
4459 "-[0-9]" ; -5
4460 "\\+\\+" ; ++var
4461 "--" ; --var
4462 ".->" ; a->b
4463 "->" ; a SPACE ->b
4464 "\\[-" ; a[-1]
4465 "^=" ; =head
4466 "||"
4467 "&&"
4468 "[CBIXSLFZ]<\\(\\sw\\|\\s \\|\\s_\\|[\n]\\)*>" ; C<code like text>
4469 "-[a-zA-Z_0-9]+[ \t]*=>" ; -option => value
4470 ;; Unaddressed trouble spots: = -abc, f(56, -abc) --- specialcased below
4471 ;;"[*/+-|&<.]+="
4472 )
4473 "\\|")
4474 "If matches at the start of match found by `my-bad-c-style-regexp',
4475insertion of a whitespace will not help.")
4476
4477(defvar found-bad)
4478
4479(defun cperl-find-bad-style ()
4480 "Find places in the buffer where insertion of a whitespace may help.
4481Prompts user for insertion of spaces.
4482Currently it is tuned to C and Perl syntax."
4483 (interactive)
4484 (let (found-bad (p (point)))
4485 (setq last-nonmenu-event 13) ; To disable popup
4486 (beginning-of-buffer)
4487 (map-y-or-n-p "Insert space here? "
4488 (function (lambda (arg) (insert " ")))
4489 'cperl-next-bad-style
4490 '("location" "locations" "insert a space into")
4491 '((?\C-r (lambda (arg)
4492 (let ((buffer-quit-function
4493 'exit-recursive-edit))
4494 (message "Exit with Esc Esc")
4495 (recursive-edit)
4496 t)) ; Consider acted upon
4497 "edit, exit with Esc Esc")
4498 (?e (lambda (arg)
4499 (let ((buffer-quit-function
4500 'exit-recursive-edit))
4501 (message "Exit with Esc Esc")
4502 (recursive-edit)
4503 t)) ; Consider acted upon
4504 "edit, exit with Esc Esc"))
4505 t)
4506 (if found-bad (goto-char found-bad)
4507 (goto-char p)
4508 (message "No appropriate place found"))))
4509
4510(defun cperl-next-bad-style ()
4511 (let (p (not-found t) (point (point)) found)
4512 (while (and not-found
4513 (re-search-forward cperl-bad-style-regexp nil 'to-end))
4514 (setq p (point))
4515 (goto-char (match-beginning 0))
4516 (if (or
4517 (looking-at cperl-not-bad-style-regexp)
4518 ;; Check for a < -b and friends
4519 (and (eq (following-char) ?\-)
4520 (save-excursion
4521 (skip-chars-backward " \t\n")
4522 (memq (preceding-char) '(?\= ?\> ?\< ?\, ?\(, ?\[, ?\{))))
4523 ;; Now check for syntax type
4524 (save-match-data
4525 (setq found (point))
4526 (beginning-of-defun)
4527 (let ((pps (parse-partial-sexp (point) found)))
4528 (or (nth 3 pps) (nth 4 pps) (nth 5 pps)))))
4529 (goto-char (match-end 0))
4530 (goto-char (1- p))
4531 (setq not-found nil
4532 found-bad found)))
4533 (not not-found)))
4534
f83d2997
KH
4535;;; Getting help
4536(defvar cperl-have-help-regexp
4537 ;;(concat "\\("
4538 (mapconcat
4539 'identity
4540 '("[$@%*&][0-9a-zA-Z_:]+\\([ \t]*[[{]\\)?" ; Usual variable
4541 "[$@]\\^[a-zA-Z]" ; Special variable
4542 "[$@][^ \n\t]" ; Special variable
4543 "-[a-zA-Z]" ; File test
4544 "\\\\[a-zA-Z0]" ; Special chars
4545 "^=[a-z][a-zA-Z0-9_]*" ; Pod sections
4546 "[-!&*+,-./<=>?\\\\^|~]+" ; Operator
4547 "[a-zA-Z_0-9:]+" ; symbol or number
4548 "x="
4549 "#!"
4550 )
4551 ;;"\\)\\|\\("
4552 "\\|"
4553 )
4554 ;;"\\)"
4555 ;;)
4556 "Matches places in the buffer we can find help for.")
4557
4558(defvar cperl-message-on-help-error t)
4559(defvar cperl-help-from-timer nil)
4560
4561(defun cperl-word-at-point-hard ()
4562 ;; Does not save-excursion
4563 ;; Get to the something meaningful
4564 (or (eobp) (eolp) (forward-char 1))
4565 (re-search-backward "[-a-zA-Z0-9_:!&*+,-./<=>?\\\\^|~$%@]"
4566 (save-excursion (beginning-of-line) (point))
4567 'to-beg)
4568 ;; (cond
4569 ;; ((or (eobp) (looking-at "[][ \t\n{}();,]")) ; Not at a symbol
4570 ;; (skip-chars-backward " \n\t\r({[]});,")
4571 ;; (or (bobp) (backward-char 1))))
4572 ;; Try to backtrace
4573 (cond
4574 ((looking-at "[a-zA-Z0-9_:]") ; symbol
4575 (skip-chars-backward "a-zA-Z0-9_:")
4576 (cond
4577 ((and (eq (preceding-char) ?^) ; $^I
4578 (eq (char-after (- (point) 2)) ?\$))
4579 (forward-char -2))
4580 ((memq (preceding-char) (append "*$@%&\\" nil)) ; *glob
4581 (forward-char -1))
4582 ((and (eq (preceding-char) ?\=)
4583 (eq (current-column) 1))
4584 (forward-char -1))) ; =head1
4585 (if (and (eq (preceding-char) ?\<)
4586 (looking-at "\\$?[a-zA-Z0-9_:]+>")) ; <FH>
4587 (forward-char -1)))
4588 ((and (looking-at "=") (eq (preceding-char) ?x)) ; x=
4589 (forward-char -1))
4590 ((and (looking-at "\\^") (eq (preceding-char) ?\$)) ; $^I
4591 (forward-char -1))
4592 ((looking-at "[-!&*+,-./<=>?\\\\^|~]")
4593 (skip-chars-backward "-!&*+,-./<=>?\\\\^|~")
4594 (cond
4595 ((and (eq (preceding-char) ?\$)
4596 (not (eq (char-after (- (point) 2)) ?\$))) ; $-
4597 (forward-char -1))
4598 ((and (eq (following-char) ?\>)
4599 (string-match "[a-zA-Z0-9_]" (char-to-string (preceding-char)))
4600 (save-excursion
4601 (forward-sexp -1)
4602 (and (eq (preceding-char) ?\<)
4603 (looking-at "\\$?[a-zA-Z0-9_:]+>")))) ; <FH>
4604 (search-backward "<"))))
4605 ((and (eq (following-char) ?\$)
4606 (eq (preceding-char) ?\<)
4607 (looking-at "\\$?[a-zA-Z0-9_:]+>")) ; <$fh>
4608 (forward-char -1)))
4609 (if (looking-at cperl-have-help-regexp)
4610 (buffer-substring (match-beginning 0) (match-end 0))))
4611
4612(defun cperl-get-help ()
4613 "Get one-line docs on the symbol at the point.
4614The data for these docs is a little bit obsolete and may be in fact longer
4615than a line. Your contribution to update/shorten it is appreciated."
4616 (interactive)
4617 (save-match-data ; May be called "inside" query-replace
4618 (save-excursion
4619 (let ((word (cperl-word-at-point-hard)))
4620 (if word
4621 (if (and cperl-help-from-timer ; Bail out if not in mainland
4622 (not (string-match "^#!\\|\\\\\\|^=" word)) ; Show help even in comments/strings.
4623 (or (memq (get-text-property (point) 'face)
4624 '(font-lock-comment-face font-lock-string-face))
4625 (memq (get-text-property (point) 'syntax-type)
4626 '(pod here-doc format))))
4627 nil
4628 (cperl-describe-perl-symbol word))
4629 (if cperl-message-on-help-error
4630 (message "Nothing found for %s..."
4631 (buffer-substring (point) (min (+ 5 (point)) (point-max))))))))))
4632
4633;;; Stolen from perl-descr.el by Johan Vromans:
4634
4635(defvar cperl-doc-buffer " *perl-doc*"
4636 "Where the documentation can be found.")
4637
4638(defun cperl-describe-perl-symbol (val)
4639 "Display the documentation of symbol at point, a Perl operator."
4640 (let ((enable-recursive-minibuffers t)
4641 args-file regexp)
4642 (cond
4643 ((string-match "^[&*][a-zA-Z_]" val)
4644 (setq val (concat (substring val 0 1) "NAME")))
4645 ((string-match "^[$@]\\([a-zA-Z_:0-9]+\\)[ \t]*\\[" val)
4646 (setq val (concat "@" (substring val 1 (match-end 1)))))
4647 ((string-match "^[$@]\\([a-zA-Z_:0-9]+\\)[ \t]*{" val)
4648 (setq val (concat "%" (substring val 1 (match-end 1)))))
4649 ((and (string= val "x") (string-match "^x=" val))
4650 (setq val "x="))
4651 ((string-match "^\\$[\C-a-\C-z]" val)
4652 (setq val (concat "$^" (char-to-string (+ ?A -1 (aref val 1))))))
4653 ((string-match "^CORE::" val)
4654 (setq val "CORE::"))
4655 ((string-match "^SUPER::" val)
4656 (setq val "SUPER::"))
4657 ((and (string= "<" val) (string-match "^<\\$?[a-zA-Z0-9_:]+>" val))
4658 (setq val "<NAME>")))
4659 (setq regexp (concat "^"
4660 "\\([^a-zA-Z0-9_:]+[ \t]+\\)?"
4661 (regexp-quote val)
4662 "\\([ \t([/]\\|$\\)"))
4663
4664 ;; get the buffer with the documentation text
4665 (cperl-switch-to-doc-buffer)
4666
4667 ;; lookup in the doc
4668 (goto-char (point-min))
4669 (let ((case-fold-search nil))
4670 (list
4671 (if (re-search-forward regexp (point-max) t)
4672 (save-excursion
4673 (beginning-of-line 1)
4674 (let ((lnstart (point)))
4675 (end-of-line)
4676 (message "%s" (buffer-substring lnstart (point)))))
4677 (if cperl-message-on-help-error
4678 (message "No definition for %s" val)))))))
4679
4680(defvar cperl-short-docs "Ignore my value"
4681 ;; Perl4 version was written by Johan Vromans (jvromans@squirrel.nl)
4682 "# based on '@(#)@ perl-descr.el 1.9 - describe-perl-symbol' [Perl 5]
4683! ... Logical negation.
4684... != ... Numeric inequality.
4685... !~ ... Search pattern, substitution, or translation (negated).
4686$! In numeric context: errno. In a string context: error string.
4687$\" The separator which joins elements of arrays interpolated in strings.
4688$# The output format for printed numbers. Initial value is %.15g or close.
4689$$ Process number of this script. Changes in the fork()ed child process.
4690$% The current page number of the currently selected output channel.
4691
4692 The following variables are always local to the current block:
4693
4694$1 Match of the 1st set of parentheses in the last match (auto-local).
4695$2 Match of the 2nd set of parentheses in the last match (auto-local).
4696$3 Match of the 3rd set of parentheses in the last match (auto-local).
4697$4 Match of the 4th set of parentheses in the last match (auto-local).
4698$5 Match of the 5th set of parentheses in the last match (auto-local).
4699$6 Match of the 6th set of parentheses in the last match (auto-local).
4700$7 Match of the 7th set of parentheses in the last match (auto-local).
4701$8 Match of the 8th set of parentheses in the last match (auto-local).
4702$9 Match of the 9th set of parentheses in the last match (auto-local).
4703$& The string matched by the last pattern match (auto-local).
4704$' The string after what was matched by the last match (auto-local).
4705$` The string before what was matched by the last match (auto-local).
4706
4707$( The real gid of this process.
4708$) The effective gid of this process.
4709$* Deprecated: Set to 1 to do multiline matching within a string.
4710$+ The last bracket matched by the last search pattern.
4711$, The output field separator for the print operator.
4712$- The number of lines left on the page.
4713$. The current input line number of the last filehandle that was read.
4714$/ The input record separator, newline by default.
4715$0 Name of the file containing the perl script being executed. May be set.
4716$: String may be broken after these characters to fill ^-lines in a format.
4717$; Subscript separator for multi-dim array emulation. Default \"\\034\".
4718$< The real uid of this process.
4719$= The page length of the current output channel. Default is 60 lines.
4720$> The effective uid of this process.
4721$? The status returned by the last ``, pipe close or `system'.
4722$@ The perl error message from the last eval or do @var{EXPR} command.
4723$ARGV The name of the current file used with <> .
4724$[ Deprecated: The index of the first element/char in an array/string.
4725$\\ The output record separator for the print operator.
4726$] The perl version string as displayed with perl -v.
4727$^ The name of the current top-of-page format.
4728$^A The current value of the write() accumulator for format() lines.
4729$^D The value of the perl debug (-D) flags.
4730$^E Information about the last system error other than that provided by $!.
4731$^F The highest system file descriptor, ordinarily 2.
4732$^H The current set of syntax checks enabled by `use strict'.
4733$^I The value of the in-place edit extension (perl -i option).
4734$^L What formats output to perform a formfeed. Default is \f.
4735$^O The operating system name under which this copy of Perl was built.
4736$^P Internal debugging flag.
4737$^T The time the script was started. Used by -A/-M/-C file tests.
4738$^W True if warnings are requested (perl -w flag).
4739$^X The name under which perl was invoked (argv[0] in C-speech).
4740$_ The default input and pattern-searching space.
4741$| Auto-flush after write/print on current output channel? Default 0.
4742$~ The name of the current report format.
4743... % ... Modulo division.
4744... %= ... Modulo division assignment.
4745%ENV Contains the current environment.
4746%INC List of files that have been require-d or do-ne.
4747%SIG Used to set signal handlers for various signals.
4748... & ... Bitwise and.
4749... && ... Logical and.
4750... &&= ... Logical and assignment.
4751... &= ... Bitwise and assignment.
4752... * ... Multiplication.
4753... ** ... Exponentiation.
4754*NAME Glob: all objects refered by NAME. *NAM1 = *NAM2 aliases NAM1 to NAM2.
4755&NAME(arg0, ...) Subroutine call. Arguments go to @_.
4756... + ... Addition. +EXPR Makes EXPR into scalar context.
4757++ Auto-increment (magical on strings). ++EXPR EXPR++
4758... += ... Addition assignment.
4759, Comma operator.
4760... - ... Subtraction.
4761-- Auto-decrement (NOT magical on strings). --EXPR EXPR--
4762... -= ... Subtraction assignment.
4763-A Access time in days since script started.
4764-B File is a non-text (binary) file.
4765-C Inode change time in days since script started.
4766-M Age in days since script started.
4767-O File is owned by real uid.
4768-R File is readable by real uid.
4769-S File is a socket .
4770-T File is a text file.
4771-W File is writable by real uid.
4772-X File is executable by real uid.
4773-b File is a block special file.
4774-c File is a character special file.
4775-d File is a directory.
4776-e File exists .
4777-f File is a plain file.
4778-g File has setgid bit set.
4779-k File has sticky bit set.
4780-l File is a symbolic link.
4781-o File is owned by effective uid.
4782-p File is a named pipe (FIFO).
4783-r File is readable by effective uid.
4784-s File has non-zero size.
4785-t Tests if filehandle (STDIN by default) is opened to a tty.
4786-u File has setuid bit set.
4787-w File is writable by effective uid.
4788-x File is executable by effective uid.
4789-z File has zero size.
4790. Concatenate strings.
4791.. Alternation, also range operator.
4792.= Concatenate assignment strings
4793... / ... Division. /PATTERN/ioxsmg Pattern match
4794... /= ... Division assignment.
4795/PATTERN/ioxsmg Pattern match.
4796... < ... Numeric less than. <pattern> Glob. See <NAME>, <> as well.
4797<NAME> Reads line from filehandle NAME (a bareword or dollar-bareword).
4798<pattern> Glob (Unless pattern is bareword/dollar-bareword - see <NAME>).
4799<> Reads line from union of files in @ARGV (= command line) and STDIN.
4800... << ... Bitwise shift left. << start of HERE-DOCUMENT.
4801... <= ... Numeric less than or equal to.
4802... <=> ... Numeric compare.
4803... = ... Assignment.
4804... == ... Numeric equality.
4805... =~ ... Search pattern, substitution, or translation
4806... > ... Numeric greater than.
4807... >= ... Numeric greater than or equal to.
4808... >> ... Bitwise shift right.
4809... >>= ... Bitwise shift right assignment.
4810... ? ... : ... Condition=if-then-else operator. ?PAT? One-time pattern match.
4811?PATTERN? One-time pattern match.
4812@ARGV Command line arguments (not including the command name - see $0).
4813@INC List of places to look for perl scripts during do/include/use.
4814@_ Parameter array for subroutines. Also used by split unless in array context.
4815\\ Creates reference to what follows, like \$var, or quotes non-\w in strings.
4816\\0 Octal char, e.g. \\033.
4817\\E Case modification terminator. See \\Q, \\L, and \\U.
4818\\L Lowercase until \\E . See also \l, lc.
4819\\U Upcase until \\E . See also \u, uc.
4820\\Q Quote metacharacters until \\E . See also quotemeta.
4821\\a Alarm character (octal 007).
4822\\b Backspace character (octal 010).
4823\\c Control character, e.g. \\c[ .
4824\\e Escape character (octal 033).
4825\\f Formfeed character (octal 014).
4826\\l Lowercase the next character. See also \\L and \\u, lcfirst.
4827\\n Newline character (octal 012 on most systems).
4828\\r Return character (octal 015 on most systems).
4829\\t Tab character (octal 011).
4830\\u Upcase the next character. See also \\U and \\l, ucfirst.
4831\\x Hex character, e.g. \\x1b.
4832... ^ ... Bitwise exclusive or.
4833__END__ Ends program source.
4834__DATA__ Ends program source.
4835__FILE__ Current (source) filename.
4836__LINE__ Current line in current source.
4837__PACKAGE__ Current package.
4838ARGV Default multi-file input filehandle. <ARGV> is a synonym for <>.
4839ARGVOUT Output filehandle with -i flag.
4840BEGIN { ... } Immediately executed (during compilation) piece of code.
4841END { ... } Pseudo-subroutine executed after the script finishes.
4842DATA Input filehandle for what follows after __END__ or __DATA__.
4843accept(NEWSOCKET,GENERICSOCKET)
4844alarm(SECONDS)
4845atan2(X,Y)
4846bind(SOCKET,NAME)
4847binmode(FILEHANDLE)
4848caller[(LEVEL)]
4849chdir(EXPR)
4850chmod(LIST)
4851chop[(LIST|VAR)]
4852chown(LIST)
4853chroot(FILENAME)
4854close(FILEHANDLE)
4855closedir(DIRHANDLE)
4856... cmp ... String compare.
4857connect(SOCKET,NAME)
4858continue of { block } continue { block }. Is executed after `next' or at end.
4859cos(EXPR)
4860crypt(PLAINTEXT,SALT)
4861dbmclose(%HASH)
4862dbmopen(%HASH,DBNAME,MODE)
4863defined(EXPR)
4864delete($HASH{KEY})
4865die(LIST)
4866do { ... }|SUBR while|until EXPR executes at least once
4867do(EXPR|SUBR([LIST])) (with while|until executes at least once)
4868dump LABEL
4869each(%HASH)
4870endgrent
4871endhostent
4872endnetent
4873endprotoent
4874endpwent
4875endservent
4876eof[([FILEHANDLE])]
4877... eq ... String equality.
4878eval(EXPR) or eval { BLOCK }
4879exec(LIST)
4880exit(EXPR)
4881exp(EXPR)
4882fcntl(FILEHANDLE,FUNCTION,SCALAR)
4883fileno(FILEHANDLE)
4884flock(FILEHANDLE,OPERATION)
4885for (EXPR;EXPR;EXPR) { ... }
4886foreach [VAR] (@ARRAY) { ... }
4887fork
4888... ge ... String greater than or equal.
4889getc[(FILEHANDLE)]
4890getgrent
4891getgrgid(GID)
4892getgrnam(NAME)
4893gethostbyaddr(ADDR,ADDRTYPE)
4894gethostbyname(NAME)
4895gethostent
4896getlogin
4897getnetbyaddr(ADDR,ADDRTYPE)
4898getnetbyname(NAME)
4899getnetent
4900getpeername(SOCKET)
4901getpgrp(PID)
4902getppid
4903getpriority(WHICH,WHO)
4904getprotobyname(NAME)
4905getprotobynumber(NUMBER)
4906getprotoent
4907getpwent
4908getpwnam(NAME)
4909getpwuid(UID)
4910getservbyname(NAME,PROTO)
4911getservbyport(PORT,PROTO)
4912getservent
4913getsockname(SOCKET)
4914getsockopt(SOCKET,LEVEL,OPTNAME)
4915gmtime(EXPR)
4916goto LABEL
4917grep(EXPR,LIST)
4918... gt ... String greater than.
4919hex(EXPR)
4920if (EXPR) { ... } [ elsif (EXPR) { ... } ... ] [ else { ... } ] or EXPR if EXPR
4921index(STR,SUBSTR[,OFFSET])
4922int(EXPR)
4923ioctl(FILEHANDLE,FUNCTION,SCALAR)
4924join(EXPR,LIST)
4925keys(%HASH)
4926kill(LIST)
4927last [LABEL]
4928... le ... String less than or equal.
4929length(EXPR)
4930link(OLDFILE,NEWFILE)
4931listen(SOCKET,QUEUESIZE)
4932local(LIST)
4933localtime(EXPR)
4934log(EXPR)
4935lstat(EXPR|FILEHANDLE|VAR)
4936... lt ... String less than.
4937m/PATTERN/iogsmx
4938mkdir(FILENAME,MODE)
4939msgctl(ID,CMD,ARG)
4940msgget(KEY,FLAGS)
4941msgrcv(ID,VAR,SIZE,TYPE.FLAGS)
4942msgsnd(ID,MSG,FLAGS)
4943my VAR or my (VAR1,...) Introduces a lexical variable ($VAR, @ARR, or %HASH).
4944... ne ... String inequality.
4945next [LABEL]
4946oct(EXPR)
4947open(FILEHANDLE[,EXPR])
4948opendir(DIRHANDLE,EXPR)
4949ord(EXPR) ASCII value of the first char of the string.
4950pack(TEMPLATE,LIST)
4951package NAME Introduces package context.
4952pipe(READHANDLE,WRITEHANDLE) Create a pair of filehandles on ends of a pipe.
4953pop(ARRAY)
4954print [FILEHANDLE] [(LIST)]
4955printf [FILEHANDLE] (FORMAT,LIST)
4956push(ARRAY,LIST)
4957q/STRING/ Synonym for 'STRING'
4958qq/STRING/ Synonym for \"STRING\"
4959qx/STRING/ Synonym for `STRING`
4960rand[(EXPR)]
4961read(FILEHANDLE,SCALAR,LENGTH[,OFFSET])
4962readdir(DIRHANDLE)
4963readlink(EXPR)
4964recv(SOCKET,SCALAR,LEN,FLAGS)
4965redo [LABEL]
4966rename(OLDNAME,NEWNAME)
4967require [FILENAME | PERL_VERSION]
4968reset[(EXPR)]
4969return(LIST)
4970reverse(LIST)
4971rewinddir(DIRHANDLE)
4972rindex(STR,SUBSTR[,OFFSET])
4973rmdir(FILENAME)
4974s/PATTERN/REPLACEMENT/gieoxsm
4975scalar(EXPR)
4976seek(FILEHANDLE,POSITION,WHENCE)
4977seekdir(DIRHANDLE,POS)
4978select(FILEHANDLE | RBITS,WBITS,EBITS,TIMEOUT)
4979semctl(ID,SEMNUM,CMD,ARG)
4980semget(KEY,NSEMS,SIZE,FLAGS)
4981semop(KEY,...)
4982send(SOCKET,MSG,FLAGS[,TO])
4983setgrent
4984sethostent(STAYOPEN)
4985setnetent(STAYOPEN)
4986setpgrp(PID,PGRP)
4987setpriority(WHICH,WHO,PRIORITY)
4988setprotoent(STAYOPEN)
4989setpwent
4990setservent(STAYOPEN)
4991setsockopt(SOCKET,LEVEL,OPTNAME,OPTVAL)
4992shift[(ARRAY)]
4993shmctl(ID,CMD,ARG)
4994shmget(KEY,SIZE,FLAGS)
4995shmread(ID,VAR,POS,SIZE)
4996shmwrite(ID,STRING,POS,SIZE)
4997shutdown(SOCKET,HOW)
4998sin(EXPR)
4999sleep[(EXPR)]
5000socket(SOCKET,DOMAIN,TYPE,PROTOCOL)
5001socketpair(SOCKET1,SOCKET2,DOMAIN,TYPE,PROTOCOL)
5002sort [SUBROUTINE] (LIST)
5003splice(ARRAY,OFFSET[,LENGTH[,LIST]])
5004split[(/PATTERN/[,EXPR[,LIMIT]])]
5005sprintf(FORMAT,LIST)
5006sqrt(EXPR)
5007srand(EXPR)
5008stat(EXPR|FILEHANDLE|VAR)
5009study[(SCALAR)]
5010sub [NAME [(format)]] { BODY } sub NAME [(format)]; sub [(format)] {...}
5011substr(EXPR,OFFSET[,LEN])
5012symlink(OLDFILE,NEWFILE)
5013syscall(LIST)
5014sysread(FILEHANDLE,SCALAR,LENGTH[,OFFSET])
5015system(LIST)
5016syswrite(FILEHANDLE,SCALAR,LENGTH[,OFFSET])
5017tell[(FILEHANDLE)]
5018telldir(DIRHANDLE)
5019time
5020times
5021tr/SEARCHLIST/REPLACEMENTLIST/cds
5022truncate(FILE|EXPR,LENGTH)
5023umask[(EXPR)]
5024undef[(EXPR)]
5025unless (EXPR) { ... } [ else { ... } ] or EXPR unless EXPR
5026unlink(LIST)
5027unpack(TEMPLATE,EXPR)
5028unshift(ARRAY,LIST)
5029until (EXPR) { ... } EXPR until EXPR
5030utime(LIST)
5031values(%HASH)
5032vec(EXPR,OFFSET,BITS)
5033wait
5034waitpid(PID,FLAGS)
5035wantarray Returns true if the sub/eval is called in list context.
5036warn(LIST)
5037while (EXPR) { ... } EXPR while EXPR
5038write[(EXPR|FILEHANDLE)]
5039... x ... Repeat string or array.
5040x= ... Repetition assignment.
5041y/SEARCHLIST/REPLACEMENTLIST/
5042... | ... Bitwise or.
5043... || ... Logical or.
5044~ ... Unary bitwise complement.
5045#! OS interpreter indicator. If has `perl', used for options, and -x.
5046AUTOLOAD {...} Shorthand for `sub AUTOLOAD {...}'.
5047CORE:: Prefix to access builtin function if imported sub obscures it.
5048SUPER:: Prefix to lookup for a method in @ISA classes.
5049DESTROY Shorthand for `sub DESTROY {...}'.
5050... EQ ... Obsolete synonym of `eq'.
5051... GE ... Obsolete synonym of `ge'.
5052... GT ... Obsolete synonym of `gt'.
5053... LE ... Obsolete synonym of `le'.
5054... LT ... Obsolete synonym of `lt'.
5055... NE ... Obsolete synonym of `ne'.
5056abs [ EXPR ] absolute value
5057... and ... Low-precedence synonym for &&.
5058bless REFERENCE [, PACKAGE] Makes reference into an object of a package.
5059chomp [LIST] Strips $/ off LIST/$_. Returns count. Special if $/ eq ''!
5060chr Converts a number to char with the same ordinal.
5061else Part of if/unless {BLOCK} elsif {BLOCK} else {BLOCK}.
5062elsif Part of if/unless {BLOCK} elsif {BLOCK} else {BLOCK}.
5063exists $HASH{KEY} True if the key exists.
5064format [NAME] = Start of output format. Ended by a single dot (.) on a line.
5065formline PICTURE, LIST Backdoor into \"format\" processing.
5066glob EXPR Synonym of <EXPR>.
5067lc [ EXPR ] Returns lowercased EXPR.
5068lcfirst [ EXPR ] Returns EXPR with lower-cased first letter.
5069map EXPR, LIST or map {BLOCK} LIST Applies EXPR/BLOCK to elts of LIST.
5070no PACKAGE [SYMBOL1, ...] Partial reverse for `use'. Runs `unimport' method.
5071not ... Low-precedence synonym for ! - negation.
5072... or ... Low-precedence synonym for ||.
5073pos STRING Set/Get end-position of the last match over this string, see \\G.
5074quotemeta [ EXPR ] Quote regexp metacharacters.
5075qw/WORD1 .../ Synonym of split('', 'WORD1 ...')
5076readline FH Synonym of <FH>.
5077readpipe CMD Synonym of `CMD`.
5078ref [ EXPR ] Type of EXPR when dereferenced.
5079sysopen FH, FILENAME, MODE [, PERM] (MODE is numeric, see Fcntl.)
5080tie VAR, PACKAGE, LIST Hide an object behind a simple Perl variable.
5081tied Returns internal object for a tied data.
5082uc [ EXPR ] Returns upcased EXPR.
5083ucfirst [ EXPR ] Returns EXPR with upcased first letter.
5084untie VAR Unlink an object from a simple Perl variable.
5085use PACKAGE [SYMBOL1, ...] Compile-time `require' with consequent `import'.
5086... xor ... Low-precedence synonym for exclusive or.
5087prototype \&SUB Returns prototype of the function given a reference.
5088=head1 Top-level heading.
5089=head2 Second-level heading.
5090=head3 Third-level heading (is there such?).
5091=over [ NUMBER ] Start list.
5092=item [ TITLE ] Start new item in the list.
5093=back End list.
5094=cut Switch from POD to Perl.
5095=pod Switch from Perl to POD.
5096")
5097
5098(defun cperl-switch-to-doc-buffer ()
5099 "Go to the perl documentation buffer and insert the documentation."
5100 (interactive)
5101 (let ((buf (get-buffer-create cperl-doc-buffer)))
5102 (if (interactive-p)
5103 (switch-to-buffer-other-window buf)
5104 (set-buffer buf))
5105 (if (= (buffer-size) 0)
5106 (progn
5107 (insert (documentation-property 'cperl-short-docs
5108 'variable-documentation))
5109 (setq buffer-read-only t)))))
5110
5111(defun cperl-beautify-regexp-piece (b e embed)
5112 ;; b is before the starting delimiter, e before the ending
5113 ;; e should be a marker, may be changed, but remains "correct".
5114 (let (s c tmp (m (make-marker)) (m1 (make-marker)) c1 spaces inline code)
5115 (if (not embed)
5116 (goto-char (1+ b))
5117 (goto-char b)
5118 (cond ((looking-at "(\\?\\\\#") ; badly commented (?#)
5119 (forward-char 2)
5120 (delete-char 1)
5121 (forward-char 1))
5122 ((looking-at "(\\?[^a-zA-Z]")
5123 (forward-char 3))
5124 ((looking-at "(\\?") ; (?i)
5125 (forward-char 2))
5126 (t
5127 (forward-char 1))))
5128 (setq c (if embed (current-indentation) (1- (current-column)))
5129 c1 (+ c (or cperl-regexp-indent-step cperl-indent-level)))
5130 (or (looking-at "[ \t]*[\n#]")
5131 (progn
5132 (insert "\n")))
5133 (goto-char e)
5134 (beginning-of-line)
5135 (if (re-search-forward "[^ \t]" e t)
5136 (progn
5137 (goto-char e)
5138 (insert "\n")
5139 (indent-to-column c)
5140 (set-marker e (point))))
5141 (goto-char b)
5142 (end-of-line 2)
5143 (while (< (point) (marker-position e))
5144 (beginning-of-line)
5145 (setq s (point)
5146 inline t)
5147 (skip-chars-forward " \t")
5148 (delete-region s (point))
5149 (indent-to-column c1)
5150 (while (and
5151 inline
5152 (looking-at
5153 (concat "\\([a-zA-Z0-9]+[^*+{?]\\)" ; 1 word
5154 "\\|" ; Embedded variable
5155 "\\$\\([a-zA-Z0-9_]+\\([[{]\\)?\\|[^\n \t)|]\\)" ; 2 3
5156 "\\|" ; $ ^
5157 "[$^]"
5158 "\\|" ; simple-code simple-code*?
5159 "\\(\\\\.\\|[^][()#|*+?\n]\\)\\([*+{?]\\??\\)?" ; 4 5
5160 "\\|" ; Class
5161 "\\(\\[\\)" ; 6
5162 "\\|" ; Grouping
5163 "\\((\\(\\?\\)?\\)" ; 7 8
5164 "\\|" ; |
5165 "\\(|\\)" ; 9
5166 )))
5167 (goto-char (match-end 0))
5168 (setq spaces t)
5169 (cond ((match-beginning 1) ; Alphanum word + junk
5170 (forward-char -1))
5171 ((or (match-beginning 3) ; $ab[12]
5172 (and (match-beginning 5) ; X* X+ X{2,3}
5173 (eq (preceding-char) ?\{)))
5174 (forward-char -1)
5175 (forward-sexp 1))
5176 ((match-beginning 6) ; []
5177 (setq tmp (point))
5178 (if (looking-at "\\^?\\]")
5179 (goto-char (match-end 0)))
5180 (or (re-search-forward "\\]\\([*+{?]\\)?" e t)
5181 (progn
5182 (goto-char (1- tmp))
5183 (error "[]-group not terminated")))
5184 (if (not (eq (preceding-char) ?\{)) nil
5185 (forward-char -1)
5186 (forward-sexp 1)))
5187 ((match-beginning 7) ; ()
5188 (goto-char (match-beginning 0))
5189 (or (eq (current-column) c1)
5190 (progn
5191 (insert "\n")
5192 (indent-to-column c1)))
5193 (setq tmp (point))
5194 (forward-sexp 1)
5195 ;; (or (forward-sexp 1)
5196 ;; (progn
5197 ;; (goto-char tmp)
5198 ;; (error "()-group not terminated")))
5199 (set-marker m (1- (point)))
5200 (set-marker m1 (point))
5201 (cond
5202 ((not (match-beginning 8))
5203 (cperl-beautify-regexp-piece tmp m t))
5204 ((eq (char-after (+ 2 tmp)) ?\{) ; Code
5205 t)
5206 ((eq (char-after (+ 2 tmp)) ?\() ; Conditional
5207 (goto-char (+ 2 tmp))
5208 (forward-sexp 1)
5209 (cperl-beautify-regexp-piece (point) m t))
5210 (t
5211 (cperl-beautify-regexp-piece tmp m t)))
5212 (goto-char m1)
5213 (cond ((looking-at "[*+?]\\??")
5214 (goto-char (match-end 0)))
5215 ((eq (following-char) ?\{)
5216 (forward-sexp 1)
5217 (if (eq (following-char) ?\?)
5218 (forward-char))))
5219 (skip-chars-forward " \t")
5220 (setq spaces nil)
5221 (if (looking-at "[#\n]")
5222 (progn
5223 (or (eolp) (indent-for-comment))
5224 (beginning-of-line 2))
5225 (insert "\n"))
5226 (end-of-line)
5227 (setq inline nil))
5228 ((match-beginning 9) ; |
5229 (forward-char -1)
5230 (setq tmp (point))
5231 (beginning-of-line)
5232 (if (re-search-forward "[^ \t]" tmp t)
5233 (progn
5234 (goto-char tmp)
5235 (insert "\n"))
5236 ;; first at line
5237 (delete-region (point) tmp))
5238 (indent-to-column c)
5239 (forward-char 1)
5240 (skip-chars-forward " \t")
5241 (setq spaces nil)
5242 (if (looking-at "[#\n]")
5243 (beginning-of-line 2)
5244 (insert "\n"))
5245 (end-of-line)
5246 (setq inline nil)))
5247 (or (looking-at "[ \t\n]")
5248 (not spaces)
5249 (insert " "))
5250 (skip-chars-forward " \t"))
5251 (or (looking-at "[#\n]")
5252 (error "unknown code \"%s\" in a regexp" (buffer-substring (point)
5253 (1+ (point)))))
5254 (and inline (end-of-line 2)))
5255 ;; Special-case the last line of group
5256 (if (and (>= (point) (marker-position e))
5257 (/= (current-indentation) c))
5258 (progn
5259 (beginning-of-line)
5260 (setq s (point))
5261 (skip-chars-forward " \t")
5262 (delete-region s (point))
5263 (indent-to-column c)))
5264 ))
5265
5266(defun cperl-make-regexp-x ()
5267 (save-excursion
5268 (or cperl-use-syntax-table-text-property
5269 (error "I need to have regex marked!"))
5270 ;; Find the start
5271 (re-search-backward "\\s|") ; Assume it is scanned already.
5272 ;;(forward-char 1)
5273 (let ((b (point)) (e (make-marker)) have-x delim (c (current-column))
5274 (sub-p (eq (preceding-char) ?s)) s)
5275 (forward-sexp 1)
5276 (set-marker e (1- (point)))
5277 (setq delim (preceding-char))
5278 (if (and sub-p (eq delim (char-after (- (point) 2))))
5279 (error "Possible s/blah// - do not know how to deal with"))
5280 (if sub-p (forward-sexp 1))
5281 (if (looking-at "\\sw*x")
5282 (setq have-x t)
5283 (insert "x"))
5284 ;; Protect fragile " ", "#"
5285 (if have-x nil
5286 (goto-char (1+ b))
5287 (while (re-search-forward "\\(\\=\\|[^\\\\]\\)\\(\\\\\\\\\\)*[ \t\n#]" e t) ; Need to include (?#) too?
5288 (forward-char -1)
5289 (insert "\\")
5290 (forward-char 1)))
5291 b)))
5292
5293(defun cperl-beautify-regexp ()
5294 "do it. (Experimental, may change semantics, recheck the result.)
5295We suppose that the regexp is scanned already."
5296 (interactive)
5297 (cperl-make-regexp-x)
5298 (re-search-backward "\\s|") ; Assume it is scanned already.
5299 ;;(forward-char 1)
5300 (let ((b (point)) (e (make-marker)))
5301 (forward-sexp 1)
5302 (set-marker e (1- (point)))
5303 (cperl-beautify-regexp-piece b e nil)))
5304
5305(defun cperl-contract-level ()
5306 "Find an enclosing group in regexp and contract it. Unfinished.
5307\(Experimental, may change semantics, recheck the result.)
5308We suppose that the regexp is scanned already."
5309 (interactive)
5310 (let ((bb (cperl-make-regexp-x)) done)
5311 (while (not done)
5312 (or (eq (following-char) ?\()
5313 (search-backward "(" (1+ bb) t)
5314 (error "Cannot find `(' which starts a group"))
5315 (setq done
5316 (save-excursion
5317 (skip-chars-backward "\\")
5318 (looking-at "\\(\\\\\\\\\\)*(")))
5319 (or done (forward-char -1)))
5320 (let ((b (point)) (e (make-marker)) s c)
5321 (forward-sexp 1)
5322 (set-marker e (1- (point)))
5323 (goto-char b)
5324 (while (re-search-forward "\\(#\\)\\|\n" e t)
5325 (cond
5326 ((match-beginning 1) ; #-comment
5327 (or c (setq c (current-indentation)))
5328 (beginning-of-line 2) ; Skip
5329 (setq s (point))
5330 (skip-chars-forward " \t")
5331 (delete-region s (point))
5332 (indent-to-column c))
5333 (t
5334 (delete-char -1)
5335 (just-one-space)))))))
5336
5337(defun cperl-beautify-level ()
5338 "Find an enclosing group in regexp and beautify it.
5339\(Experimental, may change semantics, recheck the result.)
5340We suppose that the regexp is scanned already."
5341 (interactive)
5342 (let ((bb (cperl-make-regexp-x)) done)
5343 (while (not done)
5344 (or (eq (following-char) ?\()
5345 (search-backward "(" (1+ bb) t)
5346 (error "Cannot find `(' which starts a group"))
5347 (setq done
5348 (save-excursion
5349 (skip-chars-backward "\\")
5350 (looking-at "\\(\\\\\\\\\\)*(")))
5351 (or done (forward-char -1)))
5352 (let ((b (point)) (e (make-marker)))
5353 (forward-sexp 1)
5354 (set-marker e (1- (point)))
5355 (cperl-beautify-regexp-piece b e nil))))
5356
5357(if (fboundp 'run-with-idle-timer)
5358 (progn
5359 (defvar cperl-help-shown nil
5360 "Non-nil means that the help was already shown now.")
5361
5362 (defvar cperl-lazy-installed nil
5363 "Non-nil means that the lazy-help handlers are installed now.")
5364
5365 (defun cperl-lazy-install ()
5366 (interactive)
5367 (make-variable-buffer-local 'cperl-help-shown)
5368 (if (and (cperl-val 'cperl-lazy-help-time)
5369 (not cperl-lazy-installed))
5370 (progn
5371 (add-hook 'post-command-hook 'cperl-lazy-hook)
5372 (run-with-idle-timer
5373 (cperl-val 'cperl-lazy-help-time 1000000 5)
5374 t
5375 'cperl-get-help-defer)
5376 (setq cperl-lazy-installed t))))
5377
5378 (defun cperl-lazy-unstall ()
5379 (interactive)
5380 (remove-hook 'post-command-hook 'cperl-lazy-hook)
5381 (cancel-function-timers 'cperl-get-help-defer)
5382 (setq cperl-lazy-installed nil))
5383
5384 (defun cperl-lazy-hook ()
5385 (setq cperl-help-shown nil))
5386
5387 (defun cperl-get-help-defer ()
5388 (if (not (eq major-mode 'perl-mode)) nil
5389 (let ((cperl-message-on-help-error nil) (cperl-help-from-timer t))
5390 (cperl-get-help)
5391 (setq cperl-help-shown t))))
5392 (cperl-lazy-install)))
5393
5394(provide 'cperl-mode)
5395
5396;;; cperl-mode.el ends here