3 ;; FILE: br-python-ft.el
4 ;; SUMMARY: Python OO-Browser class and member functions.
5 ;; USAGE: GNU Emacs Lisp Library
6 ;; KEYWORDS: python, oop, tools
8 ;; AUTHOR: Harri Pasanen / Bob Weiner
9 ;; based on Smalltalk and C++ OO-Browsers
12 ;; ORIG-DATE: 5-Apr-96
13 ;; LAST-MOD: 10-May-01 at 19:21:10 by Bob Weiner
15 ;; Copyright (C) 1996, 1997, 1998 BeOpen.com
16 ;; See the file BR-COPY for license information.
18 ;; This file is part of the OO-Browser.
21 ;; There may still be traces of C++ origin in this file.
24 ;;; ************************************************************************
25 ;;; Other required Elisp libraries
26 ;;; ************************************************************************
31 ;;; ************************************************************************
33 ;;; ************************************************************************
35 (defconst python-feature-entry-regexp
36 (concat br-feature-type-regexp " \\(.+\\.\\)?\\([^\t\n\r]*[^ \t\n\r]\\)")
37 "Regexp matching a Python feature entry string from a browser listing buffer.")
39 (defvar python-import-dirs
40 (if (stringp (getenv "PYTHONPATH"))
41 (mapcar 'file-name-as-directory (split-string (getenv "PYTHONPATH") ":"))
42 '("/usr/local/lib/python/"))
43 "Ordered list of module directories searched by the python interpreter.
44 Each directory must end with a directory separator.")
46 (defconst python-type-tag-separator "@"
47 "String that separates a tag's type from its normalized definition form.
48 This should be a single character which is unchanged when quoted for use as a
49 literal in a regular expression.")
51 (defconst python-tag-fields-regexp
52 ;; The \\\\? below is necessary because we sometimes use this expression to
53 ;; test against a string that has ben regexp-quoted and some of the
54 ;; characters in br-feature-type-regexp will then be preceded by \\.
55 (format "^\\([^%s \n]+\\)%s\\\\?\\(%s \\)\\([^%s\n]+\\)%s"
56 python-type-tag-separator python-type-tag-separator br-feature-type-regexp
57 python-type-tag-separator python-type-tag-separator)
58 "Regexp matching the fields of a Python feature tag line.
59 Group 1 is the class of the feature. Group 2 is the prefix preceding the
60 feature when displayed within a listing buffer. Group 3 is the feature name.
61 The feature definition signature begins at the end of the regexp match,
62 i.e. (match-end 0), and goes to the end of the string or line.")
64 ;;; ************************************************************************
66 ;;; ************************************************************************
68 (defun python-add-default-classes ()
70 (c-add-default-classes)
71 ;; Add to categorize module functions
72 (br-add-default-classes '("[function]")))
73 (br-add-default-classes '("[global]" "[module]" "[package]")))
75 (defun python-feature-implementors (name)
76 "Return unsorted list of Python feature tags which implement feature NAME."
78 (python-feature-matches (concat "^" (regexp-quote name) "$"))
79 (python-feature-matches (concat "\\." (regexp-quote name) "$"))))
81 (defun python-feature-signature-to-name (feature-sig-or-tag &optional with-class for-display)
82 "Extracts the feature name from FEATURE-SIG-OR-TAG.
83 The feature's class name is dropped from feature-sig-or-tag unless optional
84 WITH-CLASS is non-nil. If optional FOR-DISPLAY is non-nil, a feature type
85 character is prepended to the name for display in a browser listing."
86 (if (br-feature-tag-p feature-sig-or-tag)
87 (br-feature-tag-name feature-sig-or-tag with-class for-display)
91 ((string-match python-tag-fields-regexp feature-sig-or-tag)
92 (setq name (substring feature-sig-or-tag
93 (match-beginning (if for-display 2 3))
97 (substring feature-sig-or-tag
98 (match-beginning 1) (match-end 1))
100 ;; Remove any trailing whitespace.
101 (br-delete-space name))
104 (t;; Remove any trailing whitespace and add display prefix.
105 (setq name (br-delete-space feature-sig-or-tag))
106 (if for-display (concat "- " name) name))))))
108 (defun python-scan-features ()
109 "Return reverse ordered list of current module's global attributes and function definitions.
110 Assume point is at the beginning of a widened buffer."
112 (let ((case-fold-search)
113 (features) globals class name feat start)
116 (while (re-search-forward python-global-def nil t)
117 (setq start (match-beginning 0))
118 (if (python-within-string-p)
119 ;; ignore any feature found and skip to the end of the string
120 (re-search-forward python-multi-line-string-delimiter nil t)
121 ;; otherwise record the globals found
122 (setq globals (nreverse (python-scan-globals))
123 feat (br-buffer-substring start (point)))
127 (function (lambda (global)
128 (python-feature-normalize feat "[global]" global)))
132 ;; Record non-member functions
133 (goto-char (point-min))
134 (while (re-search-forward python-routine-def nil t)
135 (setq class "[function]"
136 name (br-buffer-substring
137 (match-beginning python-feature-name-grpn)
138 (match-end python-feature-name-grpn))
139 feat (python-feature-normalize
140 (br-buffer-substring (match-beginning 0) (match-end 0))
142 (if (python-within-string-p)
143 ;; ignore any feature found and skip to the end of the string
144 (re-search-forward python-multi-line-string-delimiter nil t)
145 ;; otherwise record the function found
146 (setq features (cons feat features))))
149 (defun python-to-definition (&optional other-win)
150 "If point is on an import statement, look for the module file.
151 With OTHER-WIN non-nil, show it in another window."
154 ((python-import-file other-win))
157 "(OO-Browser): Select an import statement to display its source.")
160 (defun python-insert-entry-info ()
161 "Insert `python-docstring' into the current buffer at point."
163 (insert python-docstring))
165 (defalias 'python-insert-class-info 'python-insert-entry-info)
167 ;; Optional arg below is solely for call compatibility when called with
168 ;; an argument from br-store-class-info. The argument is not used under
170 (defun python-store-entry-info (&optional entry)
171 "Set `python-docstring' to the documentation for the listing entry at point and return it.
172 Return nil if no documentation is available."
173 (setq python-docstring (python-lookup-docstring)))
175 (defalias 'python-store-class-info 'python-store-entry-info)
177 ;;; ************************************************************************
178 ;;; Private functions
179 ;;; ************************************************************************
181 (defun python-lookup-docstring ()
182 "Look up and return a docstring for the browser listing entry at point or nil."
188 (pydoc-interface-p (fboundp 'pydoc-commands)))
190 (cond ((br-at-feature-p)
191 (setq feature-tag (br-feature-get-tag)
192 entry-name (br-feature-tag-name feature-tag)
193 file-name (br-feature-tag-path feature-tag))
194 ;; Entry-type may be: [package], [module], [global], [function]
196 (setq entry-type (br-feature-tag-class feature-tag))
197 (if (not (br-member entry-type '("[package]" "[module]" "[global]"
199 (setq entry-type "[method]")))
201 ((and (setq entry-name (br-find-class-name))
202 (br-class-in-table-p entry-name))
203 (setq file-name (br-class-path entry-name))
204 ;; entry type may be a class or interface; consider them the
205 ;; same for documentation extraction purposes
206 (setq entry-type "[class]"))
208 (t (error "(OO-Browser): Entry referenced but not defined in the Environment.")))
210 (if (and file-name (not (string-equal entry-type "[global]")))
212 (if pydoc-interface-p
214 (save-window-excursion
216 (cond ((string-equal entry-type "[package]")
217 (if (or (not (fboundp 'pydoc-package-list))
218 (br-member entry-name (pydoc-package-list)))
219 (progn (pydoc-packages entry-name)
220 (setq docstring (buffer-string)))))
222 ((string-equal entry-type "[module]")
223 (if (or (not (fboundp 'pydoc-module-list))
224 (br-member entry-name (pydoc-module-list)))
225 (progn (pydoc-modules entry-name)
226 (setq docstring (buffer-string)))))
228 ((br-member entry-type '("[function]" "[method]"))
229 (pydoc-help entry-name)
230 (setq docstring (buffer-string)))))
232 (setq docstring nil))))
235 (python-get-docstring-from-source
236 entry-name entry-type feature-tag file-name)))))
240 (defun python-get-docstring-from-source (entry-name entry-type feature-tag file-name)
241 "Scan source for ENTRY-NAME's docstring using ENTRY-TYPE, FEATURE-TAG and FILE-NAME.
242 ENTRY-TYPE must a string, one of [package], [module], [function], [method] or
244 (let ((no-kill (get-file-buffer file-name))
249 (set-buffer no-kill))
250 ((not (file-directory-p file-name))
251 (br-insert-file-contents file-name)))
253 (goto-char (point-min))
254 (cond ((string-equal entry-type "[class]")
255 (if (re-search-forward (python-class-definition-regexp
258 ;; Skip over any superclass list
259 (if (char-equal (preceding-char) ?\()
260 (progn (backward-char 1)
262 (setq docstring (python-extract-docstring)))))
264 ((br-member entry-type '("[function]" "[method]"))
265 (if (python-feature-locate-p feature-tag)
266 ;; Skip past argument list
267 (if (> (skip-chars-forward "^\(") 0)
270 (setq docstring (python-extract-docstring))))))
272 ((string-equal entry-type "[module]")
273 (setq docstring (python-extract-docstring)))
275 ((string-equal entry-type "[package]")
276 (setq file-name (expand-file-name "__init__.py" file-name)
277 no-kill (get-file-buffer file-name))
280 (br-insert-file-contents file-name))
281 (setq docstring (python-extract-docstring))))))
284 (kill-buffer *br-tmp-buffer*))
287 (defun python-extract-docstring ()
288 "Return the documentation string after point, or nil if none."
289 (skip-chars-forward ": \t")
291 (concat python-empty-line "*[ \t]*" python-string-start))
292 (let ((start (match-end 0))
293 (end-quote (br-buffer-substring (match-beginning 4) (match-end 4))))
295 (if (search-forward end-quote nil t)
296 (br-buffer-substring start (match-beginning 0))))))
298 (defconst python-string-start
301 "'''" ; triple single-quoted
303 "\"\"\"" ; triple double-quoted
305 "'" ; single-quoted, not empty
307 "\"" ; double-quoted, not empty
309 "regexp matching python string literal starting quotes")
311 (defconst python-empty-line
312 "\\(\\([ \t]*[\n\r]+\\)\\|\\([ \t]*#.*$\\)\\)"
313 "Regexp matching an empty or python comment line.")
315 (defun python-within-comment-p ()
316 "Return non-nil if point is within a Python comment."
318 (and (re-search-backward "#\\|\n" nil t)
319 (not (looking-at "\n")))))
321 (defun python-within-string-p ()
322 "Return non-nil if point is within a multi-line python string."
325 (while (re-search-forward python-multi-line-string-delimiter nil t)
326 (setq count (1+ count)))
329 (defun python-feature-map-tags (function regexp)
330 "Apply FUNCTION to all current feature tags that match REGEXP and return a list of the results."
331 (let ((identifier-chars (concat "[" python-identifier-chars ".]*"))
333 ;; Ensure handle "^" and "$" meta-chars.
335 (concat (format "\\`%s " br-feature-type-regexp)
336 (if (equal (substring regexp 0 1) "^")
337 (progn (setq regexp (substring regexp 1)) nil)
339 (if (equal (substring regexp -1) "$")
340 (substring regexp 0 -1)
341 (concat regexp identifier-chars))
343 (br-feature-map-tags function regexp)))
345 (defun python-feature-matches (regexp)
346 "Return an unsorted list of feature tags whose names match in part or whole to REGEXP.
347 ^ and $ characters may be used to match to the beginning and end of a feature name,
349 (python-feature-map-tags 'identity regexp))
351 (defun python-feature-normalize (feature class name)
352 "Return a feature tag based on FEATURE, CLASS and NAME."
353 (setq class (br-delete-space class))
354 (setq name (if (equal class "[global]")
357 (let* ((len (length feature))
358 (normal-feature (make-string len ?\ ))
360 (space-regexp "[ \t\n\r]+")
361 (original-syntax-table (syntax-table))
365 (set-syntax-table text-mode-syntax-table)
367 (setq chr (aref feature i))
369 ;; Convert sequences of space characters to a single space.
370 ;; GNU Emacs doesn't support optional syntax-table arg to
372 ((eq (char-syntax chr) ?\ )
373 (if (string-match space-regexp feature i)
374 (progn (setq i (match-end 0))
375 (if (not (and (> n 0)
376 (eq (aref normal-feature (1- n)) ?\ )))
384 (while (and (< i len) (not (eq (aref feature i) ?\n)))
386 (t ;; Normal character
387 (aset normal-feature n chr)
390 (concat class python-type-tag-separator
391 name python-type-tag-separator
392 (br-delete-space (substring normal-feature 0 n))))
393 (set-syntax-table original-syntax-table))))
395 (defun python-files-with-source (class)
396 "Use CLASS to compute set of files that match to a Python source file regexp.
398 (let ((file (if class (br-class-path class) buffer-file-name)))
400 (let* ((src-file-regexp (concat "^" (br-filename-head file)
401 python-code-file-regexp))
402 (dir (file-name-directory file))
403 (files (directory-files dir nil src-file-regexp)))
404 (mapcar (function (lambda (f) (expand-file-name f dir)))
407 (defun python-find-ancestors-feature (class-list ftr-pat &optional other-win)
408 "Scan ancestors of CLASS-LIST and show routine definition matching FTR-PAT."
409 ;; If no class, search for a non-member function.
410 (or class-list (setq class-list '(nil)))
411 (br-feature-display class-list ftr-pat other-win))
413 (defun python-find-class-name ()
414 "Return current word as a potential class name."
417 (ignore "\]\[ \t\n\r\f\;,.\(\){}*&-")
418 (pat (concat "^" ignore)))
420 (skip-chars-backward ignore)
421 (skip-chars-backward pat)
423 (skip-chars-forward (concat pat ":"))
424 (br-buffer-substring start (point)))))
426 (defun python-output-feature-tags (routine-file routine-tags-list)
427 "Write Python ROUTINE-FILE's ROUTINE-TAGS-LIST into `br-feature-tags-file'.
428 Assume `br-feature-tags-init' has been called."
431 (br-feature-set-tags-buffer)
433 ;; Delete any prior routine tags associated with routine-file
434 (if (search-forward routine-file nil 'end)
435 (progn (forward-line -1)
436 (let ((start (point)))
437 (search-forward "\^L" nil 'end 2)
439 (delete-region start (point)))))
440 (if routine-tags-list
441 (progn (insert "\^L\n")
442 ;; Quote pathname to avoid read errors on MS OSes.
443 (prin1 routine-file (current-buffer))
445 (mapcar (function (lambda (tag) (insert tag "\n")))
446 routine-tags-list)))))
448 (defun python-find-module-name ()
449 "Return current word as a potential module name."
453 (skip-chars-backward python-identifier-chars)
455 (skip-chars-forward python-identifier-chars)
456 (br-buffer-substring start (point)))))
458 (defun python-import-file (&optional other-win)
459 "If point is on an import module line, display the module, method or function name at point.
460 With optional OTHER-WIN non-nil, display it in the other window.
462 Return non-nil iff point is on an import file line, even if a matching entry
463 is not found. When found return the full pathname to the import entry,
466 Look for import files within `python-import-dirs' and any Environment
468 (let ((opoint (point)))
470 (cond ((looking-at python-import-modules-regexp)
472 (max opoint (match-beginning python-import-name-grpn)))
473 ;; Have to avoid selecting anything within a # comment here.
474 (goto-char (match-beginning python-import-name-grpn))
476 (max opoint (match-beginning python-import-name-grpn))))
477 (let* ((import-name (python-find-module-name))
478 (path (python-import-pathname import-name)))
479 ;; If found, display file
480 (python-display-module import-name path other-win)
482 ((looking-at python-import-functions-regexp)
484 (max opoint (match-beginning python-import-name-grpn)))
485 ;; Have to avoid selecting anything within a # comment here.
486 (goto-char (match-beginning python-import-name-grpn))
488 (max opoint (match-beginning python-import-name-grpn))))
489 (setq opoint (point))
490 (let* ((end-module-name (match-end python-import-name-grpn))
493 (match-beginning python-import-name-grpn)
494 (match-end python-import-name-grpn)))
495 (import-name (python-find-module-name))
496 (path (python-import-pathname module-name)))
497 ;; If found, display file
498 (if (python-display-module module-name path other-win)
499 (if (or (<= opoint end-module-name)
500 (equal import-name "import")
501 (equal import-name ""))
503 (if (re-search-forward
504 (concat "^[ \t]*\\(class\\|def\\|\\)"
505 "\\(" (regexp-quote import-name) "\\)"
506 "[^" python-identifier-chars "]")
508 (goto-char (match-beginning 2))
510 (message "(OO-Browser): Found module `%s' but not member `%s'."
511 module-name import-name))))
513 (t (goto-char opoint)
516 (defun python-display-module (module-name path other-win)
517 "Display file associated with MODULE-NAME and PATH in OTHER-WIN (if non-nil).
518 Return t if file is displayed, nil otherwise."
520 (if (file-readable-p path)
522 (funcall br-edit-file-function path other-win)
524 (goto-char (point-min))
525 (if (not (fboundp 'br-lang-mode))
530 (message "(OO-Browser): Module `%s' is unreadable." path)
533 (message "(OO-Browser): Cannot find module `%s'." module-name)
536 (defun python-import-pathname (import-name)
537 "Return the full pathname to a Python IMPORT-NAME or nil if none.
538 Look for import files within `python-import-dirs' and any Environment
540 (if (not (stringp import-name))
541 (error "(python-import-pathname): Invalid import name, `%s'" import-name))
542 (if (string-match "\\.py\\'" import-name)
543 (setq import-name (substring import-name 0 (match-beginning 0))))
544 ;; Convert import-name a.b.c to pathname form, a/b/c.
545 (setq import-name (hypb:replace-match-string
547 (file-name-as-directory "/")
549 (setq import-name (concat import-name ".py"))
550 (let ((dir-list (append python-lib-search-dirs python-sys-search-dirs
555 (setq dir-list (cons (file-name-directory buffer-file-name)
557 (while (and (not found) dir-list)
558 (setq path (expand-file-name import-name (car dir-list)))
559 (or (setq found (file-exists-p path))
560 (setq dir-list (cdr dir-list))))
562 ;; If not found in normal include dirs, check all Env paths also.
565 (let ((paths (delq nil (hash-map 'cdr br-paths-htable))))
566 (while (and (not found) paths)
567 (setq path (car paths))
568 (if (string-equal (file-name-nondirectory path) import-name)
569 (setq found t paths nil)
570 (setq paths (cdr paths))))))
573 (defun python-scan-ancestors-feature (class-list ftr-pat &optional other-win)
574 "Display routine definition derived from CLASS-LIST, matching FTR-PAT.
575 Scan files with same base name as class file."
576 (let ((classes class-list)
582 (if (null class-list)
584 (while (and (not found-ftr) classes)
585 (setq class (car classes)
586 code-def-files (python-files-with-source class)
587 ftr-sig-regexp (funcall ftr-pat class))
588 (while (and (setq file (car code-def-files))
590 (br-feature-found-p file ftr-sig-regexp
592 (setq code-def-files (cdr code-def-files)))
593 (setq classes (if found-ftr nil (cdr classes))))
596 (python-scan-ancestors-feature
597 (apply 'append (mapcar (function (lambda (cl) (br-get-parents cl)))
601 (defun python-scan-features-in-class (class start end)
602 "Return reverse ordered list of Python routine definitions within CLASS def.
603 START and END give buffer region to search."
604 (setq class (br-delete-space class))
607 (narrow-to-region start end)
609 (let ((routines) rout name)
611 ;; Get member definitions
613 (while (re-search-forward python-routine-def-in-class nil t)
614 (setq start (match-beginning 0)
615 name (concat class "."
617 (match-beginning python-feature-name-grpn)
618 (match-end python-feature-name-grpn)))
619 rout (python-feature-normalize
620 (br-buffer-substring (match-beginning 0) (match-end 0))
622 routines (cons rout routines)))
625 (defun python-scan-globals ()
626 "Return list of globals names from a single global statement.
627 Point must be after the 'global' keyword which begins the list of comma
628 separated identifiers."
629 (let ((global-list) (again t)
631 (while (and again (re-search-forward python-global-name nil t))
632 (setq again (eq ?, (following-char))
633 global (br-buffer-substring (match-beginning 1)
635 global-list (cons global global-list)))
636 (nreverse global-list)))
638 (defun python-feature-locate-p (feature-tag &optional regexp-flag)
639 "Leave point at the start of FEATURE-TAG's definition in the current buffer.
640 Assume caller has moved point to the beginning of the buffer or to the point
641 of desired search start.
642 Optional REGEXP-FLAG means FEATURE-TAG is a regular expression."
643 (let ((case-fold-search) (start)
644 (found t) feature-sig feature-regexp class)
645 (if (br-feature-tag-p feature-tag)
646 (setq feature-sig (br-feature-tag-signature feature-tag)
647 class (br-feature-tag-class feature-tag))
648 (setq feature-sig feature-tag
651 (if (stringp feature-tag)
652 (setq feature-regexp feature-tag)
653 (error "(python-feature-locate-p): Not a regexp, %s" feature-tag)))
655 ;; First move to the proper class implementation if feature-tag does not
656 ;; include a <class>:: part and this is not a [default-class], so that if
657 ;; two classes in the same file have the same feature signature, we still
658 ;; end up at the right one.
660 (if (or (string-match "\\`\\[" class)
661 (and feature-sig (string-match "::" feature-sig)))
663 (setq found (re-search-forward
664 (python-class-definition-regexp class nil)
666 start (match-beginning 0))))
667 ((string-match python-tag-fields-regexp feature-sig)
668 (setq class (substring feature-sig
669 (match-beginning 1) (match-end 1))
670 feature-sig (substring feature-sig (match-end 0)))
671 (if (or (and regexp-flag
672 (not (string-match "\\`\\\\\\[\\|::" feature-regexp)))
674 (string-match "\\`\\[\\|::" feature-tag))))
675 (setq found (re-search-forward
676 (python-class-definition-regexp class regexp-flag)
678 start (match-beginning 0)))))
680 ;; If class was searched for and not found, then skip down to code display.
683 ;; Otherwise, look for feature expression.
685 (or regexp-flag (setq feature-regexp
686 (python-feature-signature-to-regexp feature-sig)))
687 (while (and (re-search-forward feature-regexp nil t)
688 (setq start (match-beginning 0))
690 (cond ((eq major-mode 'python-mode)
691 (cond ((python-within-comment-p)
693 ((python-within-string-p)
695 python-multi-line-string-delimiter nil t)
698 ;; must be a C/C++ file
699 ((c-within-comment-p)
700 (search-forward "*/" nil t)
703 (if found (br-display-code start))))
705 (defun python-feature-name-to-regexp (name)
706 "Converts routine NAME into a regular expression matching the routine's name tag."
707 (setq name (python-feature-signature-to-regexp name))
708 (aset name (1- (length name)) ?\() ;; Match only to functions
711 (defun python-feature-signature-to-regexp (signature)
712 "Given a Python SIGNATURE, return regexp used to match to its definition."
713 (setq signature (regexp-quote signature))
715 (if (string-match python-tag-fields-regexp signature)
716 (prog1 (substring signature (match-beginning 0) (match-end 0))
717 (setq signature (substring signature (match-end 0)))))))
718 (let ((pat) (i 0) (c) (len (length signature)))
720 (setq c (aref signature i)
722 ;; Allow for possible single line comment
723 ;; following any whitespace, e.g. following
724 ;; each routine argument.
725 (concat pat "[ \t\n\r]*\\(#.*\\)?"))
727 (concat pat (char-to-string c))))
729 (setq pat (concat prefix-info pat)))))
734 ;;; ************************************************************************
735 ;;; Private variables
736 ;;; ************************************************************************
738 (defvar python-docstring ""
739 "Documentation string for python class, method or function.")
741 (defconst python-code-file-regexp "\\.py\\'"
742 "Regexp which matches a unique part of a Python source (non-header) file name and no others.")
744 (defconst python-import-modules-regexp
745 (concat "^[ \t]*import[ \t]+" python-identifier "[^#\n\r]+")
746 "Regexp which matches Python module import statements.
747 Grouping `python-import-name-grpn' matches the first import module name.")
749 (defconst python-import-functions-regexp
750 (concat "^[ \t]*from[ \t]+" python-identifier "[ \t\n\r]+import[ \t]+[^#\n\r]+")
751 "Regexp which matches Python function import statements.
752 Grouping `python-import-name-grpn' matches the import module name.")
754 (defconst python-global-def "^global[ \t]+"
755 "Regexp which matches a global definition statement.
756 After a match to this expression, point is left after the 'global' keyword.")
758 (defconst python-routine-def
759 (concat "^def[ \t]+" python-identifier "[ \t\n\r\\]*[^:]+")
760 "Regexp which matches a global python function definition.
761 Grouping `python-feature-name-grpn' matches the function name.
762 After a match to this expression, point is left before the colon
763 terminating the signature line.")
765 (defconst python-routine-def-in-class
766 (concat "^[ \t]+def[ \t]+" python-identifier "[ \t\n\r\\]*[^:]+")
767 "Regexp which matches a python class method definition.
768 Grouping `python-feature-name-grpn' matches the function name.
769 After a match to this expression, point is left before the colon
770 terminating the signature line.")
772 (defconst python-feature-name-grpn 1
773 "Feature name grouping from `python-routine-def' and `python-routine-def-in-class' matches.")
775 (defconst python-import-name-grpn 1
776 "Module name regexp grouping for import statements.")
778 (defconst python-multi-line-string-delimiter "'''\\|\"\"\""
779 "Regexp matching a Python multi-line string Start or end delimiter.")
781 (provide 'br-python-ft)