Mercurial > emacs
comparison lisp/progmodes/python.el @ 78755:38a441bc4532
Merge changes from Dave Love's v2007-Sep-10.
(python-font-lock-keywords): Update to the 2.5 version of the language.
(python-quote-syntax): Let-bind font-lock-syntactic-keywords to nil.
(python-backspace): Only behave funny in code.
(python-compilation-regexp-alist): Add PDB stack trace regexp.
(inferior-python-mode): Add PDB prompt regexp.
(python-fill-paragraph): Refine the fenced-string regexp.
(python-find-imports): Handle imports spanning several lines.
(python-mode): Add `class' to hideshow support.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Mon, 10 Sep 2007 20:02:31 +0000 |
parents | 419c5c316b51 |
children | 9aa24f503773 |
comparison
equal
deleted
inserted
replaced
78754:a09b799218f8 | 78755:38a441bc4532 |
---|---|
1 ;;; python.el --- silly walks for Python | 1 ;;; python.el --- silly walks for Python -*- coding: iso-8859-1 -*- |
2 | 2 |
3 ;; Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. | 3 ;; Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. |
4 | 4 |
5 ;; Author: Dave Love <fx@gnu.org> | 5 ;; Author: Dave Love <fx@gnu.org> |
6 ;; Maintainer: FSF | 6 ;; Maintainer: FSF |
87 | 87 |
88 ;;;; Font lock | 88 ;;;; Font lock |
89 | 89 |
90 (defvar python-font-lock-keywords | 90 (defvar python-font-lock-keywords |
91 `(,(rx symbol-start | 91 `(,(rx symbol-start |
92 ;; From v 2.4 reference. | 92 ;; From v 2.5 reference, § keywords. |
93 ;; def and class dealt with separately below | 93 ;; def and class dealt with separately below |
94 (or "and" "assert" "break" "continue" "del" "elif" "else" | 94 (or "and" "as" "assert" "break" "continue" "del" "elif" "else" |
95 "except" "exec" "finally" "for" "from" "global" "if" | 95 "except" "exec" "finally" "for" "from" "global" "if" |
96 "import" "in" "is" "lambda" "not" "or" "pass" "print" | 96 "import" "in" "is" "lambda" "not" "or" "pass" "print" |
97 "raise" "return" "try" "while" "yield" | 97 "raise" "return" "try" "while" "with" "yield" |
98 ;; Future keywords | |
99 "as" "None" "with" | |
100 ;; Not real keywords, but close enough to be fontified as such | 98 ;; Not real keywords, but close enough to be fontified as such |
101 "self" "True" "False") | 99 "self" "True" "False") |
102 symbol-end) | 100 symbol-end) |
101 (,(rx symbol-start "None" symbol-end) ; See § Keywords in 2.5 manual. | |
102 . font-lock-constant-face) | |
103 ;; Definitions | 103 ;; Definitions |
104 (,(rx symbol-start (group "class") (1+ space) (group (1+ (or word ?_)))) | 104 (,(rx symbol-start (group "class") (1+ space) (group (1+ (or word ?_)))) |
105 (1 font-lock-keyword-face) (2 font-lock-type-face)) | 105 (1 font-lock-keyword-face) (2 font-lock-type-face)) |
106 (,(rx symbol-start (group "def") (1+ space) (group (1+ (or word ?_)))) | 106 (,(rx symbol-start (group "def") (1+ space) (group (1+ (or word ?_)))) |
107 (1 font-lock-keyword-face) (2 font-lock-function-name-face)) | 107 (1 font-lock-keyword-face) (2 font-lock-function-name-face)) |
149 (save-excursion | 149 (save-excursion |
150 (goto-char (match-beginning 0)) | 150 (goto-char (match-beginning 0)) |
151 (cond | 151 (cond |
152 ;; Consider property for the last char if in a fenced string. | 152 ;; Consider property for the last char if in a fenced string. |
153 ((= n 3) | 153 ((= n 3) |
154 (let ((syntax (syntax-ppss))) | 154 (let* ((font-lock-syntactic-keywords nil) |
155 (syntax (syntax-ppss))) | |
155 (when (eq t (nth 3 syntax)) ; after unclosed fence | 156 (when (eq t (nth 3 syntax)) ; after unclosed fence |
156 (goto-char (nth 8 syntax)) ; fence position | 157 (goto-char (nth 8 syntax)) ; fence position |
157 (skip-chars-forward "uUrR") ; skip any prefix | 158 (skip-chars-forward "uUrR") ; skip any prefix |
158 ;; Is it a matching sequence? | 159 ;; Is it a matching sequence? |
159 (if (eq (char-after) (char-after (match-beginning 2))) | 160 (if (eq (char-after) (char-after (match-beginning 2))) |
161 ;; Consider property for initial char, accounting for prefixes. | 162 ;; Consider property for initial char, accounting for prefixes. |
162 ((or (and (= n 2) ; leading quote (not prefix) | 163 ((or (and (= n 2) ; leading quote (not prefix) |
163 (= (match-beginning 1) (match-end 1))) ; prefix is null | 164 (= (match-beginning 1) (match-end 1))) ; prefix is null |
164 (and (= n 1) ; prefix | 165 (and (= n 1) ; prefix |
165 (/= (match-beginning 1) (match-end 1)))) ; non-empty | 166 (/= (match-beginning 1) (match-end 1)))) ; non-empty |
166 (unless (nth 3 (syntax-ppss)) | 167 (let ((font-lock-syntactic-keywords nil)) |
167 (eval-when-compile (string-to-syntax "|")))) | 168 (unless (nth 3 (syntax-ppss)) |
169 (eval-when-compile (string-to-syntax "|"))))) | |
168 ;; Otherwise (we're in a non-matching string) the property is | 170 ;; Otherwise (we're in a non-matching string) the property is |
169 ;; nil, which is OK. | 171 ;; nil, which is OK. |
170 ))) | 172 ))) |
171 | 173 |
172 ;; This isn't currently in `font-lock-defaults' as probably not worth | 174 ;; This isn't currently in `font-lock-defaults' as probably not worth |
346 (condition-case () | 348 (condition-case () |
347 (progn (backward-up-list) t) ; actually within brackets | 349 (progn (backward-up-list) t) ; actually within brackets |
348 (error nil)))))))) | 350 (error nil)))))))) |
349 | 351 |
350 (defun python-comment-line-p () | 352 (defun python-comment-line-p () |
351 "Return non-nil if current line has only a comment." | 353 "Return non-nil iff current line has only a comment." |
352 (save-excursion | 354 (save-excursion |
353 (end-of-line) | 355 (end-of-line) |
354 (when (eq 'comment (syntax-ppss-context (syntax-ppss))) | 356 (when (eq 'comment (syntax-ppss-context (syntax-ppss))) |
355 (back-to-indentation) | 357 (back-to-indentation) |
356 (looking-at (rx (or (syntax comment-start) line-end)))))) | 358 (looking-at (rx (or (syntax comment-start) line-end)))))) |
357 | 359 |
358 (defun python-blank-line-p () | 360 (defun python-blank-line-p () |
359 "Return non-nil if current line is blank." | 361 "Return non-nil iff current line is blank." |
360 (save-excursion | 362 (save-excursion |
361 (beginning-of-line) | 363 (beginning-of-line) |
362 (looking-at "\\s-*$"))) | 364 (looking-at "\\s-*$"))) |
363 | 365 |
364 (defun python-beginning-of-string () | 366 (defun python-beginning-of-string () |
848 | 850 |
849 (defun python-skip-out (&optional forward syntax) | 851 (defun python-skip-out (&optional forward syntax) |
850 "Skip out of any nested brackets. | 852 "Skip out of any nested brackets. |
851 Skip forward if FORWARD is non-nil, else backward. | 853 Skip forward if FORWARD is non-nil, else backward. |
852 If SYNTAX is non-nil it is the state returned by `syntax-ppss' at point. | 854 If SYNTAX is non-nil it is the state returned by `syntax-ppss' at point. |
853 Return non-nil if skipping was done." | 855 Return non-nil iff skipping was done." |
854 (let ((depth (syntax-ppss-depth (or syntax (syntax-ppss)))) | 856 (let ((depth (syntax-ppss-depth (or syntax (syntax-ppss)))) |
855 (forward (if forward -1 1))) | 857 (forward (if forward -1 1))) |
856 (unless (zerop depth) | 858 (unless (zerop depth) |
857 (if (> depth 0) | 859 (if (> depth 0) |
858 ;; Skip forward out of nested brackets. | 860 ;; Skip forward out of nested brackets. |
1073 (python-indent-line))) ; OK, do it | 1075 (python-indent-line))) ; OK, do it |
1074 (put 'python-electric-colon 'delete-selection t) | 1076 (put 'python-electric-colon 'delete-selection t) |
1075 | 1077 |
1076 (defun python-backspace (arg) | 1078 (defun python-backspace (arg) |
1077 "Maybe delete a level of indentation on the current line. | 1079 "Maybe delete a level of indentation on the current line. |
1078 Do so if point is at the end of the line's indentation. | 1080 Do so if point is at the end of the line's indentation outside |
1081 strings and comments. | |
1079 Otherwise just call `backward-delete-char-untabify'. | 1082 Otherwise just call `backward-delete-char-untabify'. |
1080 Repeat ARG times." | 1083 Repeat ARG times." |
1081 (interactive "*p") | 1084 (interactive "*p") |
1082 (if (or (/= (current-indentation) (current-column)) | 1085 (if (or (/= (current-indentation) (current-column)) |
1083 (bolp) | 1086 (bolp) |
1084 (python-continuation-line-p)) | 1087 (python-continuation-line-p) |
1088 (python-in-string/comment)) | |
1085 (backward-delete-char-untabify arg) | 1089 (backward-delete-char-untabify arg) |
1086 ;; Look for the largest valid indentation which is smaller than | 1090 ;; Look for the largest valid indentation which is smaller than |
1087 ;; the current indentation. | 1091 ;; the current indentation. |
1088 (let ((indent 0) | 1092 (let ((indent 0) |
1089 (ci (current-indentation)) | 1093 (ci (current-indentation)) |
1180 (group (1+ (not (any "\"<")))) ; avoid `<stdin>' &c | 1184 (group (1+ (not (any "\"<")))) ; avoid `<stdin>' &c |
1181 "\", line " (group (1+ digit))) | 1185 "\", line " (group (1+ digit))) |
1182 1 2) | 1186 1 2) |
1183 (,(rx " in file " (group (1+ not-newline)) " on line " | 1187 (,(rx " in file " (group (1+ not-newline)) " on line " |
1184 (group (1+ digit))) | 1188 (group (1+ digit))) |
1189 1 2) | |
1190 ;; pdb stack trace | |
1191 (,(rx line-start "> " (group (1+ (not (any "(\"<")))) | |
1192 "(" (group (1+ digit)) ")" (1+ (not (any "("))) "()") | |
1185 1 2)) | 1193 1 2)) |
1186 "`compilation-error-regexp-alist' for inferior Python.") | 1194 "`compilation-error-regexp-alist' for inferior Python.") |
1187 | 1195 |
1188 (defvar inferior-python-mode-map | 1196 (defvar inferior-python-mode-map |
1189 (let ((map (make-sparse-keymap))) | 1197 (let ((map (make-sparse-keymap))) |
1190 ;; This will inherit from comint-mode-map. | 1198 ;; This will inherit from comint-mode-map. |
1191 (define-key map "\C-c\C-l" 'python-load-file) | 1199 (define-key map "\C-c\C-l" 'python-load-file) |
1192 (define-key map "\C-c\C-v" 'python-check) | 1200 (define-key map "\C-c\C-v" 'python-check) |
1193 ;; Note that we _can_ still use these commands which send to the | 1201 ;; Note that we _can_ still use these commands which send to the |
1194 ;; Python process even at the prompt provided we have a normal prompt, | 1202 ;; Python process even at the prompt iff we have a normal prompt, |
1195 ;; i.e. '>>> ' and not '... '. See the comment before | 1203 ;; i.e. '>>> ' and not '... '. See the comment before |
1196 ;; python-send-region. Fixme: uncomment these if we address that. | 1204 ;; python-send-region. Fixme: uncomment these if we address that. |
1197 | 1205 |
1198 ;; (define-key map [(meta ?\t)] 'python-complete-symbol) | 1206 ;; (define-key map [(meta ?\t)] 'python-complete-symbol) |
1199 ;; (define-key map "\C-c\C-f" 'python-describe-symbol) | 1207 ;; (define-key map "\C-c\C-f" 'python-describe-symbol) |
1235 (add-hook 'comint-preoutput-filter-functions #'python-preoutput-filter | 1243 (add-hook 'comint-preoutput-filter-functions #'python-preoutput-filter |
1236 nil t) | 1244 nil t) |
1237 ;; Still required by `comint-redirect-send-command', for instance | 1245 ;; Still required by `comint-redirect-send-command', for instance |
1238 ;; (and we need to match things like `>>> ... >>> '): | 1246 ;; (and we need to match things like `>>> ... >>> '): |
1239 (set (make-local-variable 'comint-prompt-regexp) | 1247 (set (make-local-variable 'comint-prompt-regexp) |
1240 (rx line-start (1+ (and (repeat 3 (any ">.")) " ")))) | 1248 (rx line-start (1+ (and (or (repeat 3 (any ">.")) "(Pdb)") " ")))) |
1241 (set (make-local-variable 'compilation-error-regexp-alist) | 1249 (set (make-local-variable 'compilation-error-regexp-alist) |
1242 python-compilation-regexp-alist) | 1250 python-compilation-regexp-alist) |
1243 (compilation-shell-minor-mode 1)) | 1251 (compilation-shell-minor-mode 1)) |
1244 | 1252 |
1245 (defcustom inferior-python-filter-regexp "\\`\\s-*\\S-?\\S-?\\s-*\\'" | 1253 (defcustom inferior-python-filter-regexp "\\`\\s-*\\S-?\\S-?\\s-*\\'" |
1727 (if (member (match-string 1) python-jython-packages) | 1735 (if (member (match-string 1) python-jython-packages) |
1728 (throw 'done t)))) | 1736 (throw 'done t)))) |
1729 (jython-mode))))))) | 1737 (jython-mode))))))) |
1730 | 1738 |
1731 (defun python-fill-paragraph (&optional justify) | 1739 (defun python-fill-paragraph (&optional justify) |
1732 "`fill-paragraph-function' handling comments and multi-line strings. | 1740 "`fill-paragraph-function' handling multi-line strings and possibly comments. |
1733 If any of the current line is a comment, fill the comment or the | 1741 If any of the current line is in or at the end of a multi-line string, |
1734 paragraph of it that point is in, preserving the comment's | 1742 fill the string or the paragraph of it that point is in, preserving |
1735 indentation and initial comment characters. Similarly if the end | 1743 the strings's indentation." |
1736 of the current line is in or at the end of a multi-line string. | |
1737 Otherwise, do nothing." | |
1738 (interactive "P") | 1744 (interactive "P") |
1739 (or (fill-comment-paragraph justify) | 1745 (or (fill-comment-paragraph justify) |
1740 ;; The `paragraph-start' and `paragraph-separate' variables | |
1741 ;; don't allow us to delimit the last paragraph in a multi-line | |
1742 ;; string properly, so narrow to the string and then fill around | |
1743 ;; (the end of) the current line. | |
1744 (save-excursion | 1746 (save-excursion |
1745 (end-of-line) | 1747 (end-of-line) |
1746 (let* ((syntax (syntax-ppss)) | 1748 (let* ((syntax (syntax-ppss)) |
1747 (orig (point)) | 1749 (orig (point)) |
1748 (start (nth 8 syntax)) | 1750 start end) |
1749 end) | 1751 (cond ((nth 4 syntax) ; comment. fixme: loses with trailing one |
1750 (cond ((eq t (nth 3 syntax)) ; in fenced string | 1752 (let (fill-paragraph-function) |
1751 (goto-char (nth 8 syntax)) ; string start | 1753 (fill-paragraph justify))) |
1754 ;; The `paragraph-start' and `paragraph-separate' | |
1755 ;; variables don't allow us to delimit the last | |
1756 ;; paragraph in a multi-line string properly, so narrow | |
1757 ;; to the string and then fill around (the end of) the | |
1758 ;; current line. | |
1759 ((eq t (nth 3 syntax)) ; in fenced string | |
1760 (goto-char (nth 8 syntax)) ; string start | |
1761 (setq start (line-beginning-position)) | |
1752 (setq end (condition-case () ; for unbalanced quotes | 1762 (setq end (condition-case () ; for unbalanced quotes |
1753 (progn (forward-sexp) (point)) | 1763 (progn (forward-sexp) |
1764 (- (point) 3)) | |
1754 (error (point-max))))) | 1765 (error (point-max))))) |
1755 ((re-search-backward "\\s|\\s-*\\=" nil t) ; end of fenced | 1766 ((re-search-backward "\\s|\\s-*\\=" nil t) ; end of fenced string |
1756 ; string | |
1757 (forward-char) | 1767 (forward-char) |
1758 (setq end (point)) | 1768 (setq end (point)) |
1759 (condition-case () | 1769 (condition-case () |
1760 (progn (backward-sexp) | 1770 (progn (backward-sexp) |
1761 (setq start (point))) | 1771 (setq start (line-beginning-position))) |
1762 (error (setq end nil))))) | 1772 (error nil)))) |
1763 (when end | 1773 (when end |
1764 (save-restriction | 1774 (save-restriction |
1765 (narrow-to-region start end) | 1775 (narrow-to-region start end) |
1766 (goto-char orig) | 1776 (goto-char orig) |
1767 (let ((paragraph-separate | 1777 ;; Avoid losing leading and trailing newlines in doc |
1768 ;; Make sure that fenced-string delimiters that stand | 1778 ;; strings written like: |
1769 ;; on their own line stay there. | 1779 ;; """ |
1770 (concat "[ \t]*['\"]+[ \t]*$\\|" paragraph-separate))) | 1780 ;; ... |
1771 (fill-paragraph justify)))))) | 1781 ;; """ |
1772 t)) | 1782 (let* ((paragraph-separate |
1783 (concat ".*\\s|\"\"$" ; newline after opening quotes | |
1784 "\\|\\(?:" paragraph-separate "\\)")) | |
1785 (paragraph-start | |
1786 (concat ".*\\s|\"\"[ \t]*[^ \t].*" ; not newline after | |
1787 ; opening quotes | |
1788 "\\|\\(?:" paragraph-separate "\\)")) | |
1789 (fill-paragraph-function)) | |
1790 (fill-paragraph justify))))))) t) | |
1773 | 1791 |
1774 (defun python-shift-left (start end &optional count) | 1792 (defun python-shift-left (start end &optional count) |
1775 "Shift lines in region COUNT (the prefix arg) columns to the left. | 1793 "Shift lines in region COUNT (the prefix arg) columns to the left. |
1776 COUNT defaults to `python-indent'. If region isn't active, just shift | 1794 COUNT defaults to `python-indent'. If region isn't active, just shift |
1777 current line. The region shifted includes the lines in which START and | 1795 current line. The region shifted includes the lines in which START and |
1864 (save-excursion | 1882 (save-excursion |
1865 (let (lines) | 1883 (let (lines) |
1866 (goto-char (point-min)) | 1884 (goto-char (point-min)) |
1867 (while (re-search-forward "^import\\>\\|^from\\>" nil t) | 1885 (while (re-search-forward "^import\\>\\|^from\\>" nil t) |
1868 (unless (syntax-ppss-context (syntax-ppss)) | 1886 (unless (syntax-ppss-context (syntax-ppss)) |
1869 (push (buffer-substring (line-beginning-position) | 1887 (let ((start (line-beginning-position))) |
1870 (line-beginning-position 2)) | 1888 ;; Skip over continued lines. |
1871 lines))) | 1889 (while (and (eq ?\\ (char-before (line-end-position))) |
1890 (= 0 (forward-line 1)))) | |
1891 (push (buffer-substring start (line-beginning-position 2)) | |
1892 lines)))) | |
1872 (setq python-imports | 1893 (setq python-imports |
1873 (if lines | 1894 (if lines |
1874 (apply #'concat | 1895 (apply #'concat |
1875 ;; This is probably best left out since you're unlikely to need the | 1896 ;; This is probably best left out since you're unlikely to need the |
1876 ;; doc for a function in the buffer and the import will lose if the | 1897 ;; doc for a function in the buffer and the import will lose if the |
2257 nil t) | 2278 nil t) |
2258 ;; Fixme: should be in hideshow. This seems to be of limited use | 2279 ;; Fixme: should be in hideshow. This seems to be of limited use |
2259 ;; since it isn't (can't be) indentation-based. Also hide-level | 2280 ;; since it isn't (can't be) indentation-based. Also hide-level |
2260 ;; doesn't seem to work properly. | 2281 ;; doesn't seem to work properly. |
2261 (add-to-list 'hs-special-modes-alist | 2282 (add-to-list 'hs-special-modes-alist |
2262 `(python-mode "^\\s-*def\\>" nil "#" | 2283 `(python-mode "^\\s-*\\(?:def\\|class\\)\\>" nil "#" |
2263 ,(lambda (arg) | 2284 ,(lambda (arg) |
2264 (python-end-of-defun) | 2285 (python-end-of-defun) |
2265 (skip-chars-backward " \t\n")) | 2286 (skip-chars-backward " \t\n")) |
2266 nil)) | 2287 nil)) |
2267 (set (make-local-variable 'skeleton-further-elements) | 2288 (set (make-local-variable 'skeleton-further-elements) |