From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Fabian Ezequiel Gallina Newsgroups: gmane.emacs.devel Subject: Python fill-paragraph Date: Thu, 4 Oct 2012 12:32:07 -0300 Message-ID: NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 X-Trace: ger.gmane.org 1349401896 24616 80.91.229.3 (5 Oct 2012 01:51:36 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 5 Oct 2012 01:51:36 +0000 (UTC) To: Emacs-Devel devel Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri Oct 05 03:51:42 2012 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1TJx4R-0006Y7-K1 for ged-emacs-devel@m.gmane.org; Fri, 05 Oct 2012 03:51:19 +0200 Original-Received: from localhost ([::1]:51973 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TJnp8-0000iU-UY for ged-emacs-devel@m.gmane.org; Thu, 04 Oct 2012 11:58:54 -0400 Original-Received: from eggs.gnu.org ([208.118.235.92]:59142) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TJnhU-0001HB-Uu for emacs-devel@gnu.org; Thu, 04 Oct 2012 11:51:45 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1TJnPE-0003qT-R0 for emacs-devel@gnu.org; Thu, 04 Oct 2012 11:32:17 -0400 Original-Received: from mail-ie0-f169.google.com ([209.85.223.169]:35052) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1TJnPE-0003qK-KO for emacs-devel@gnu.org; Thu, 04 Oct 2012 11:32:08 -0400 Original-Received: by mail-ie0-f169.google.com with SMTP id 10so1526623ied.0 for ; Thu, 04 Oct 2012 08:32:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=AYqpCJayJk8IDevqrkjLcYe2HqA/IZQNVPQR5NT1xBo=; b=rEJMs0E7PjQNevtzkjDPt5jl+r8JxlIxmjDDL9SKqMN1ncTp5kNz5xEI0uAbzmuB4L j/ROF8jMuDozB92D4EmiArn3KkiULfnsYP2KqV1XEKn79Q6lJdH15kAPIWcNvpR6h+6v I9h/ZrsXeOZXFjfNg6D4nTHmaYPWMdwoVf+w4cKj0j6QpAUZqZNzuCrf+I3O2+ZVB7VG BHKU5QO5i8bWDe+Gge5DSFr4CrBAKhkuDZZOcxg8q+12jk29nDNNEJkvqBq80MJwME/0 OA264+lSHnFJS1/ZdY+xk1fJBTuLpEaDKT8fqweKbIA+gu7tMs44DE6Q/u94ismea2LV mPyQ== Original-Received: by 10.50.207.33 with SMTP id lt1mr5732358igc.40.1349364727300; Thu, 04 Oct 2012 08:32:07 -0700 (PDT) Original-Received: by 10.64.165.72 with HTTP; Thu, 4 Oct 2012 08:32:07 -0700 (PDT) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 209.85.223.169 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:154044 Archived-At: Now that we are on feature freeze I happen to step into a bug[0] into the fill paragraph machinery we have on python.el. As I see it, the good way to solve it is to give the user the possibility to indicate how he wants his docstrings formatted. For this I created a patch (ChangeLog not included yet) that adds this feature while it fixes this bug. Is it possible for me to install it into the trunk? [0] https://github.com/fgallina/python.el/issues/107 === modified file 'lisp/progmodes/python.el' --- lisp/progmodes/python.el 2012-10-03 21:53:09 +0000 +++ lisp/progmodes/python.el 2012-10-04 15:24:50 +0000 @@ -2267,32 +2267,82 @@ This is the function used by `python-fill-paragraph-function' to fill comments." :type 'symbol - :group 'python - :safe 'symbolp) + :group 'python) (defcustom python-fill-string-function 'python-fill-string "Function to fill strings. This is the function used by `python-fill-paragraph-function' to fill strings." :type 'symbol - :group 'python - :safe 'symbolp) + :group 'python) (defcustom python-fill-decorator-function 'python-fill-decorator "Function to fill decorators. This is the function used by `python-fill-paragraph-function' to fill decorators." :type 'symbol - :group 'python - :safe 'symbolp) + :group 'python) (defcustom python-fill-paren-function 'python-fill-paren "Function to fill parens. This is the function used by `python-fill-paragraph-function' to fill parens." :type 'symbol + :group 'python) + +(defcustom python-fill-string-style 'pep-257 + "Style used to fill docstrings. +This affects `python-fill-string' behavior with regards to +triple quotes positioning. + +Possible values are DJANGO, PEP-257, PEP-257-NN, SYMMETRIC and +NIL. A value of NIL won't care about quotes position, will do +what `fill-paragraph' does, any other value may result in one of +the following docstring styles: + +DJANGO: + + \"\"\" + Process foo, return bar. + \"\"\" + + \"\"\" + Process foo, return bar. + + If processing fails throw ProcessingError. + \"\"\" + +PEP-257: + + \"\"\"Process foo, return bar.\"\"\" + + \"\"\"Process foo, return bar. + + If processing fails throw ProcessingError. + + \"\"\" + +PEP-257-NN: + + \"\"\"Process foo, return bar.\"\"\" + + \"\"\"Process foo, return bar. + + If processing fails throw ProcessingError. + \"\"\" + +SYMMETRIC: + + \"\"\"Process foo, return bar.\"\"\" + + \"\"\" + Process foo, return bar. + + If processing fails throw ProcessingError. + \"\"\"" + :type 'symbol :group 'python - :safe 'symbolp) + :safe (lambda (val) (memq val '(django pep-257 pep-257-nn symmetric nil)))) (defun python-fill-paragraph-function (&optional justify) "`fill-paragraph-function' handling multi-line strings and possibly comments. @@ -2302,18 +2352,19 @@ Optional argument JUSTIFY defines if the paragraph should be justified." (interactive "P") (save-excursion - (back-to-indentation) (cond ;; Comments - ((funcall python-fill-comment-function justify)) + ((python-syntax-context 'comment) + (funcall python-fill-comment-function justify)) ;; Strings/Docstrings - ((save-excursion (skip-chars-forward "\"'uUrR") - (python-syntax-context 'string)) + ((save-excursion (or (python-syntax-context 'string) + (equal (string-to-syntax "|") + (syntax-after (point))))) (funcall python-fill-string-function justify)) ;; Decorators ((equal (char-after (save-excursion (back-to-indentation) - (point-marker))) ?@) + (point))) ?@) (funcall python-fill-decorator-function justify)) ;; Parens ((or (python-syntax-context 'paren) @@ -2332,43 +2383,72 @@ (defun python-fill-string (&optional justify) "String fill function for `python-fill-paragraph-function'. JUSTIFY should be used (if applicable) as in `fill-paragraph'." - (let ((marker (point-marker)) - (string-start-marker - (progn - (skip-chars-forward "\"'uUrR") - (goto-char (python-syntax-context 'string)) - (skip-chars-forward "\"'uUrR") - (point-marker))) - (reg-start (line-beginning-position)) - (string-end-marker - (progn - (while (python-syntax-context 'string) - (goto-char (1+ (point-marker)))) - (skip-chars-backward "\"'") - (point-marker))) - (reg-end (line-end-position)) - (fill-paragraph-function)) + (let* ((marker (point-marker)) + (str-start-pos + (let ((m (make-marker))) + (setf (marker-position m) + (or (python-syntax-context 'string) + (and (equal (string-to-syntax "|") + (syntax-after (point))) + (point)))) m)) + (num-quotes (python-syntax-count-quotes + (char-after str-start-pos) str-start-pos)) + (str-end-pos + (save-excursion + (goto-char (+ str-start-pos num-quotes)) + (or (re-search-forward (rx (syntax string-delimiter)) nil t) + (goto-char (point-max))) + (point-marker))) + (multi-line-p + ;; Docstring styles may vary for oneliners and multi-liners. + (> (count-matches "\n" str-start-pos str-end-pos) 0)) + (delimiters-style + (case python-fill-string-style + ;; delimiters-style is a cons cell with the form + ;; (START-NEWLINES . END-NEWLINES). When any of the sexps + ;; is NIL means to not add any newlines for start or end + ;; of docstring. See `python-fill-string-style' for a + ;; graphic idea of each style. + (pep-257 (and multi-line-p (cons nil 2))) + (pep-257-nn (and multi-line-p (cons nil 1))) + (django (cons 1 1)) + (symmetric (and multi-line-p (cons 1 1))))) + (docstring-p (save-excursion + ;; Consider docstrings those strings which + ;; start on a line by themselves. + (goto-char str-start-pos) + (skip-chars-backward (rx whitespace)) + (= (point) (line-beginning-position)))) + (fill-paragraph-function)) (save-restriction - (narrow-to-region reg-start reg-end) - (save-excursion - (goto-char string-start-marker) - (delete-region (point-marker) (progn - (skip-syntax-forward "> ") - (point-marker))) - (goto-char string-end-marker) - (delete-region (point-marker) (progn - (skip-syntax-backward "> ") - (point-marker))) - (save-excursion - (goto-char marker) - (fill-paragraph justify)) - ;; If there is a newline in the docstring lets put triple - ;; quote in it's own line to follow pep 8 - (when (save-excursion - (re-search-backward "\n" string-start-marker t)) - (newline) - (newline-and-indent)) - (fill-paragraph justify)))) t) + (narrow-to-region str-start-pos str-end-pos) + (fill-paragraph justify)) + (save-excursion + (when (and docstring-p python-fill-string-style) + ;; Add the number of newlines indicated by the selected style + ;; at the start of the docstring. + (goto-char (+ str-start-pos num-quotes)) + (delete-region (point) (progn + (skip-syntax-forward "> ") + (point))) + (and (car delimiters-style) + (or (newline (car delimiters-style)) t) + ;; Indent only if a newline is added. + (indent-according-to-mode)) + ;; Add the number of newlines indicated by the selected style + ;; at the end of the docstring. + (goto-char (if (not (= str-end-pos (point-max))) + (- str-end-pos num-quotes) + str-end-pos)) + (delete-region (point) (progn + (skip-syntax-backward "> ") + (point))) + (and (cdr delimiters-style) + ;; Add newlines only if string ends. + (not (= str-end-pos (point-max))) + (or (newline (cdr delimiters-style)) t) + ;; Again indent only if a newline is added. + (indent-according-to-mode))))) t) (defun python-fill-decorator (&optional justify) "Decorator fill function for `python-fill-paragraph-function'.