1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-04 02:51:31 -08:00

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.
This commit is contained in:
Fabián Ezequiel Gallina 2015-04-05 23:58:13 -03:00
parent 7514b24b6a
commit deea36f0ec
4 changed files with 262 additions and 27 deletions

View file

@ -482,19 +482,10 @@ The type returned can be `comment', `string' or `paren'."
'python-info-ppss-comment-or-string-p
#'python-syntax-comment-or-string-p "24.3")
(defun python-docstring-at-p (pos)
"Check to see if there is a docstring at POS."
(save-excursion
(goto-char pos)
(if (looking-at-p "'''\\|\"\"\"")
(progn
(python-nav-backward-statement)
(looking-at "\\`\\|class \\|def "))
nil)))
(defun python-font-lock-syntactic-face-function (state)
"Return syntactic face given STATE."
(if (nth 3 state)
(if (python-docstring-at-p (nth 8 state))
(if (python-info-docstring-p state)
font-lock-doc-face
font-lock-string-face)
font-lock-comment-face))
@ -3587,17 +3578,12 @@ JUSTIFY should be used (if applicable) as in `fill-paragraph'."
(`pep-257 (and multi-line-p (cons nil 2)))
(`pep-257-nn (and multi-line-p (cons nil 1)))
(`symmetric (and multi-line-p (cons 1 1)))))
(docstring-p (save-excursion
;; Consider docstrings those strings which
;; start on a line by themselves.
(python-nav-beginning-of-statement)
(and (= (point) str-start-pos))))
(fill-paragraph-function))
(save-restriction
(narrow-to-region str-start-pos str-end-pos)
(fill-paragraph justify))
(save-excursion
(when (and docstring-p python-fill-docstring-style)
(when (and (python-info-docstring-p) python-fill-docstring-style)
;; Add the number of newlines indicated by the selected style
;; at the start of the docstring.
(goto-char (+ str-start-pos num-quotes))
@ -4423,23 +4409,40 @@ where the continued line ends."
(when (looking-at (python-rx block-start))
(point-marker)))))
(defun python-info-assignment-statement-p (&optional current-line-only)
"Check if current line is an assignment.
With argument CURRENT-LINE-ONLY is non-nil, don't follow any
continuations, just check the if current line is an assignment."
(save-excursion
(let ((found nil))
(if current-line-only
(back-to-indentation)
(python-nav-beginning-of-statement))
(while (and
(re-search-forward (python-rx not-simple-operator
assignment-operator
(group not-simple-operator))
(line-end-position) t)
(not found))
(save-excursion
;; The assignment operator should not be inside a string.
(backward-char (length (match-string-no-properties 1)))
(setq found (not (python-syntax-context-type)))))
(when found
(skip-syntax-forward " ")
(point-marker)))))
;; TODO: rename to clarify this is only for the first continuation
;; line or remove it and move its body to `python-indent-context'.
(defun python-info-assignment-continuation-line-p ()
"Check if current line is a continuation of an assignment.
"Check if current line is the first continuation of an assignment.
When current line is continuation of another with an assignment
return the point of the first non-blank character after the
operator."
(save-excursion
(when (python-info-continuation-line-p)
(forward-line -1)
(back-to-indentation)
(when (and (not (looking-at (python-rx block-start)))
(and (re-search-forward (python-rx not-simple-operator
assignment-operator
not-simple-operator)
(line-end-position) t)
(not (python-syntax-context-type))))
(skip-syntax-forward "\s")
(point-marker)))))
(python-info-assignment-statement-p t))))
(defun python-info-looking-at-beginning-of-defun (&optional syntax-ppss)
"Check if point is at `beginning-of-defun' using SYNTAX-PPSS."
@ -4464,6 +4467,45 @@ operator."
(* whitespace) line-end))
(string-equal "" (match-string-no-properties 1))))
(defun python-info-docstring-p (&optional syntax-ppss)
"Return non-nil if point is in a docstring.
When optional argument SYNTAX-PPSS is given, use that instead of
point's current `syntax-ppss'."
;;; https://www.python.org/dev/peps/pep-0257/#what-is-a-docstring
(save-excursion
(when (and syntax-ppss (python-syntax-context 'string syntax-ppss))
(goto-char (nth 8 syntax-ppss)))
(python-nav-beginning-of-statement)
(let ((counter 1)
(indentation (current-indentation))
(backward-sexp-point)
(re (concat "[uU]?[rR]?"
(python-rx string-delimiter))))
(when (and
(not (python-info-assignment-statement-p))
(looking-at-p re)
;; Allow up to two consecutive docstrings only.
(>=
2
(progn
(while (save-excursion
(python-nav-backward-sexp)
(setq backward-sexp-point (point))
(and (= indentation (current-indentation))
(looking-at-p
(concat "[uU]?[rR]?"
(python-rx string-delimiter)))))
;; Previous sexp was a string, restore point.
(goto-char backward-sexp-point)
(cl-incf counter))
counter)))
(python-util-forward-comment -1)
(python-nav-beginning-of-statement)
(cond ((bobp))
((python-info-assignment-statement-p) t)
((python-info-looking-at-beginning-of-defun))
(t nil))))))
(defun python-info-encoding-from-cookie ()
"Detect current buffer's encoding from its coding cookie.
Returns the encoding as a symbol."