From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Sandra Snan via "Bug reports for GNU Emacs, the Swiss army knife of text editors" Newsgroups: gmane.emacs.bugs Subject: bug#71017: [PATCH] Flow single-paragraph messages Date: Sat, 6 Jul 2024 22:49:50 +0200 Message-ID: <20240706204950.2437581-1-sandra.snan@idiomdrottning.org> References: Reply-To: Sandra Snan Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="22419"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Sandra Snan To: 71017@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sat Jul 06 22:51:21 2024 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1sQCNN-0005iQ-2w for geb-bug-gnu-emacs@m.gmane-mx.org; Sat, 06 Jul 2024 22:51:21 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sQCN4-0001pH-29; Sat, 06 Jul 2024 16:51:02 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sQCN0-0001mr-HQ for bug-gnu-emacs@gnu.org; Sat, 06 Jul 2024 16:50:58 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sQCMz-0003tc-W3 for bug-gnu-emacs@gnu.org; Sat, 06 Jul 2024 16:50:58 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1sQCN3-0003xP-OD for bug-gnu-emacs@gnu.org; Sat, 06 Jul 2024 16:51:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Sandra Snan Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 06 Jul 2024 20:51:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 71017 X-GNU-PR-Package: emacs Original-Received: via spool by 71017-submit@debbugs.gnu.org id=B71017.172029903815179 (code B ref 71017); Sat, 06 Jul 2024 20:51:01 +0000 Original-Received: (at 71017) by debbugs.gnu.org; 6 Jul 2024 20:50:38 +0000 Original-Received: from localhost ([127.0.0.1]:46817 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sQCMf-0003wk-Ji for submit@debbugs.gnu.org; Sat, 06 Jul 2024 16:50:38 -0400 Original-Received: from halsen.idiomdrottning.org ([74.207.231.133]:52762) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sQCMd-0003wc-87 for 71017@debbugs.gnu.org; Sat, 06 Jul 2024 16:50:36 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=idiomdrottning.org; s=idiomdrottningorg; t=1720299000; bh=lmuQGTjWN4927bO4vKX5iEfXrWxxAbGq4HODUc/uCjQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ne1SrF7uOmnq4i4ulU9Siilr+Y76/0vHmsdBqUdZzr59QqZdFI7ySEzJaJ+89fO2j ksDAjZWSzJ5AFFy7xyp/l0fKZz41ZJaXUkQl5eBj7QZ/emlMhzLObScdzPav3tIHur 8c3Og/y+7s2Mz7ImmUkJywkEa06NSTvhqqKQCpEMWdSm+4zxcHdpm5cpYeTupe/APb KSHoeouyC8JY4cWeqzPqdlYqc2J4OCQBq1yL0OSQR4JbJJ/LIqe6DTWLVpVeTuavtn +IeaHyBOmqIGrO7vUO3j9FoPiMOtKm5oGciamve2Tjs8eHWRiFwF1SwgZLeaCnVPB3 VSppWo58iCdJA== Original-Received: from localhost (31-211-247-254.customers.ownit.se [31.211.247.254]) by halsen.idiomdrottning.org (Postfix) with ESMTPSA id B3E231ECA6; Sat, 6 Jul 2024 22:49:58 +0200 (CEST) X-Mailer: git-send-email 2.39.2 In-Reply-To: X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:288520 Archived-At: This fixes two bugs when sending RFC 2646–formatted email. First, the old code didn't refill or encode the last paragraph at all unless there was at least one hard newline EOF. This was a bee to track down because there were two separate issues at play. One was a a bug in flow-fill.el where every paragraph except the last paragraph was reflowed, but the last paragraph would stay hardwrapped. Manually placing a hard newline at the end of the file was a workaround but I don't always remember to do that. I managed to fix that bug a few months ago. Second, the old code borked up code indented with tabs and spaces (iff that code had overly long lines), such as Lisp code. It could sometimes insert extra whitespace in the middle of such long lines. I fixed that bug shortly after the first one. But for months dogfooding those two changes, sometimes a hardwrapped email would still be sent. I finally managed to debug and figure it out and it took all day. Turns out mml just plain didn't call the fill-flowed-encode function if the message doesn't have any hard newlines (newlines with the hard text property). Well, of course a single-paragraph email isn't gonna have any hard newlines! But it still needs reflowing! So I've now changed that and updated the documentation to match those news semantics. I went all the way, but a possible compromise might be to not-flow a message that has \n\n but no hard text props, since that's a sign that something is wrong. Since the use-hard-newlines variable is buffer local and all this reflowing is being done in a temp buffer, that variable is more than useless so I've removed references to it. --- doc/misc/emacs-mime.texi | 7 ++--- lisp/gnus/mml.el | 29 ++++++++---------- lisp/mail/flow-fill.el | 65 +++++++++++++++++----------------------- 3 files changed, 41 insertions(+), 60 deletions(-) diff --git a/doc/misc/emacs-mime.texi b/doc/misc/emacs-mime.texi index ef7ea61..7621a9a 100644 --- a/doc/misc/emacs-mime.texi +++ b/doc/misc/emacs-mime.texi @@ -1087,13 +1087,10 @@ terminated by soft newline characters are filled together and wrapped after the column decided by @code{fill-flowed-encode-column}. Quotation marks (matching @samp{^>* ?}) are respected. The variable controls how the text will look in a client that does not support -flowed text, the default is to wrap after 66 characters. If hard -newline characters are not present in the buffer, no flow encoding -occurs. +flowed text, the default is to wrap after 66 characters. You can customize the value of the @code{mml-enable-flowed} variable -to enable or disable the flowed encoding usage when newline -characters are present in the buffer. +to enable or disable the flowed encoding usage. On decoding flowed text, lines with soft newline characters are filled together and wrapped after the column decided by diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el index e3bc393..2db39dc 100644 --- a/lisp/gnus/mml.el +++ b/lisp/gnus/mml.el @@ -691,23 +691,18 @@ type detected." (t ;; Only perform format=flowed filling on text/plain ;; parts where there either isn't a format parameter - ;; in the mml tag or it says "flowed" and there - ;; actually are hard newlines in the text. - (let (use-hard-newlines) - (when (and mml-enable-flowed - (string= type "text/plain") - (not (string= (cdr (assq 'sign cont)) "pgp")) - (or (null (assq 'format cont)) - (string= (cdr (assq 'format cont)) - "flowed")) - (setq use-hard-newlines - (text-property-any - (point-min) (point-max) 'hard 't))) - (fill-flowed-encode) - ;; Indicate that `mml-insert-mime-headers' should - ;; insert a "; format=flowed" string unless the - ;; user has already specified it. - (setq flowed (null (assq 'format cont))))) + ;; in the mml tag or it says "flowed". + (when (and mml-enable-flowed + (string= type "text/plain") + (not (string= (cdr (assq 'sign cont)) "pgp")) + (or (null (assq 'format cont)) + (string= (cdr (assq 'format cont)) + "flowed"))) + (fill-flowed-encode) + ;; Indicate that `mml-insert-mime-headers' should + ;; insert a "; format=flowed" string unless the + ;; user has already specified it. + (setq flowed (null (assq 'format cont)))) ;; Prefer `utf-8' for text/calendar parts. (if (or charset (not (string= type "text/calendar"))) diff --git a/lisp/mail/flow-fill.el b/lisp/mail/flow-fill.el index 919490e..5c9ae21 100644 --- a/lisp/mail/flow-fill.el +++ b/lisp/mail/flow-fill.el @@ -73,50 +73,39 @@ RFC 2646 suggests 66 characters for readability." ;;;###autoload (defun fill-flowed-encode (&optional buffer) (with-current-buffer (or buffer (current-buffer)) - ;; No point in doing this unless hard newlines is used. - (when use-hard-newlines - (let ((start (point-min)) end) - ;; Go through each paragraph, filling it and adding SPC - ;; as the last character on each line. - (while (setq end (text-property-any start (point-max) 'hard 't)) - (save-restriction - (narrow-to-region start end) - (let ((fill-column (eval fill-flowed-encode-column t))) - (fill-flowed-fill-buffer)) - (goto-char (point-min)) - (while (re-search-forward "\n" nil t) - (replace-match " \n" t t)) - (goto-char (setq start (1+ (point-max))))))) - t))) - -(defun fill-flowed-fill-buffer () - (let ((prefix nil) - (prev-prefix nil) - (start (point-min))) - (goto-char (point-min)) - (while (not (eobp)) - (setq prefix (and (looking-at "[> ]+") - (match-string 0))) - (if (equal prefix prev-prefix) - (forward-line 1) + (let ((fill-column (eval fill-flowed-encode-column t)) + (start (point-min)) + end) + ;; Go through each paragraph, filling it and adding SPC + ;; as the last character on each line. + (while (and (< start (point-max)) + (setq end (or (text-property-any start (point-max) 'hard 't) + (point-max)))) (save-restriction - (narrow-to-region start (point)) - (let ((fill-prefix prev-prefix)) - (fill-region (point-min) (point-max) t 'nosqueeze 'to-eop)) - (goto-char (point-max))) - (setq prev-prefix prefix - start (point)))) - (save-restriction - (narrow-to-region start (point)) - (let ((fill-prefix prev-prefix)) - (fill-region (point-min) (point-max) t 'nosqueeze 'to-eop))))) + (narrow-to-region start end) + (let ((prefix + (concat "\n" + (or (and (looking-at ">[> ]*") + (match-string 0)) "")))) + (goto-char start) + (while (search-forward prefix nil t) + (replace-match " " t t)) + (goto-char start) + (while (< (+ (point) fill-column) (point-max)) + (let ((start (point))) + (forward-char fill-column) + (when (search-backward " " start t) + (forward-char) + (insert prefix))))) + (setq start (1+ (point-max)))))) + t)) ;;;###autoload (defun fill-flowed (&optional buffer delete-space) "Apply RFC2646 decoding to BUFFER. If BUFFER is nil, default to the current buffer. -If DELETE-SPACE, delete RFC2646 spaces padding at the end of +If DELETE-SPACE, delete RFC3676 spaces padding at the end of lines." (with-current-buffer (or buffer (current-buffer)) (let ((fill-column (eval fill-flowed-display-column t))) @@ -154,7 +143,7 @@ lines." ;; Delete the newline. (when (eq (following-char) ?\s) (delete-char 1)) - ;; Hack: Don't do the flowing on the signature line. + ;; As per RFC3767: Don't do the flowing on the signature line. (when (and (not (looking-at "-- $")) (eq (char-before (line-end-position)) ?\s)) (while (and (not (eobp)) -- 2.39.2