diff options
| author | Fabián Ezequiel Gallina | 2015-04-05 23:58:13 -0300 |
|---|---|---|
| committer | Fabián Ezequiel Gallina | 2015-04-05 23:58:13 -0300 |
| commit | deea36f0ece7b1b14afe2a833b6a0f66d59f4459 (patch) | |
| tree | e3e41e0a5a03b0ea83b293c0c65835be038d56d4 /lisp/progmodes/python.el | |
| parent | 7514b24b6a512d85b762c603e9e0107d2c8a52f1 (diff) | |
| download | emacs-deea36f0ece7b1b14afe2a833b6a0f66d59f4459.tar.gz emacs-deea36f0ece7b1b14afe2a833b6a0f66d59f4459.zip | |
python.el: Enhance docstring detection following PEP-257.
* lisp/progmodes/python.el (python-docstring-at-p): Remove function.
(python-info-assignment-statement-p): New function.
(python-info-assignment-continuation-line-p): Use it.
(python-info-docstring-p): New function.
(python-font-lock-syntactic-face-function)
(python-fill-string): Use it.
* test/automated/python-tests.el (python-info-assignment-statement-p-1)
(python-info-assignment-statement-p-2)
(python-info-assignment-statement-p-3, python-info-docstring-p-1)
(python-info-docstring-p-2, python-info-docstring-p-3)
(python-info-docstring-p-4, python-info-docstring-p-5)
(python-info-docstring-p-6): New tests.
Diffstat (limited to 'lisp/progmodes/python.el')
| -rw-r--r-- | lisp/progmodes/python.el | 96 |
1 files changed, 69 insertions, 27 deletions
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 67b44aa1bbe..f402ad83cca 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el | |||
| @@ -482,19 +482,10 @@ The type returned can be `comment', `string' or `paren'." | |||
| 482 | 'python-info-ppss-comment-or-string-p | 482 | 'python-info-ppss-comment-or-string-p |
| 483 | #'python-syntax-comment-or-string-p "24.3") | 483 | #'python-syntax-comment-or-string-p "24.3") |
| 484 | 484 | ||
| 485 | (defun python-docstring-at-p (pos) | ||
| 486 | "Check to see if there is a docstring at POS." | ||
| 487 | (save-excursion | ||
| 488 | (goto-char pos) | ||
| 489 | (if (looking-at-p "'''\\|\"\"\"") | ||
| 490 | (progn | ||
| 491 | (python-nav-backward-statement) | ||
| 492 | (looking-at "\\`\\|class \\|def ")) | ||
| 493 | nil))) | ||
| 494 | |||
| 495 | (defun python-font-lock-syntactic-face-function (state) | 485 | (defun python-font-lock-syntactic-face-function (state) |
| 486 | "Return syntactic face given STATE." | ||
| 496 | (if (nth 3 state) | 487 | (if (nth 3 state) |
| 497 | (if (python-docstring-at-p (nth 8 state)) | 488 | (if (python-info-docstring-p state) |
| 498 | font-lock-doc-face | 489 | font-lock-doc-face |
| 499 | font-lock-string-face) | 490 | font-lock-string-face) |
| 500 | font-lock-comment-face)) | 491 | font-lock-comment-face)) |
| @@ -3587,17 +3578,12 @@ JUSTIFY should be used (if applicable) as in `fill-paragraph'." | |||
| 3587 | (`pep-257 (and multi-line-p (cons nil 2))) | 3578 | (`pep-257 (and multi-line-p (cons nil 2))) |
| 3588 | (`pep-257-nn (and multi-line-p (cons nil 1))) | 3579 | (`pep-257-nn (and multi-line-p (cons nil 1))) |
| 3589 | (`symmetric (and multi-line-p (cons 1 1))))) | 3580 | (`symmetric (and multi-line-p (cons 1 1))))) |
| 3590 | (docstring-p (save-excursion | ||
| 3591 | ;; Consider docstrings those strings which | ||
| 3592 | ;; start on a line by themselves. | ||
| 3593 | (python-nav-beginning-of-statement) | ||
| 3594 | (and (= (point) str-start-pos)))) | ||
| 3595 | (fill-paragraph-function)) | 3581 | (fill-paragraph-function)) |
| 3596 | (save-restriction | 3582 | (save-restriction |
| 3597 | (narrow-to-region str-start-pos str-end-pos) | 3583 | (narrow-to-region str-start-pos str-end-pos) |
| 3598 | (fill-paragraph justify)) | 3584 | (fill-paragraph justify)) |
| 3599 | (save-excursion | 3585 | (save-excursion |
| 3600 | (when (and docstring-p python-fill-docstring-style) | 3586 | (when (and (python-info-docstring-p) python-fill-docstring-style) |
| 3601 | ;; Add the number of newlines indicated by the selected style | 3587 | ;; Add the number of newlines indicated by the selected style |
| 3602 | ;; at the start of the docstring. | 3588 | ;; at the start of the docstring. |
| 3603 | (goto-char (+ str-start-pos num-quotes)) | 3589 | (goto-char (+ str-start-pos num-quotes)) |
| @@ -4423,23 +4409,40 @@ where the continued line ends." | |||
| 4423 | (when (looking-at (python-rx block-start)) | 4409 | (when (looking-at (python-rx block-start)) |
| 4424 | (point-marker))))) | 4410 | (point-marker))))) |
| 4425 | 4411 | ||
| 4412 | (defun python-info-assignment-statement-p (&optional current-line-only) | ||
| 4413 | "Check if current line is an assignment. | ||
| 4414 | With argument CURRENT-LINE-ONLY is non-nil, don't follow any | ||
| 4415 | continuations, just check the if current line is an assignment." | ||
| 4416 | (save-excursion | ||
| 4417 | (let ((found nil)) | ||
| 4418 | (if current-line-only | ||
| 4419 | (back-to-indentation) | ||
| 4420 | (python-nav-beginning-of-statement)) | ||
| 4421 | (while (and | ||
| 4422 | (re-search-forward (python-rx not-simple-operator | ||
| 4423 | assignment-operator | ||
| 4424 | (group not-simple-operator)) | ||
| 4425 | (line-end-position) t) | ||
| 4426 | (not found)) | ||
| 4427 | (save-excursion | ||
| 4428 | ;; The assignment operator should not be inside a string. | ||
| 4429 | (backward-char (length (match-string-no-properties 1))) | ||
| 4430 | (setq found (not (python-syntax-context-type))))) | ||
| 4431 | (when found | ||
| 4432 | (skip-syntax-forward " ") | ||
| 4433 | (point-marker))))) | ||
| 4434 | |||
| 4435 | ;; TODO: rename to clarify this is only for the first continuation | ||
| 4436 | ;; line or remove it and move its body to `python-indent-context'. | ||
| 4426 | (defun python-info-assignment-continuation-line-p () | 4437 | (defun python-info-assignment-continuation-line-p () |
| 4427 | "Check if current line is a continuation of an assignment. | 4438 | "Check if current line is the first continuation of an assignment. |
| 4428 | When current line is continuation of another with an assignment | 4439 | When current line is continuation of another with an assignment |
| 4429 | return the point of the first non-blank character after the | 4440 | return the point of the first non-blank character after the |
| 4430 | operator." | 4441 | operator." |
| 4431 | (save-excursion | 4442 | (save-excursion |
| 4432 | (when (python-info-continuation-line-p) | 4443 | (when (python-info-continuation-line-p) |
| 4433 | (forward-line -1) | 4444 | (forward-line -1) |
| 4434 | (back-to-indentation) | 4445 | (python-info-assignment-statement-p t)))) |
| 4435 | (when (and (not (looking-at (python-rx block-start))) | ||
| 4436 | (and (re-search-forward (python-rx not-simple-operator | ||
| 4437 | assignment-operator | ||
| 4438 | not-simple-operator) | ||
| 4439 | (line-end-position) t) | ||
| 4440 | (not (python-syntax-context-type)))) | ||
| 4441 | (skip-syntax-forward "\s") | ||
| 4442 | (point-marker))))) | ||
| 4443 | 4446 | ||
| 4444 | (defun python-info-looking-at-beginning-of-defun (&optional syntax-ppss) | 4447 | (defun python-info-looking-at-beginning-of-defun (&optional syntax-ppss) |
| 4445 | "Check if point is at `beginning-of-defun' using SYNTAX-PPSS." | 4448 | "Check if point is at `beginning-of-defun' using SYNTAX-PPSS." |
| @@ -4464,6 +4467,45 @@ operator." | |||
| 4464 | (* whitespace) line-end)) | 4467 | (* whitespace) line-end)) |
| 4465 | (string-equal "" (match-string-no-properties 1)))) | 4468 | (string-equal "" (match-string-no-properties 1)))) |
| 4466 | 4469 | ||
| 4470 | (defun python-info-docstring-p (&optional syntax-ppss) | ||
| 4471 | "Return non-nil if point is in a docstring. | ||
| 4472 | When optional argument SYNTAX-PPSS is given, use that instead of | ||
| 4473 | point's current `syntax-ppss'." | ||
| 4474 | ;;; https://www.python.org/dev/peps/pep-0257/#what-is-a-docstring | ||
| 4475 | (save-excursion | ||
| 4476 | (when (and syntax-ppss (python-syntax-context 'string syntax-ppss)) | ||
| 4477 | (goto-char (nth 8 syntax-ppss))) | ||
| 4478 | (python-nav-beginning-of-statement) | ||
| 4479 | (let ((counter 1) | ||
| 4480 | (indentation (current-indentation)) | ||
| 4481 | (backward-sexp-point) | ||
| 4482 | (re (concat "[uU]?[rR]?" | ||
| 4483 | (python-rx string-delimiter)))) | ||
| 4484 | (when (and | ||
| 4485 | (not (python-info-assignment-statement-p)) | ||
| 4486 | (looking-at-p re) | ||
| 4487 | ;; Allow up to two consecutive docstrings only. | ||
| 4488 | (>= | ||
| 4489 | 2 | ||
| 4490 | (progn | ||
| 4491 | (while (save-excursion | ||
| 4492 | (python-nav-backward-sexp) | ||
| 4493 | (setq backward-sexp-point (point)) | ||
| 4494 | (and (= indentation (current-indentation)) | ||
| 4495 | (looking-at-p | ||
| 4496 | (concat "[uU]?[rR]?" | ||
| 4497 | (python-rx string-delimiter))))) | ||
| 4498 | ;; Previous sexp was a string, restore point. | ||
| 4499 | (goto-char backward-sexp-point) | ||
| 4500 | (cl-incf counter)) | ||
| 4501 | counter))) | ||
| 4502 | (python-util-forward-comment -1) | ||
| 4503 | (python-nav-beginning-of-statement) | ||
| 4504 | (cond ((bobp)) | ||
| 4505 | ((python-info-assignment-statement-p) t) | ||
| 4506 | ((python-info-looking-at-beginning-of-defun)) | ||
| 4507 | (t nil)))))) | ||
| 4508 | |||
| 4467 | (defun python-info-encoding-from-cookie () | 4509 | (defun python-info-encoding-from-cookie () |
| 4468 | "Detect current buffer's encoding from its coding cookie. | 4510 | "Detect current buffer's encoding from its coding cookie. |
| 4469 | Returns the encoding as a symbol." | 4511 | Returns the encoding as a symbol." |