Function: cperl-imenu--create-perl-index

cperl-imenu--create-perl-index is an interactive and byte-compiled function defined in cperl-mode.el.gz.

Signature

(cperl-imenu--create-perl-index)

Documentation

Implement imenu-create-index-function for CPerl mode.

This function relies on syntaxification to exclude lines which look like declarations but actually are part of a string, a comment, or POD.

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/progmodes/cperl-mode.el.gz
(defun cperl-imenu--create-perl-index ()
  "Implement `imenu-create-index-function' for CPerl mode.
This function relies on syntaxification to exclude lines which
look like declarations but actually are part of a string, a
comment, or POD."
  (interactive) ; We'll remove that at some point
  (goto-char (point-min))
  (cperl-update-syntaxification (point-max))
  (let ((case-fold-search nil)
	(index-alist '())
	(index-package-alist '())
	(index-pod-alist '())
	(index-sub-alist '())
	(index-unsorted-alist '())
	(package-stack '())                 ; for package NAME BLOCK
	(current-package "(main)")
	(current-package-end (point-max)))   ; end of package scope
    ;; collect index entries
    (while (re-search-forward (rx (eval cperl--imenu-entries-rx)) nil t)
      ;; First, check whether we have left the scope of previously
      ;; recorded packages, and if so, eliminate them from the stack.
      (while (< current-package-end (point))
	(setq current-package (pop package-stack))
	(setq current-package-end (pop package-stack)))
      (let ((state (syntax-ppss))
            (entry-type (match-string 1))
	    name marker) ; for the "current" entry
	(cond
	 ((nth 3 state) nil)            ; matched in a string, so skip
         ((member entry-type cperl-imenu-package-keywords) ; package or class
	  (unless (nth 4 state)         ; skip if in a comment
	    (setq name (match-string-no-properties 2)
		  marker (copy-marker (match-end 2)))
	    (if  (string= (match-string 3) ";")
		(setq current-package name)  ; package NAME;
	      ;; No semicolon, therefore we have: package NAME BLOCK.
	      ;; Stash the current package, because we need to restore
	      ;; it after the end of BLOCK.
	      (push current-package-end package-stack)
	      (push current-package package-stack)
	      ;; record the current name and its scope
	      (setq current-package name)
	      (setq current-package-end (save-excursion
					  (goto-char (match-beginning 3))
					  (forward-sexp)
					  (point))))
	    (push (cons name marker) index-package-alist)
	    (push (cons (concat entry-type " " name) marker) index-unsorted-alist)))
	 ((or (member entry-type cperl-imenu-sub-keywords) ; sub or method
              (string-equal entry-type ""))                ; named blocks
	  (unless (nth 4 state)         ; skip if in a comment
	    (setq name (match-string-no-properties 2)
		  marker (copy-marker (match-end 2)))
	    ;; Qualify the sub name with the package if it doesn't
	    ;; already have one, and if it isn't lexically scoped.
	    ;; "my" and "state" subs are lexically scoped, but "our"
	    ;; are just lexical aliases to package subs.
	    (if (and (null (string-match "::" name))
		     (or (null (match-string 3))
			 (string-equal (match-string 3) "our")))
	      (setq name (concat current-package "::" name)))
	    (let ((index (cons name marker)))
	      (push index index-alist)
	      (push index index-sub-alist)
	      (push index index-unsorted-alist))))
	 ((member entry-type cperl-imenu-pod-keywords)  ; POD heading
	  (when (get-text-property (match-beginning 2) 'in-pod)
	    (setq name (concat (make-string
				(* 3 (- (char-after (match-beginning 3)) ?1))
				?\ )
			       (match-string-no-properties 2))
		  marker (copy-marker (match-beginning 2)))
	    (push (cons name marker) index-pod-alist)
	    (push (cons (concat "=" name) marker) index-unsorted-alist)))
	 (t (error "Unidentified match: %s" (match-string 0))))))
    ;; Now format the collected stuff
    (setq index-alist
	  (if (default-value 'imenu-sort-function)
	      (sort index-alist (default-value 'imenu-sort-function))
	    (nreverse index-alist)))
    (and index-pod-alist
	 (push (cons "+POD headers+..."
		     (nreverse index-pod-alist))
	       index-alist))
    (and (or index-package-alist index-sub-alist)
	 (let ((lst index-package-alist) hier-list pack elt group name)
	   ;; reverse and uniquify.
	   (while lst
	     (setq elt (car lst) lst (cdr lst) name (car elt))
	     (if (assoc name hier-list) nil
	       (setq hier-list (cons (cons name (cdr elt)) hier-list))))
	   (setq lst index-sub-alist)
	   (while lst
	     (setq elt (car lst) lst (cdr lst))
	     (cond ((string-match
                     (rx (sequence (or "::" "'")
                                   (eval cperl--basic-identifier-rx)
                                   string-end))
                     (car elt))
		    (setq pack (substring (car elt) 0 (match-beginning 0)))
		    (if (setq group (assoc pack hier-list))
			(if (listp (cdr group))
			    ;; Have some functions already
			    (setcdr group
				    (cons (cons (substring
						 (car elt)
						 (+ 2 (match-beginning 0)))
						(cdr elt))
					  (cdr group)))
			  (setcdr group (list (cons (substring
						     (car elt)
						     (+ 2 (match-beginning 0)))
						    (cdr elt)))))
		      (setq hier-list
			    (cons (cons pack
					(list (cons (substring
						     (car elt)
						     (+ 2 (match-beginning 0)))
						    (cdr elt))))
				  hier-list))))))
	   (push (cons "+Hierarchy+..."
		       hier-list)
		 index-alist)))
    (and index-package-alist
	 (push (cons "+Packages+..."
		     (nreverse index-package-alist))
	       index-alist))
    (and (or index-package-alist index-pod-alist
	     (default-value 'imenu-sort-function))
	 index-unsorted-alist
	 (push (cons "+Unsorted List+..."
		     (nreverse index-unsorted-alist))
	       index-alist))
    ;; Finally, return the whole collection
    index-alist))