+(defun cperl-beginning-of-property (p prop &optional lim)
+ "Given that P has a property PROP, find where the property starts.
+Will not look before LIM."
+ ;;; XXXX What to do at point-max???
+ (or (previous-single-property-change (cperl-1+ p) prop lim)
+ (point-min))
+;;; (cond ((eq p (point-min))
+;;; p)
+;;; ((and lim (<= p lim))
+;;; p)
+;;; ((not (get-text-property (1- p) prop))
+;;; p)
+;;; (t (or (previous-single-property-change p look-prop lim)
+;;; (point-min))))
+ )
+
+(defun cperl-sniff-for-indent (&optional parse-data) ; was parse-start
+ ;; Old workhorse for calculation of indentation; the major problem
+ ;; is that it mixes the sniffer logic to understand what the current line
+ ;; MEANS with the logic to actually calculate where to indent it.
+ ;; The latter part should be eventually moved to `cperl-calculate-indent';
+ ;; actually, this is mostly done now...
+ (cperl-update-syntaxification (point) (point))
+ (let ((res (get-text-property (point) 'syntax-type)))
+ (save-excursion
+ (cond
+ ((and (memq res '(pod here-doc here-doc-delim format))
+ (not (get-text-property (point) 'indentable)))
+ (vector res))
+ ;; before start of POD - whitespace found since do not have 'pod!
+ ((looking-at "[ \t]*\n=")
+ (error "Spaces before POD section!"))
+ ((and (not cperl-indent-left-aligned-comments)
+ (looking-at "^#"))
+ [comment-special:at-beginning-of-line])
+ ((get-text-property (point) 'in-pod)
+ [in-pod])
+ (t
+ (beginning-of-line)
+ (let* ((indent-point (point))
+ (char-after-pos (save-excursion
+ (skip-chars-forward " \t")
+ (point)))
+ (char-after (char-after char-after-pos))
+ (pre-indent-point (point))
+ p prop look-prop is-block delim)
+ (save-excursion ; Know we are not in POD, find appropriate pos before
+ (cperl-backward-to-noncomment nil)
+ (setq p (max (point-min) (1- (point)))
+ prop (get-text-property p 'syntax-type)
+ look-prop (or (nth 1 (assoc prop cperl-look-for-prop))
+ 'syntax-type))
+ (if (memq prop '(pod here-doc format here-doc-delim))
+ (progn
+ (goto-char (cperl-beginning-of-property p look-prop))
+ (beginning-of-line)
+ (setq pre-indent-point (point)))))
+ (goto-char pre-indent-point) ; Orig line skipping preceeding pod/etc
+ (let* ((case-fold-search nil)
+ (s-s (cperl-get-state (car parse-data) (nth 1 parse-data)))
+ (start (or (nth 2 parse-data) ; last complete sexp terminated
+ (nth 0 s-s))) ; Good place to start parsing
+ (state (nth 1 s-s))
+ (containing-sexp (car (cdr state)))
+ old-indent)
+ (if (and
+ ;;containing-sexp ;; We are buggy at toplevel :-(
+ parse-data)
+ (progn
+ (setcar parse-data pre-indent-point)
+ (setcar (cdr parse-data) state)
+ (or (nth 2 parse-data)
+ (setcar (cddr parse-data) start))
+ ;; Before this point: end of statement
+ (setq old-indent (nth 3 parse-data))))
+ (cond ((get-text-property (point) 'indentable)
+ ;; indent to "after" the surrounding open
+ ;; (same offset as `cperl-beautify-regexp-piece'),
+ ;; skip blanks if we do not close the expression.
+ (setq delim ; We do not close the expression
+ (get-text-property
+ (cperl-1+ char-after-pos) 'indentable)
+ p (1+ (cperl-beginning-of-property
+ (point) 'indentable))
+ is-block ; misused for: preceeding line in REx
+ (save-excursion ; Find preceeding line
+ (cperl-backward-to-noncomment p)
+ (beginning-of-line)
+ (if (<= (point) p)
+ (progn ; get indent from the first line
+ (goto-char p)
+ (skip-chars-forward " \t")
+ (if (memq (char-after (point))
+ (append "#\n" nil))
+ nil ; Can't use intentation of this line...
+ (point)))
+ (skip-chars-forward " \t")
+ (point)))
+ prop (parse-partial-sexp p char-after-pos))
+ (cond ((not delim) ; End the REx, ignore is-block
+ (vector 'indentable 'terminator p is-block))
+ (is-block ; Indent w.r.t. preceeding line
+ (vector 'indentable 'cont-line char-after-pos
+ is-block char-after p))
+ (t ; No preceeding line...
+ (vector 'indentable 'first-line p))))
+ ((get-text-property char-after-pos 'REx-part2)
+ (vector 'REx-part2 (point)))
+ ((nth 3 state)
+ [comment])
+ ((nth 4 state)
+ [string])
+ ;; XXXX Do we need to special-case this?
+ ((null containing-sexp)
+ ;; Line is at top level. May be data or function definition,
+ ;; or may be function argument declaration.
+ ;; Indent like the previous top level line
+ ;; unless that ends in a closeparen without semicolon,
+ ;; in which case this line is the first argument decl.
+ (skip-chars-forward " \t")
+ (cperl-backward-to-noncomment (or old-indent (point-min)))
+ (setq state
+ (or (bobp)
+ (eq (point) old-indent) ; old-indent was at comment
+ (eq (preceding-char) ?\;)
+ ;; Had ?\) too
+ (and (eq (preceding-char) ?\})
+ (cperl-after-block-and-statement-beg
+ (point-min))) ; Was start - too close
+ (memq char-after (append ")]}" nil))
+ (and (eq (preceding-char) ?\:) ; label
+ (progn
+ (forward-sexp -1)
+ (skip-chars-backward " \t")
+ (looking-at "[ \t]*[a-zA-Z_][a-zA-Z_0-9]*[ \t]*:")))
+ (get-text-property (point) 'first-format-line)))
+
+ ;; Look at previous line that's at column 0
+ ;; to determine whether we are in top-level decls
+ ;; or function's arg decls. Set basic-indent accordingly.
+ ;; Now add a little if this is a continuation line.
+ (and state
+ parse-data
+ (not (eq char-after ?\C-j))
+ (setcdr (cddr parse-data)
+ (list pre-indent-point)))
+ (vector 'toplevel start char-after state (nth 2 s-s)))
+ ((not
+ (or (setq is-block
+ (and (setq delim (= (char-after containing-sexp) ?{))
+ (save-excursion ; Is it a hash?
+ (goto-char containing-sexp)
+ (cperl-block-p))))
+ cperl-indent-parens-as-block))
+ ;; group is an expression, not a block:
+ ;; indent to just after the surrounding open parens,
+ ;; skip blanks if we do not close the expression.
+ (goto-char (1+ containing-sexp))
+ (or (memq char-after
+ (append (if delim "}" ")]}") nil))
+ (looking-at "[ \t]*\\(#\\|$\\)")
+ (skip-chars-forward " \t"))
+ (setq old-indent (point)) ; delim=is-brace
+ (vector 'in-parens char-after (point) delim containing-sexp))
+ (t
+ ;; Statement level. Is it a continuation or a new statement?
+ ;; Find previous non-comment character.
+ (goto-char pre-indent-point) ; Skip one level of POD/etc
+ (cperl-backward-to-noncomment containing-sexp)
+ ;; Back up over label lines, since they don't
+ ;; affect whether our line is a continuation.
+ ;; (Had \, too)
+ (while;;(or (eq (preceding-char) ?\,)
+ (and (eq (preceding-char) ?:)
+ (or;;(eq (char-after (- (point) 2)) ?\') ; ????
+ (memq (char-syntax (char-after (- (point) 2)))
+ '(?w ?_))))
+ ;;)
+ ;; This is always FALSE?
+ (if (eq (preceding-char) ?\,)
+ ;; Will go to beginning of line, essentially.
+ ;; Will ignore embedded sexpr XXXX.
+ (cperl-backward-to-start-of-continued-exp containing-sexp))
+ (beginning-of-line)
+ (cperl-backward-to-noncomment containing-sexp))
+ ;; Now we get non-label preceeding the indent point
+ (if (not (or (eq (1- (point)) containing-sexp)
+ (memq (preceding-char)
+ (append (if is-block " ;{" " ,;{") '(nil)))
+ (and (eq (preceding-char) ?\})
+ (cperl-after-block-and-statement-beg
+ containing-sexp))
+ (get-text-property (point) 'first-format-line)))
+ ;; This line is continuation of preceding line's statement;
+ ;; indent `cperl-continued-statement-offset' more than the
+ ;; previous line of the statement.
+ ;;
+ ;; There might be a label on this line, just
+ ;; consider it bad style and ignore it.
+ (progn
+ (cperl-backward-to-start-of-continued-exp containing-sexp)
+ (vector 'continuation (point) char-after is-block delim))
+ ;; This line starts a new statement.
+ ;; Position following last unclosed open brace
+ (goto-char containing-sexp)
+ ;; Is line first statement after an open-brace?
+ (or
+ ;; If no, find that first statement and indent like
+ ;; it. If the first statement begins with label, do
+ ;; not believe when the indentation of the label is too
+ ;; small.
+ (save-excursion
+ (forward-char 1)
+ (let ((colon-line-end 0))
+ (while
+ (progn (skip-chars-forward " \t\n")
+ (looking-at "#\\|[a-zA-Z0-9_$]*:[^:]\\|=[a-zA-Z]"))
+ ;; Skip over comments and labels following openbrace.
+ (cond ((= (following-char) ?\#)
+ (forward-line 1))
+ ((= (following-char) ?\=)
+ (goto-char
+ (or (next-single-property-change (point) 'in-pod)
+ (point-max)))) ; do not loop if no syntaxification
+ ;; label:
+ (t
+ (save-excursion (end-of-line)
+ (setq colon-line-end (point)))
+ (search-forward ":"))))
+ ;; We are at beginning of code (NOT label or comment)
+ ;; First, the following code counts
+ ;; if it is before the line we want to indent.
+ (and (< (point) indent-point)
+ (vector 'have-prev-sibling (point) colon-line-end
+ containing-sexp))))
+ (progn
+ ;; If no previous statement,
+ ;; indent it relative to line brace is on.
+
+ ;; For open-braces not the first thing in a line,
+ ;; add in cperl-brace-imaginary-offset.
+
+ ;; If first thing on a line: ?????
+ ;; Move back over whitespace before the openbrace.
+ (setq ; brace first thing on a line
+ old-indent (progn (skip-chars-backward " \t") (bolp)))
+ ;; Should we indent w.r.t. earlier than start?
+ ;; Move to start of control group, possibly on a different line
+ (or cperl-indent-wrt-brace
+ (cperl-backward-to-noncomment (point-min)))
+ ;; If the openbrace is preceded by a parenthesized exp,
+ ;; move to the beginning of that;
+ (if (eq (preceding-char) ?\))
+ (progn
+ (forward-sexp -1)
+ (cperl-backward-to-noncomment (point-min))))
+ ;; In the case it starts a subroutine, indent with
+ ;; respect to `sub', not with respect to the
+ ;; first thing on the line, say in the case of
+ ;; anonymous sub in a hash.
+ (if (and;; Is it a sub in group starting on this line?
+ (cond ((get-text-property (point) 'attrib-group)
+ (goto-char (cperl-beginning-of-property
+ (point) 'attrib-group)))
+ ((eq (preceding-char) ?b)
+ (forward-sexp -1)
+ (looking-at "sub\\>")))
+ (setq p (nth 1 ; start of innermost containing list
+ (parse-partial-sexp
+ (save-excursion (beginning-of-line)
+ (point))
+ (point)))))
+ (progn
+ (goto-char (1+ p)) ; enclosing block on the same line
+ (skip-chars-forward " \t")
+ (vector 'code-start-in-block containing-sexp char-after
+ (and delim (not is-block)) ; is a HASH
+ old-indent ; brace first thing on a line
+ t (point) ; have something before...
+ )
+ ;;(current-column)
+ )
+ ;; Get initial indentation of the line we are on.
+ ;; If line starts with label, calculate label indentation
+ (vector 'code-start-in-block containing-sexp char-after
+ (and delim (not is-block)) ; is a HASH
+ old-indent ; brace first thing on a line
+ nil (point) ; nothing interesting before
+ ))))))))))))))
+
+(defvar cperl-indent-rules-alist
+ '((pod nil) ; via `syntax-type' property
+ (here-doc nil) ; via `syntax-type' property
+ (here-doc-delim nil) ; via `syntax-type' property
+ (format nil) ; via `syntax-type' property
+ (in-pod nil) ; via `in-pod' property
+ (comment-special:at-beginning-of-line nil)
+ (string t)
+ (comment nil))
+ "Alist of indentation rules for CPerl mode.
+The values mean:
+ nil: do not indent;
+ number: add this amount of indentation.
+
+Not finished.")
+