From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Maxim Cournoyer Newsgroups: gmane.emacs.bugs Subject: bug#56197: [PATCH] lisp: Introduce lisp-fill-paragraph-as-displayed option. Date: Sat, 4 Jan 2025 22:03:43 +0900 Message-ID: <20250104130343.4801-1-maxim.cournoyer@gmail.com> References: <87zgi2xcgm.fsf@gmail.com> Mime-Version: 1.0 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="7666"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Maxim Cournoyer , eliz@gnu.org, larsi@gnus.org, felix.lechner@lease-up.com, stefankangas@gmail.com To: 56197@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sat Jan 04 14:05:30 2025 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 1tU3qL-0001rp-Lm for geb-bug-gnu-emacs@m.gmane-mx.org; Sat, 04 Jan 2025 14:05:29 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tU3q1-0003k8-PE; Sat, 04 Jan 2025 08:05:13 -0500 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 1tU3py-0003ib-OV for bug-gnu-emacs@gnu.org; Sat, 04 Jan 2025 08:05:06 -0500 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 1tU3py-0007NB-7A; Sat, 04 Jan 2025 08:05:06 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:Date:From:To:In-Reply-To:References:Subject; bh=6uOjoPXhOa4hCevD53gRIpDA+qla3Osf5kgF2XePqHI=; b=SphrEP/6l8dx+E4TvMqEcWgaYzt8c4fW+yU8tH8I+bz81n/Av4HyM8Ol4uK1UxnUbE30nEYcbTJhE6Esfe8PUk7bIwrDcDE2P+ELRWLvaA8/8dad1JNsAJOGO4GHdKU19VQLDGZJ86/Sac3aHrtcJUYOOxQaBnBBGwr901nivTppKHWVG907rh3JXeXvLvzJaeN0dKNQvQjSHRsF2/muMwOW2XBbqQfTP6159tnomdTHmMEouLZ/fwhuHmjZCy09Iu99k30dD1T4vT3xv5Px/PXXMol7y8gQ5S943EKgeLUlcuBIOsL9WWSMtyvbL/kU5yxiJYMMvpnTz834FC1HuQ==; Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1tU3pt-0006zA-Qx; Sat, 04 Jan 2025 08:05:01 -0500 X-Loop: help-debbugs@gnu.org In-Reply-To: <87zgi2xcgm.fsf@gmail.com> Resent-From: Maxim Cournoyer Original-Sender: "Debbugs-submit" Resent-CC: eliz@gnu.org, larsi@gnus.org, felix.lechner@lease-up.com, stefankangas@gmail.com, bug-gnu-emacs@gnu.org Resent-Date: Sat, 04 Jan 2025 13:05:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 56197 X-GNU-PR-Package: emacs X-Debbugs-Original-Xcc: eliz@gnu.org, larsi@gnus.org, felix.lechner@lease-up.com, stefankangas@gmail.com Original-Received: via spool by 56197-submit@debbugs.gnu.org id=B56197.173599586126775 (code B ref 56197); Sat, 04 Jan 2025 13:05:01 +0000 Original-Received: (at 56197) by debbugs.gnu.org; 4 Jan 2025 13:04:21 +0000 Original-Received: from localhost ([127.0.0.1]:53844 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tU3pE-0006xm-Ib for submit@debbugs.gnu.org; Sat, 04 Jan 2025 08:04:21 -0500 Original-Received: from mail-pj1-x102a.google.com ([2607:f8b0:4864:20::102a]:47279) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1tU3pA-0006xU-9u for 56197@debbugs.gnu.org; Sat, 04 Jan 2025 08:04:19 -0500 Original-Received: by mail-pj1-x102a.google.com with SMTP id 98e67ed59e1d1-2f43da61ba9so14968818a91.2 for <56197@debbugs.gnu.org>; Sat, 04 Jan 2025 05:04:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1735995849; x=1736600649; darn=debbugs.gnu.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=6uOjoPXhOa4hCevD53gRIpDA+qla3Osf5kgF2XePqHI=; b=WECZso2uWS2MXXLZsYcBpCazw87hAemqtgp8SWzcd389sN3Nupa+DtlQeFi/F3Ojii +lZ2NWyX7wVM0mUgBK+6belunpUSRWtOgnI/6+pUesF/RjRnyL+RjMKk2GtrZXTUS3ym mapILMCGK43UGpbQEPp7eQ3ebyLuLrfYgT5SAah1c+KQY8vlbMEwbpSwVKa/Hh8dHKUD NxZv0TeW5MfJDEL4RWCgNC5dKKw0dQSCd9b233Pv8LSL2xSYJHU+sfInMTHgD9ybQVaM hs1OIBR/ws403ph2O1TQfsd/1CPF+1sol872qkSVX9g5gGzbksDMOzdqYDfa5enmEmX3 2HPQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1735995849; x=1736600649; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=6uOjoPXhOa4hCevD53gRIpDA+qla3Osf5kgF2XePqHI=; b=PsOsh4cklnAvQyD1Eu65AG7Yhx5EMoqy9sIB9uBj3h2TVm+iEKuUcmV1Snh4Lml2Ia n164kcz7Rky49R6QUBE2LNr14TFXk+JJ0OsSmExjQ/8ZiCFby9k/lawYY13GE9cpP085 1BzupgSBUBeky8bVWYu9R9aCKffbqZSq/qPJg/Lgm6/nzyM1R3OdtyJCgD0KMsAAKSO7 IY9zbOAkyxAzxgVlGW7Oc4RPCdQ1eK2sCWF75+cvid/fNT43kBvFV/qC4YHMKwgOvprM PgfyHmFLSRlq6NRp6kTLsiA5GFewExjM0X99nL/1ZgicrwDkW9oTCBPisGHs98/93LQc 2ykw== X-Gm-Message-State: AOJu0YwDYyVLYVpKi/GqKsf/ZWyGTuowcAzfuqxwDxbIXRunjCRlUR11 elQEXHapUpcmW1Xb3VoUqPHPsLP7AnZYDY39FYKXQ6fa7XmAvlK1ttXljBtl2XM= X-Gm-Gg: ASbGncs1zy5P93jNvFFFDLC6VEekFsuEL7RZdhJOLGk36JqNccFfZ7nnWhk3scPHaQl pzJwFXtzSZFCQrcIDZmAGsfD5x8sdt37RD+GJkcsecHvnMKM/77bbQeY2j013k0lYt6WEXNa+J2 0fQSsOmqrVvUewuG6+3u2a+CY5AcR6u6/Op/5RX2AhGbbD2TPKjCyrr5SlPWrwLbetoy5MU7WwR rCwqM+t584K9Aiam0v5jZ4BOrWpACBj9+FunDdf+SCEzSW/A6JrcXIsCzYZGLjb2oMYjWPoAbs= X-Google-Smtp-Source: AGHT+IGm4ZZM/9at7bkcQd/V9RvIUO3AGyFSuIANmWEqyK+ZuuzTjaCvSo0SnP9TZiX0nw8N1K0Jtg== X-Received: by 2002:a17:90b:50c7:b0:2ee:c04a:4281 with SMTP id 98e67ed59e1d1-2f452dfb023mr72335598a91.6.1735995848933; Sat, 04 Jan 2025 05:04:08 -0800 (PST) Original-Received: from localhost.localdomain ([2405:6586:be0:0:c8ff:1707:9b9:af89]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-2f4633df7c0sm26306140a91.18.2025.01.04.05.04.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 04 Jan 2025 05:04:08 -0800 (PST) X-Mailer: git-send-email 2.46.0 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:298392 Archived-At: Starting with Emacs 28, filling strings now happens in a narrowed scope, and looses the leading indentation and can cause the string to extend past the fill-column value. Introduce lisp-fill-paragraph-as-displayed as a new option allowing users to easily opt out of this new behavior. * lisp/emacs-lisp/lisp-mode.el (lisp-fill-paragraph-as-displayed): New variable. (lisp-fill-paragraph): Honor it, by avoiding the logic narrow to strings before applying fill-paragraph. * test/lisp/emacs-lisp/lisp-mode-tests.el (lisp-fill-paragraph-respects-fill-column): Test it. (lisp-fill-paragraph-docstring-boundaries): New test, as a safeguard to avoid regressions. Fixes: bug#56197 --- lisp/emacs-lisp/lisp-mode.el | 74 ++++++++++++++----------- test/lisp/emacs-lisp/lisp-mode-tests.el | 47 ++++++++++++++++ 2 files changed, 90 insertions(+), 31 deletions(-) diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el index d0c32d238bc..cc9f6f51cb5 100644 --- a/lisp/emacs-lisp/lisp-mode.el +++ b/lisp/emacs-lisp/lisp-mode.el @@ -1,6 +1,6 @@ ;;; lisp-mode.el --- Lisp mode, and its idiosyncratic commands -*- lexical-binding:t -*- -;; Copyright (C) 1985-1986, 1999-2024 Free Software Foundation, Inc. +;; Copyright (C) 1985-1986, 1999-2025 Free Software Foundation, Inc. ;; Maintainer: emacs-devel@gnu.org ;; Keywords: lisp, languages @@ -1431,6 +1431,16 @@ emacs-lisp-docstring-fill-column :group 'lisp :version "30.1") +(defcustom lisp-fill-paragraph-as-displayed nil + "Fill paragraphs as displayed in the buffer, preserving surrounding +context such as the leading indentation. This is useful if respecting +`fill-column' is more important than avoiding surrounding code from +being filled, and makes `lisp-fill-paragraph' behave as it used to in +Emacs 27 and prior versions." + :type 'boolean + :group 'lisp + :version "31.0") + (defun lisp-fill-paragraph (&optional justify) "Like \\[fill-paragraph], but handle Emacs Lisp comments and docstrings. If any of the current line is a comment, fill the comment or the @@ -1480,42 +1490,44 @@ lisp-fill-paragraph (derived-mode-p 'emacs-lisp-mode)) emacs-lisp-docstring-fill-column fill-column))) - (let ((ppss (syntax-ppss)) - (start (point)) - ;; Avoid recursion if we're being called directly with - ;; `M-x lisp-fill-paragraph' in an `emacs-lisp-mode' buffer. - (fill-paragraph-function t)) + (let* ((ppss (syntax-ppss)) + (start (point)) + ;; Avoid recursion if we're being called directly with + ;; `M-x lisp-fill-paragraph' in an `emacs-lisp-mode' buffer. + (fill-paragraph-function t) + (string-start (ppss-comment-or-string-start ppss))) (save-excursion (save-restriction ;; If we're not inside a string, then do very basic ;; filling. This avoids corrupting embedded strings in ;; code. - (if (not (ppss-comment-or-string-start ppss)) + (if (not string-start) (lisp--fill-line-simple) - ;; If we're in a string, then narrow (roughly) to that - ;; string before filling. This avoids filling Lisp - ;; statements that follow the string. - (when (ppss-string-terminator ppss) - (goto-char (ppss-comment-or-string-start ppss)) - ;; The string may be unterminated -- in that case, don't - ;; narrow. - (when (ignore-errors - (progn - (forward-sexp 1) - t)) - (narrow-to-region (1+ (ppss-comment-or-string-start ppss)) - (1- (point))))) - ;; Move back to where we were. - (goto-char start) - ;; We should fill the first line of a string - ;; separately (since it's usually a doc string). - (if (= (line-number-at-pos) 1) - (narrow-to-region (line-beginning-position) - (line-beginning-position 2)) - (save-excursion - (goto-char (point-min)) - (forward-line 1) - (narrow-to-region (point) (point-max)))) + (unless lisp-fill-paragraph-as-displayed + ;; If we're in a string, then narrow (roughly) to that + ;; string before filling. This avoids filling Lisp + ;; statements that follow the string. + (when (ppss-string-terminator ppss) + (goto-char string-start) + ;; The string may be unterminated -- in that case, don't + ;; narrow. + (when (ignore-errors + (progn + (forward-sexp 1) + t)) + (narrow-to-region (1+ string-start) + (1- (point))))) + ;; Move back to where we were. + (goto-char start) + ;; We should fill the first line of a string + ;; separately (since it's usually a doc string). + (if (= (line-number-at-pos) 1) + (narrow-to-region (line-beginning-position) + (line-beginning-position 2)) + (save-excursion + (goto-char (point-min)) + (forward-line 1) + (narrow-to-region (point) (point-max))))) (fill-paragraph justify))))))) ;; Never return nil. t) diff --git a/test/lisp/emacs-lisp/lisp-mode-tests.el b/test/lisp/emacs-lisp/lisp-mode-tests.el index da02be65d03..347b3d5b642 100644 --- a/test/lisp/emacs-lisp/lisp-mode-tests.el +++ b/test/lisp/emacs-lisp/lisp-mode-tests.el @@ -308,6 +308,53 @@ lisp-indent-defun (indent-region (point-min) (point-max)) (should (equal (buffer-string) orig))))) + +;;; Filling + +(ert-deftest lisp-fill-paragraph-docstring-boundaries () + "Test bug#28937, ensuring filling the docstring filled is properly +bounded." + (with-temp-buffer + (insert "\ +(defun test () + \"This is a test docstring. +Here is some more text.\" + 1 + 2 + 3 + 4 + 5)") + (let ((correct (buffer-string))) + (emacs-lisp-mode) + (search-backward "This is a test docstring") + (fill-paragraph) ;function under test + (should (equal (buffer-string) correct))))) + +(ert-deftest lisp-fill-paragraph-as-displayed () + "Test bug#56197 -- more specifically, validate that a leading indentation +for a string is preserved in the filled string." + (let ((lisp-fill-paragraph-as-displayed t) ;option under test + (source "\ +'(description \"This is a very long string which is indented by a considerable value, causing it to +protrude from the configured `fill-column' since +lisp-fill-paragraph was refactored in version 28.\")")) + (with-temp-buffer + ;; The following is a contrived example that demonstrates the + ;; fill-column problem when the string to fill is indented. + (insert source) + (emacs-lisp-mode) + (search-backward "This is a very long string") + (fill-paragraph) ;function under test + (goto-char (point-min)) + (message "%s" (buffer-substring-no-properties (point-min) (point-max))) + (let ((i 1) + (lines-count (count-lines (point-min) (point-max)))) + (while (< i lines-count) + (beginning-of-line i) + (end-of-line) + (should (<= (current-column) fill-column)) + (setq i (1+ i))))))) + ;;; Fontification -- 2.46.0